diff --git a/core/debugger/remote_debugger.cpp b/core/debugger/remote_debugger.cpp index 1107599b1322..382b0533bfdd 100644 --- a/core/debugger/remote_debugger.cpp +++ b/core/debugger/remote_debugger.cpp @@ -36,6 +36,7 @@ #include "core/debugger/engine_profiler.h" #include "core/debugger/script_debugger.h" #include "core/input/input.h" +#include "core/input/input_event.h" #include "core/io/resource_loader.h" #include "core/math/expression.h" #include "core/object/script_language.h" @@ -768,6 +769,33 @@ Error RemoteDebugger::_automation_capture(const String &p_cmd, const Array &p_da ERR_FAIL_COND_V(p_data.size() < 2, ERR_INVALID_DATA); Array args = p_data.size() > 2 ? Array(p_data[2]) : Array(); _call_method(p_data[0], p_data[1], args); + } else if (p_cmd == "mouse_button") { + // mouse_button: [x, y, button_index, pressed, double_click?] + ERR_FAIL_COND_V(p_data.size() < 4, ERR_INVALID_DATA); + Vector2 pos(p_data[0], p_data[1]); + bool double_click = p_data.size() > 4 ? (bool)p_data[4] : false; + _inject_mouse_button(pos, p_data[2], p_data[3], double_click); + } else if (p_cmd == "mouse_motion") { + // mouse_motion: [x, y, relative_x, relative_y] + ERR_FAIL_COND_V(p_data.size() < 4, ERR_INVALID_DATA); + Vector2 pos(p_data[0], p_data[1]); + Vector2 rel(p_data[2], p_data[3]); + _inject_mouse_motion(pos, rel); + } else if (p_cmd == "key") { + // key: [keycode, pressed, physical?] + ERR_FAIL_COND_V(p_data.size() < 2, ERR_INVALID_DATA); + bool physical = p_data.size() > 2 ? (bool)p_data[2] : false; + _inject_key(p_data[0], p_data[1], physical); + } else if (p_cmd == "touch") { + // touch: [index, x, y, pressed] + ERR_FAIL_COND_V(p_data.size() < 4, ERR_INVALID_DATA); + Vector2 pos(p_data[1], p_data[2]); + _inject_touch(p_data[0], pos, p_data[3]); + } else if (p_cmd == "action") { + // action: [action_name, pressed, strength?] + ERR_FAIL_COND_V(p_data.size() < 2, ERR_INVALID_DATA); + float strength = p_data.size() > 2 ? (float)p_data[2] : 1.0f; + _inject_action(p_data[0], p_data[1], strength); } else { r_captured = false; } @@ -898,6 +926,100 @@ Dictionary RemoteDebugger::_serialize_node(Node *p_node) { return data; } +void RemoteDebugger::_inject_mouse_button(const Vector2 &p_position, int p_button, bool p_pressed, bool p_double_click) { + Input *input = Input::get_singleton(); + ERR_FAIL_NULL(input); + + Ref ev; + ev.instantiate(); + ev->set_device(InputEvent::DEVICE_ID_EMULATION); + ev->set_position(p_position); + ev->set_global_position(p_position); + ev->set_button_index((MouseButton)p_button); + ev->set_pressed(p_pressed); + ev->set_double_click(p_double_click); + + input->parse_input_event(ev); + + Array msg; + msg.push_back(true); + EngineDebugger::get_singleton()->send_message("automation:input_result", msg); +} + +void RemoteDebugger::_inject_mouse_motion(const Vector2 &p_position, const Vector2 &p_relative) { + Input *input = Input::get_singleton(); + ERR_FAIL_NULL(input); + + Ref ev; + ev.instantiate(); + ev->set_device(InputEvent::DEVICE_ID_EMULATION); + ev->set_position(p_position); + ev->set_global_position(p_position); + ev->set_relative(p_relative); + ev->set_button_mask(input->get_mouse_button_mask()); + + input->parse_input_event(ev); + + Array msg; + msg.push_back(true); + EngineDebugger::get_singleton()->send_message("automation:input_result", msg); +} + +void RemoteDebugger::_inject_key(int p_keycode, bool p_pressed, bool p_physical) { + Input *input = Input::get_singleton(); + ERR_FAIL_NULL(input); + + Ref ev; + ev.instantiate(); + ev->set_device(InputEvent::DEVICE_ID_EMULATION); + ev->set_pressed(p_pressed); + + if (p_physical) { + ev->set_physical_keycode((Key)p_keycode); + } else { + ev->set_keycode((Key)p_keycode); + } + + input->parse_input_event(ev); + + Array msg; + msg.push_back(true); + EngineDebugger::get_singleton()->send_message("automation:input_result", msg); +} + +void RemoteDebugger::_inject_touch(int p_index, const Vector2 &p_position, bool p_pressed) { + Input *input = Input::get_singleton(); + ERR_FAIL_NULL(input); + + Ref ev; + ev.instantiate(); + ev->set_device(InputEvent::DEVICE_ID_EMULATION); + ev->set_index(p_index); + ev->set_position(p_position); + ev->set_pressed(p_pressed); + + input->parse_input_event(ev); + + Array msg; + msg.push_back(true); + EngineDebugger::get_singleton()->send_message("automation:input_result", msg); +} + +void RemoteDebugger::_inject_action(const String &p_action, bool p_pressed, float p_strength) { + Input *input = Input::get_singleton(); + ERR_FAIL_NULL(input); + + if (p_pressed) { + input->action_press(p_action, p_strength); + } else { + input->action_release(p_action); + } + + Array msg; + msg.push_back(true); + EngineDebugger::get_singleton()->send_message("automation:input_result", msg); +} + RemoteDebugger::RemoteDebugger(Ref p_peer) { peer = p_peer; max_chars_per_second = GLOBAL_GET("network/limits/debugger/max_chars_per_second"); diff --git a/core/debugger/remote_debugger.h b/core/debugger/remote_debugger.h index 6f6ee970066d..1a46b62ae5c6 100644 --- a/core/debugger/remote_debugger.h +++ b/core/debugger/remote_debugger.h @@ -120,6 +120,13 @@ class RemoteDebugger : public EngineDebugger { void _call_method(const String &p_path, const String &p_method, const Array &p_args); Dictionary _serialize_node(class Node *p_node); + // Input injection for automation (Phase 2) + void _inject_mouse_button(const Vector2 &p_position, int p_button, bool p_pressed, bool p_double_click = false); + void _inject_mouse_motion(const Vector2 &p_position, const Vector2 &p_relative); + void _inject_key(int p_keycode, bool p_pressed, bool p_physical = false); + void _inject_touch(int p_index, const Vector2 &p_position, bool p_pressed); + void _inject_action(const String &p_action, bool p_pressed, float p_strength = 1.0f); + public: // Overrides void poll_events(bool p_is_idle);