diff --git a/resource/config.json b/resource/config.json index cfba5b3373..f81df16fa7 100644 --- a/resource/config.json +++ b/resource/config.json @@ -58,7 +58,7 @@ "stop": "[Adb] -s [AdbSerial] shell \"am force-stop `dumpsys activity activities 2>/dev/null | grep Activities= 2>/dev/null | grep -m 1 -i -o -E [^\\ ]*arknights[^/]*`\"", "pushMinitouch": "[Adb] -s [AdbSerial] push \"[minitouchLocalPath]\" \"/data/local/tmp/[minitouchWorkingFile]\"", "chmodMinitouch": "[Adb] -s [AdbSerial] shell chmod 700 \"/data/local/tmp/[minitouchWorkingFile]\"", - "callMinitouch": "[Adb] -s [AdbSerial] shell 'echo \"[minitouchInput]\" | \"/data/local/tmp/[minitouchWorkingFile]\" -i'" + "callMinitouch": "[Adb] -s [AdbSerial] shell \"/data/local/tmp/[minitouchWorkingFile]\" -i > /dev/null 2&>1" }, "BlueStacks": { "devices": "[Adb] devices", @@ -79,7 +79,7 @@ "stop": "[Adb] -s [AdbSerial] shell \"am force-stop `dumpsys activity activities 2>/dev/null | grep Activities= 2>/dev/null | grep -m 1 -i -o -E [^\\ ]*arknights[^/]*`\"", "pushMinitouch": "[Adb] -s [AdbSerial] push \"[minitouchLocalPath]\" \"/data/local/tmp/[minitouchWorkingFile]\"", "chmodMinitouch": "[Adb] -s [AdbSerial] shell chmod 700 \"/data/local/tmp/[minitouchWorkingFile]\"", - "callMinitouch": "[Adb] -s [AdbSerial] shell 'echo \"[minitouchInput]\" | \"/data/local/tmp/[minitouchWorkingFile]\" -i'" + "callMinitouch": "[Adb] -s [AdbSerial] shell \"/data/local/tmp/[minitouchWorkingFile]\" -i > /dev/null 2&>1" }, "MuMuEmulator": { "devices": "[Adb] devices", @@ -100,7 +100,7 @@ "stop": "[Adb] -s [AdbSerial] shell \"am force-stop `dumpsys activity activities 2>/dev/null | grep Activities= 2>/dev/null | grep -m 1 -i -o -E [^\\ ]*arknights[^/]*`\"", "pushMinitouch": "[Adb] -s [AdbSerial] push \"[minitouchLocalPath]\" \"/data/local/tmp/[minitouchWorkingFile]\"", "chmodMinitouch": "[Adb] -s [AdbSerial] shell chmod 700 \"/data/local/tmp/[minitouchWorkingFile]\"", - "callMinitouch": "[Adb] -s [AdbSerial] shell 'echo \"[minitouchInput]\" | \"/data/local/tmp/[minitouchWorkingFile]\" -i'" + "callMinitouch": "[Adb] -s [AdbSerial] shell \"/data/local/tmp/[minitouchWorkingFile]\" -i > /dev/null 2&>1" }, "LDPlayer": { "devices": "[Adb] devices", @@ -121,7 +121,7 @@ "stop": "[Adb] -s [AdbSerial] shell \"am force-stop `dumpsys activity activities 2>/dev/null | grep Activities= 2>/dev/null | grep -m 1 -i -o -E [^\\ ]*arknights[^/]*`\"", "pushMinitouch": "[Adb] -s [AdbSerial] push \"[minitouchLocalPath]\" \"/data/local/tmp/[minitouchWorkingFile]\"", "chmodMinitouch": "[Adb] -s [AdbSerial] shell chmod 700 \"/data/local/tmp/[minitouchWorkingFile]\"", - "callMinitouch": "[Adb] -s [AdbSerial] shell 'echo \"[minitouchInput]\" | \"/data/local/tmp/[minitouchWorkingFile]\" -i'" + "callMinitouch": "[Adb] -s [AdbSerial] shell \"/data/local/tmp/[minitouchWorkingFile]\" -i > /dev/null 2&>1" }, "Nox": { "devices": "[Adb] devices", @@ -142,7 +142,7 @@ "stop": "[Adb] -s [AdbSerial] shell \"am force-stop `dumpsys activity activities 2>/dev/null | grep Activities= 2>/dev/null | grep -m 1 -i -o -E [^\\ ]*arknights[^/]*`\"", "pushMinitouch": "[Adb] -s [AdbSerial] push \"[minitouchLocalPath]\" \"/data/local/tmp/[minitouchWorkingFile]\"", "chmodMinitouch": "[Adb] -s [AdbSerial] shell chmod 700 \"/data/local/tmp/[minitouchWorkingFile]\"", - "callMinitouch": "[Adb] -s [AdbSerial] shell 'echo \"[minitouchInput]\" | \"/data/local/tmp/[minitouchWorkingFile]\" -i'" + "callMinitouch": "[Adb] -s [AdbSerial] shell \"/data/local/tmp/[minitouchWorkingFile]\" -i > /dev/null 2&>1" }, "XYAZ": { "devices": "[Adb] devices", @@ -163,7 +163,7 @@ "stop": "[Adb] -s [AdbSerial] shell \"am force-stop `dumpsys activity activities 2>/dev/null | grep Activities= 2>/dev/null | grep -m 1 -i -o -E [^\\ ]*arknights[^/]*`\"", "pushMinitouch": "[Adb] -s [AdbSerial] push \"[minitouchLocalPath]\" \"/data/local/tmp/[minitouchWorkingFile]\"", "chmodMinitouch": "[Adb] -s [AdbSerial] shell chmod 700 \"/data/local/tmp/[minitouchWorkingFile]\"", - "callMinitouch": "[Adb] -s [AdbSerial] shell 'echo \"[minitouchInput]\" | \"/data/local/tmp/[minitouchWorkingFile]\" -i'" + "callMinitouch": "[Adb] -s [AdbSerial] shell \"/data/local/tmp/[minitouchWorkingFile]\" -i > /dev/null 2&>1" }, "WSA": { "devices": "[Adb] devices", @@ -185,7 +185,7 @@ "stop": "[Adb] -s [AdbSerial] shell \"am force-stop `dumpsys activity activities 2>/dev/null | grep Activities= 2>/dev/null | grep -m 1 -i -o -E [^\\ ]*arknights[^/]*`\"", "pushMinitouch": "[Adb] -s [AdbSerial] push \"[minitouchLocalPath]\" \"/data/local/tmp/[minitouchWorkingFile]\"", "chmodMinitouch": "[Adb] -s [AdbSerial] shell chmod 700 \"/data/local/tmp/[minitouchWorkingFile]\"", - "callMinitouch": "[Adb] -s [AdbSerial] shell 'echo \"[minitouchInput]\" | \"/data/local/tmp/[minitouchWorkingFile]\" -i'" + "callMinitouch": "[Adb] -s [AdbSerial] shell \"/data/local/tmp/[minitouchWorkingFile]\" -i > /dev/null 2&>1" }, "Compatible": { "devices": "[Adb] devices", @@ -206,7 +206,7 @@ "stop": "[Adb] -s [AdbSerial] shell \"am force-stop `dumpsys activity activities 2>/dev/null | grep Activities= 2>/dev/null | grep -m 1 -i -o -E [^\\ ]*arknights[^/]*`\"", "pushMinitouch": "[Adb] -s [AdbSerial] push \"[minitouchLocalPath]\" \"/data/local/tmp/[minitouchWorkingFile]\"", "chmodMinitouch": "[Adb] -s [AdbSerial] shell chmod 700 \"/data/local/tmp/[minitouchWorkingFile]\"", - "callMinitouch": "[Adb] -s [AdbSerial] shell 'echo \"[minitouchInput]\" | \"/data/local/tmp/[minitouchWorkingFile]\" -i'" + "callMinitouch": "[Adb] -s [AdbSerial] shell \"/data/local/tmp/[minitouchWorkingFile]\" -i > /dev/null 2&>1" } } } diff --git a/src/MeoAssistant/Controller.cpp b/src/MeoAssistant/Controller.cpp index daeeaa7bd7..9c43965bec 100644 --- a/src/MeoAssistant/Controller.cpp +++ b/src/MeoAssistant/Controller.cpp @@ -63,7 +63,8 @@ asst::Controller::~Controller() { LogTraceFunction; - set_inited(false); + release_minitouch(); + make_instance_inited(false); kill_adb_daemon(); #ifndef _WIN32 @@ -123,7 +124,7 @@ std::optional asst::Controller::call_command(const std::string& cmd auto cmdline_osstr = asst::utils::to_osstring(cmd); BOOL create_ret = - CreateProcessW(nullptr, &cmdline_osstr[0], nullptr, nullptr, TRUE, 0, nullptr, nullptr, &si, &process_info); + CreateProcessW(nullptr, cmdline_osstr.data(), nullptr, nullptr, TRUE, 0, nullptr, nullptr, &si, &process_info); if (!create_ret) { Log.error("Call `", cmd, "` create process failed, ret", create_ret); return std::nullopt; @@ -367,7 +368,7 @@ std::optional asst::Controller::call_command(const std::string& cmd if (recv_by_socket && !sock_data.empty() && sock_data.size() < 4096) { Log.trace("socket output:", Logger::separator::newline, sock_data); } - // 直接 return,避免走到下面的 else if 里的 set_inited(false) 关闭 adb 连接, + // 直接 return,避免走到下面的 else if 里的 make_instance_inited(false) 关闭 adb 连接, // 导致停止后再开始任务还需要重连一次 if (need_exit()) { return std::nullopt; @@ -429,7 +430,7 @@ std::optional asst::Controller::call_command(const std::string& cmd { "cmd", m_adb.connect }, } }, }; - set_inited(false); // 重连失败,释放 + make_instance_inited(false); // 重连失败,释放 callback(AsstMsg::ConnectionInfo, info); } @@ -443,6 +444,84 @@ void asst::Controller::callback(AsstMsg msg, const json::value& details) } } +bool asst::Controller::call_and_hup_minitouch(const std::string& cmd) +{ + LogTraceFunction; + + m_minitouch_avaiable = false; + +#ifdef _WIN32 + + SECURITY_ATTRIBUTES sa_attr { + .nLength = sizeof(SECURITY_ATTRIBUTES), + .lpSecurityDescriptor = nullptr, + .bInheritHandle = TRUE, + }; + HANDLE minitouch_in_read = nullptr; + + if (!asst::win32::CreateOverlappablePipe(&minitouch_in_read, &m_minitouch_in_write, &sa_attr, nullptr, 4096UL, + false, true)) { + DWORD err = GetLastError(); + Log.error("Failed to create pipe for minitouch, err", err); + return false; + } + + STARTUPINFOW si {}; + si.cb = sizeof(STARTUPINFOW); + si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; + si.wShowWindow = SW_HIDE; + si.hStdInput = m_minitouch_in_write; + + auto cmd_osstr = utils::to_osstring(cmd); + if (!CreateProcessW(NULL, cmd_osstr.data(), nullptr, nullptr, TRUE, 0, nullptr, nullptr, &si, + &m_minitouch_process_info)) { + DWORD err = GetLastError(); + Log.error("Failed to create process for minitouch, err", err); + CloseHandle(minitouch_in_read); + CloseHandle(m_minitouch_in_write); + return false; + } + + CloseHandle(minitouch_in_read); + + m_minitouch_avaiable = true; + return true; + +#else // !_WIN32 + // TODO + return false; +#endif // _WIN32 +} + +bool asst::Controller::input_to_minitouch(const std::string& cmd) +{ + LogTraceFunction; + + DWORD written = 0; + BOOL wr_ret = WriteFile(m_minitouch_in_write, cmd.c_str(), static_cast(cmd.size()), &written, NULL); + + Log.info(std::format("input to minitouch: \"{}\", write_ret: {}, written_size: {}", cmd, wr_ret, written)); + return wr_ret && cmd.size() == written; +} + +void asst::Controller::release_minitouch() +{ + LogTraceFunction; + + if (!m_minitouch_avaiable) { + return; + } + m_minitouch_avaiable = false; + +#ifdef _WIN32 + + CloseHandle(m_minitouch_process_info.hProcess); + CloseHandle(m_minitouch_process_info.hThread); + CloseHandle(m_minitouch_in_write); + +#endif // _WIN32 +} + // 返回值代表是否找到 "\r\n",函数本身会将所有 "\r\n" 替换为 "\n" bool asst::Controller::convert_lf(std::string& data) { @@ -518,12 +597,13 @@ void asst::Controller::random_delay() const void asst::Controller::clear_info() noexcept { - set_inited(false); + make_instance_inited(false); m_adb = decltype(m_adb)(); m_uuid.clear(); m_width = 0; m_height = 0; m_control_scale = 1.0; + m_minitouch_avaiable = false; m_scale_size = { WindowWidthDefault, WindowHeightDefault }; } @@ -659,7 +739,7 @@ bool asst::Controller::screencap(bool allow_reconnect) auto duration = duration_cast(high_resolution_clock::now() - start_time); if (duration < min_cost) { m_adb.screencap_method = AdbProperty::ScreencapMethod::RawByNc; - set_inited(true); + make_instance_inited(true); min_cost = duration; } Log.info("RawByNc cost", duration.count(), "ms"); @@ -674,7 +754,7 @@ bool asst::Controller::screencap(bool allow_reconnect) auto duration = duration_cast(high_resolution_clock::now() - start_time); if (duration < min_cost) { m_adb.screencap_method = AdbProperty::ScreencapMethod::RawWithGzip; - set_inited(true); + make_instance_inited(true); min_cost = duration; } Log.info("RawWithGzip cost", duration.count(), "ms"); @@ -689,7 +769,7 @@ bool asst::Controller::screencap(bool allow_reconnect) auto duration = duration_cast(high_resolution_clock::now() - start_time); if (duration < min_cost) { m_adb.screencap_method = AdbProperty::ScreencapMethod::Encode; - set_inited(true); + make_instance_inited(true); min_cost = duration; } Log.info("Encode cost", duration.count(), "ms"); @@ -832,15 +912,13 @@ bool asst::Controller::click_without_scale(const Point& p) Log.error("click point out of range"); } - std::string cur_cmd; - if (m_enable_minitouch) { + if (m_minitouch_avaiable) { std::string minitouch_cmd = MinitouchCmd::down(p.x, p.y) + MinitouchCmd::up(); - cur_cmd = utils::string_replace_all(m_adb.call_minitouch, { { "[minitouchInput]", minitouch_cmd } }); - } - else { - cur_cmd = - utils::string_replace_all(m_adb.click, { { "[x]", std::to_string(p.x) }, { "[y]", std::to_string(p.y) } }); + return input_to_minitouch(minitouch_cmd); } + + std::string cur_cmd = + utils::string_replace_all(m_adb.click, { { "[x]", std::to_string(p.x) }, { "[y]", std::to_string(p.y) } }); return call_command(cur_cmd).has_value(); } @@ -877,8 +955,7 @@ bool asst::Controller::swipe_without_scale(const Point& p1, const Point& p2, int y1 = std::clamp(y1, 0, m_height - 1); } - std::string cur_cmd; - if (m_enable_minitouch) { + if (m_minitouch_avaiable) { std::string minitouch_cmd = MinitouchCmd::down(x1, x2); if (duration == 0) { duration = 1000; @@ -894,24 +971,22 @@ bool asst::Controller::swipe_without_scale(const Point& p1, const Point& p2, int minitouch_cmd += MinitouchCmd::move(x2, y2); minitouch_cmd += MinitouchCmd::up(); - cur_cmd = utils::string_replace_all(m_adb.call_minitouch, { { "[minitouchInput]", minitouch_cmd } }); - } - else { - cur_cmd = - utils::string_replace_all(m_adb.swipe, { - { "[x1]", std::to_string(x1) }, - { "[y1]", std::to_string(y1) }, - { "[x2]", std::to_string(x2) }, - { "[y2]", std::to_string(y2) }, - { "[duration]", duration <= 0 ? "" : std::to_string(duration) }, - }); + return input_to_minitouch(minitouch_cmd); } + std::string cur_cmd = + utils::string_replace_all(m_adb.swipe, { + { "[x1]", std::to_string(x1) }, + { "[y1]", std::to_string(y1) }, + { "[x2]", std::to_string(x2) }, + { "[y2]", std::to_string(y2) }, + { "[duration]", duration <= 0 ? "" : std::to_string(duration) }, + }); bool ret = call_command(cur_cmd).has_value(); // 额外的滑动:adb有bug,同样的参数,偶尔会划得非常远。额外做一个短程滑动,把之前的停下来 const auto& opt = Configer.get_options(); - if (!m_enable_minitouch && extra_swipe && opt.adb_extra_swipe_duration > 0) { + if (!m_minitouch_avaiable && extra_swipe && opt.adb_extra_swipe_duration > 0) { std::string extra_cmd = utils::string_replace_all( m_adb.swipe, { { "[x1]", std::to_string(x2) }, @@ -934,11 +1009,12 @@ bool asst::Controller::connect(const std::string& adb_path, const std::string& a { LogTraceFunction; + release_minitouch(); clear_info(); #ifdef ASST_DEBUG if (config == "DEBUG") { - set_inited(true); + make_instance_inited(true); return true; } #endif @@ -1195,7 +1271,7 @@ bool asst::Controller::connect(const std::string& adb_path, const std::string& a return false; } - if (m_enable_minitouch) { + if (m_minitouch_enabled) { auto minitouch_cmd_rep = [&](const std::string& cfg_cmd) -> std::string { return utils::string_replace_all( cmd_replace(cfg_cmd), @@ -1208,8 +1284,7 @@ bool asst::Controller::connect(const std::string& adb_path, const std::string& a call_command(minitouch_cmd_rep(adb_cfg.push_minitouch)); call_command(minitouch_cmd_rep(adb_cfg.chmod_minitouch)); - - m_adb.call_minitouch = minitouch_cmd_rep(adb_cfg.call_minitouch); + call_and_hup_minitouch(minitouch_cmd_rep(adb_cfg.call_minitouch)); } // try to find the fastest way @@ -1221,9 +1296,9 @@ bool asst::Controller::connect(const std::string& adb_path, const std::string& a return true; } -bool asst::Controller::set_inited(bool inited) +bool asst::Controller::make_instance_inited(bool inited) { - Log.trace(__FUNCTION__, "|", inited, ", m_inited =", m_inited, ", m_instance_count =", m_instance_count); + Log.trace(__FUNCTION__, "|", inited, ", pre m_inited =", m_inited, ", pre m_instance_count =", m_instance_count); if (inited == m_inited) { return true; diff --git a/src/MeoAssistant/Controller.h b/src/MeoAssistant/Controller.h index 1209d5fe64..3e36d3ab13 100644 --- a/src/MeoAssistant/Controller.h +++ b/src/MeoAssistant/Controller.h @@ -71,7 +71,7 @@ namespace asst bool allow_reconnect = true, bool recv_by_socket = false); bool release(); void kill_adb_daemon(); - bool set_inited(bool inited); + bool make_instance_inited(bool inited); void close_socket() noexcept; std::optional init_socket(const std::string& local_address); @@ -89,6 +89,10 @@ namespace asst void clear_info() noexcept; void callback(AsstMsg msg, const json::value& details); + bool call_and_hup_minitouch(const std::string& cmd); + bool input_to_minitouch(const std::string& cmd); + void release_minitouch(); + // 转换 data 中的 CRLF 为 LF:有些模拟器自带的 adb,exec-out 输出的 \n 会被替换成 \r\n, // 导致解码错误,所以这里转一下回来(点名批评 mumu 和雷电) static bool convert_lf(std::string& data); @@ -135,8 +139,6 @@ namespace asst std::string start; std::string stop; - std::string call_minitouch; - /* properties */ enum class ScreencapEndOfLine { @@ -156,7 +158,17 @@ namespace asst } screencap_method = ScreencapMethod::UnknownYet; } m_adb; - bool m_enable_minitouch = true; + bool m_minitouch_enabled = true; // 开关 + bool m_minitouch_avaiable = false; // 状态 + +#ifdef _WIN32 + HANDLE m_minitouch_in_write = nullptr; + ASST_AUTO_DEDUCED_ZERO_INIT_START + PROCESS_INFORMATION m_minitouch_process_info = { nullptr }; + ASST_AUTO_DEDUCED_ZERO_INIT_END +#else + // TODO +#endif inline static std::filesystem::path m_resource_path; @@ -185,33 +197,29 @@ namespace asst inline static std::string down(int x, int y, bool with_commit = true, bool with_wait = true, int contact = 0, int pressure = 50) { - std::stringstream ss; - ss << "d " << contact << " " << x << " " << y << " " << pressure << "\\n"; - if (with_commit) ss << commit(); - if (with_wait) ss << wait(); - return ss.str(); + std::string str = std::format("d {} {} {} {}\\n", contact, x, y, pressure); + if (with_commit) str += commit(); + if (with_wait) str += wait(); + return str; } inline static std::string move(int x, int y, bool with_commit = true, bool with_wait = true, int contact = 0, int pressure = 50) { - std::stringstream ss; - ss << "m " << contact << " " << x << " " << y << " " << pressure << "\\n"; - if (with_commit) ss << commit(); - if (with_wait) ss << wait(); - return ss.str(); + std::string str = std::format("m {} {} {} {}\\n", contact, x, y, pressure); + if (with_commit) str += commit(); + if (with_wait) str += wait(); + return str; } inline static std::string up(bool with_commit = true, int contact = 0) { - std::stringstream ss; - ss << "u " << contact << "\\n"; - if (with_commit) ss << commit(); - return ss.str(); + std::string str = std::format("u {}\\n", contact); + if (with_commit) str += commit(); + return str; } inline static std::string wait(int ms = DefaultInterval) { - std::stringstream ss; - ss << "w " << ms << "\\n"; - return ss.str(); + std::string str = std::format("w {}\\n", ms); + return str; } }; diff --git a/src/MeoAssistant/Utils/Platform/AsstPlatformWin32.cpp b/src/MeoAssistant/Utils/Platform/AsstPlatformWin32.cpp index 5ba9a351d3..09b51f4c30 100644 --- a/src/MeoAssistant/Utils/Platform/AsstPlatformWin32.cpp +++ b/src/MeoAssistant/Utils/Platform/AsstPlatformWin32.cpp @@ -148,7 +148,7 @@ std::string asst::platform::call_command(const std::string& cmdline, bool* exit_ auto cmdline_osstr = to_osstring(cmdline); BOOL create_ret = - CreateProcessW(nullptr, &cmdline_osstr[0], nullptr, nullptr, TRUE, 0, nullptr, nullptr, &si, &process_info); + CreateProcessW(nullptr, cmdline_osstr.data(), nullptr, nullptr, TRUE, 0, nullptr, nullptr, &si, &process_info); if (!create_ret) { Log.error("Call `", cmdline, "` create process failed, ret", create_ret); return {};