#pragma once #include "AdbController.h" #include "Config/GeneralConfig.h" #include namespace asst { class MinitouchController : public AdbController { public: MinitouchController(const AsstCallback& callback, Assistant* inst, PlatformType type) : AdbController(callback, inst, type) { } MinitouchController(const MinitouchController&) = delete; MinitouchController(MinitouchController&&) = delete; virtual ~MinitouchController(); virtual bool connect(const std::string& adb_path, const std::string& address, const std::string& config) override; virtual void set_swipe_with_pause(bool enable) noexcept override; virtual bool click(const Point& p) override; virtual bool swipe( const Point& p1, const Point& p2, int duration = 0, bool extra_swipe = false, double slope_in = 1, double slope_out = 1, bool with_pause = false) override; virtual bool inject_input_event(const InputEvent& event) override; virtual ControlFeat::Feat support_features() const noexcept override; MinitouchController& operator=(const MinitouchController&) = delete; MinitouchController& operator=(MinitouchController&&) = delete; virtual void back_to_home() noexcept override; protected: virtual std::optional reconnect(const std::string& cmd, int64_t timeout, bool recv_by_socket) override; bool call_and_hup_minitouch(); bool probe_minitouch(const AdbCfg& adb_cfg, std::function cmd_replace); bool input_to_minitouch(const std::string& cmd); void release_minitouch(bool force = false); bool use_swipe_with_pause() const noexcept; virtual void clear_info() noexcept override; bool m_minitouch_available = false; bool m_use_maa_touch = false; bool m_swipe_with_pause_enabled = false; std::shared_ptr m_minitouch_handler = nullptr; class Minitoucher; std::unique_ptr m_minitoucher = nullptr; struct MinitouchProps { int max_contacts = 0; int max_x = 0; int max_y = 0; int max_pressure = 0; double x_scaling = 0; double y_scaling = 0; int orientation = 0; } m_minitouch_props; class Minitoucher { public: using InputFunc = std::function; public: static constexpr int DefaultClickDelay = 50; static constexpr int DefaultSwipeDelay = 2; static constexpr int ExtraDelay = 0; Minitoucher(InputFunc func, const MinitouchProps& props) : m_input_func(func), m_props(props) { } ~Minitoucher() = default; // nodiscard! for false return value may indicating *this got replaced in m_input_func [[nodiscard]] bool reset() { return m_input_func(reset_cmd()); } [[nodiscard]] bool commit() { return m_input_func(commit_cmd()); } [[nodiscard]] bool down(int x, int y, int wait_ms = DefaultClickDelay, bool with_commit = true, int contact = 0) { return m_input_func(down_cmd(x, y, wait_ms, with_commit, contact)); } [[nodiscard]] bool move(int x, int y, int wait_ms = DefaultSwipeDelay, bool with_commit = true, int contact = 0) { return m_input_func(move_cmd(x, y, wait_ms, with_commit, contact)); } [[nodiscard]] bool up(int wait_ms = DefaultClickDelay, bool with_commit = true, int contact = 0) { return m_input_func(up_cmd(wait_ms, with_commit, contact)); } [[nodiscard]] bool key_down(int key_code, int wait_ms = DefaultClickDelay, bool with_commit = true) { return m_input_func(key_down_cmd(key_code, wait_ms, with_commit)); } [[nodiscard]] bool key_up(int key_code, int wait_ms = DefaultClickDelay, bool with_commit = true) { return m_input_func(key_up_cmd(key_code, wait_ms, with_commit)); } [[nodiscard]] bool wait(int ms) { return m_input_func(wait_cmd(ms)); } void clear() noexcept { m_wait_ms_count = 0; } void extra_sleep() { sleep(); } private: [[nodiscard]] std::string reset_cmd() const noexcept { return "r\n"; } [[nodiscard]] std::string commit_cmd() const noexcept { return "c\n"; } #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4996) #endif [[nodiscard]] std::string down_cmd(int x, int y, int wait_ms = DefaultClickDelay, bool with_commit = true, int contact = 0) { auto [c_x, c_y] = scale(x, y); std::string str = std::format("d {} {} {} {}\n", contact, c_x, c_y, m_props.max_pressure); if (with_commit) { str += commit_cmd(); } if (wait_ms) { str += wait_cmd(wait_ms); } return str; } [[nodiscard]] std::string move_cmd(int x, int y, int wait_ms = DefaultSwipeDelay, bool with_commit = true, int contact = 0) { auto [c_x, c_y] = scale(x, y); std::string str = std::format("m {} {} {} {}\n", contact, c_x, c_y, m_props.max_pressure); if (with_commit) { str += commit_cmd(); } if (wait_ms) { str += wait_cmd(wait_ms); } return str; } [[nodiscard]] std::string up_cmd(int wait_ms = DefaultClickDelay, bool with_commit = true, int contact = 0) { std::string str = std::format("u {}\n", contact); if (with_commit) { str += commit_cmd(); } if (wait_ms) { str += wait_cmd(wait_ms); } return str; } [[nodiscard]] std::string key_down_cmd(int key_code, int wait_ms = DefaultClickDelay, bool with_commit = true) { std::string str = std::format("k {} d\n", key_code); if (with_commit) { str += commit_cmd(); } if (wait_ms) { str += wait_cmd(wait_ms); } return str; } [[nodiscard]] std::string key_up_cmd(int key_code, int wait_ms = DefaultClickDelay, bool with_commit = true) { std::string str = std::format("k {} u\n", key_code); if (with_commit) { str += commit_cmd(); } if (wait_ms) { str += wait_cmd(wait_ms); } return str; } [[nodiscard]] std::string wait_cmd(int ms) { return std::format("w {}\n", ms); } #ifdef _MSC_VER #pragma warning(pop) #endif void sleep() { using namespace std::chrono_literals; std::this_thread::sleep_for(m_wait_ms_count * 1ms); m_wait_ms_count = 0; } private: Point scale(int x, int y) const noexcept { switch (m_props.orientation) { case 0: default: return { static_cast(x * m_props.x_scaling), static_cast(y * m_props.y_scaling), }; case 1: return { m_props.max_y - static_cast(y * m_props.y_scaling), static_cast(x * m_props.x_scaling), }; case 2: return { m_props.max_x - static_cast(x * m_props.x_scaling), m_props.max_y - static_cast(y * m_props.y_scaling), }; case 3: return { static_cast(y * m_props.y_scaling), m_props.max_x - static_cast(x * m_props.x_scaling), }; } } const std::function m_input_func = nullptr; const MinitouchProps& m_props; int m_wait_ms_count = ExtraDelay; }; }; } // namespace asst