From 0deab959c5477fc43fe21787a426d5d092a5c91a Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Tue, 5 Sep 2023 15:33:20 +0300 Subject: [PATCH] Add an input event synthetizer class --- source/input/synthesizer.cpp | 19 ++++++ source/input/synthesizer.h | 32 +++++++++ source/input/windows/synthesizer.cpp | 98 ++++++++++++++++++++++++++++ source/input/x11/synthesizer.cpp | 56 ++++++++++++++++ 4 files changed, 205 insertions(+) create mode 100644 source/input/synthesizer.cpp create mode 100644 source/input/synthesizer.h create mode 100644 source/input/windows/synthesizer.cpp create mode 100644 source/input/x11/synthesizer.cpp diff --git a/source/input/synthesizer.cpp b/source/input/synthesizer.cpp new file mode 100644 index 0000000..4b34490 --- /dev/null +++ b/source/input/synthesizer.cpp @@ -0,0 +1,19 @@ +#include "synthesizer.h" + +namespace Msp { +namespace Input { + +void Synthesizer::click_key(Key key) +{ + press_key(key); + release_key(key); +} + +void Synthesizer::click_mouse_button(MouseButton button) +{ + press_mouse_button(button); + release_mouse_button(button); +} + +} // namespace Input +} // namespace Msp diff --git a/source/input/synthesizer.h b/source/input/synthesizer.h new file mode 100644 index 0000000..844c39a --- /dev/null +++ b/source/input/synthesizer.h @@ -0,0 +1,32 @@ +#ifndef MSP_INPUT_SYNTHESIZER_H_ +#define MSP_INPUT_SYNTHESIZER_H_ + +#include +#include +#include "keys.h" + +namespace Msp { +namespace Input { + +class MSPGUI_API Synthesizer +{ +private: + Graphics::Display &display; + +public: + Synthesizer(Graphics::Display &); + + void press_key(Key); + void release_key(Key); + void click_key(Key); + + void move_mouse_to(int ,int); + void press_mouse_button(MouseButton); + void release_mouse_button(MouseButton); + void click_mouse_button(MouseButton); +}; + +} // namespace Input +} // namespace Msp + +#endif diff --git a/source/input/windows/synthesizer.cpp b/source/input/windows/synthesizer.cpp new file mode 100644 index 0000000..deef9a3 --- /dev/null +++ b/source/input/windows/synthesizer.cpp @@ -0,0 +1,98 @@ +#include +#include "keys_private.h" +#include "synthesizer.h" + +using namespace std; + +namespace { + +void send_key_input(Msp::Input::Key key, bool press) +{ + INPUT input; + + input.type = INPUT_KEYBOARD; + input.ki.wVk = key_to_sys(key); + input.ki.wScan = 0; + input.ki.dwFlags = (press ? 0 : KEYEVENTF_KEYUP); + input.ki.time = 0; + input.ki.dwExtraInfo = 0; + + SendInput(1, &input, sizeof(INPUT)); +} + +void send_button_input(Msp::Input::MouseButton button, bool press) +{ + INPUT input; + + input.type = INPUT_MOUSE; + input.mi.dx = 0; + input.mi.dy = 0; + input.mi.mouseData = 0; + switch(button) + { + case Msp::Input::MOUSE_LEFT: + input.mi.dwFlags = (press ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_LEFTUP); + break; + case Msp::Input::MOUSE_MIDDLE: + input.mi.dwFlags = (press ? MOUSEEVENTF_MIDDLEDOWN : MOUSEEVENTF_MIDDLEUP); + break; + case Msp::Input::MOUSE_RIGHT: + input.mi.dwFlags = (press ? MOUSEEVENTF_RIGHTDOWN : MOUSEEVENTF_RIGHTUP); + break; + default: + throw invalid_argument("send_button_input"); + } + input.mi.time = 0; + input.mi.dwExtraInfo = 0; + + SendInput(1, &input, sizeof(INPUT)); +} + +} + +namespace Msp { +namespace Input { + +Synthesizer::Synthesizer(Graphics::Display &d): + display(d) +{ } + +void Synthesizer::press_key(Key key) +{ + send_key_input(key, true); +} + +void Synthesizer::release_key(Key key) +{ + send_key_input(key, false); +} + +void Synthesizer::move_mouse_to(int x, int y) +{ + const Graphics::VideoMode &desktop_mode = display.get_desktop_mode(); + + INPUT input; + + input.type = INPUT_MOUSE; + input.mi.dx = x*65535/(desktop_mode.width-1); + input.mi.dy = y*65535/(desktop_mode.height-1); + input.mi.mouseData = 0; + input.mi.dwFlags = MOUSEEVENTF_ABSOLUTE; + input.mi.time = 0; + input.mi.dwExtraInfo = 0; + + SendInput(1, &input, sizeof(INPUT)); +} + +void Synthesizer::press_mouse_button(MouseButton button) +{ + send_button_input(button, true); +} + +void Synthesizer::release_mouse_button(MouseButton button) +{ + send_button_input(button, false); +} + +} // namespace Input +} // namespace Msp diff --git a/source/input/x11/synthesizer.cpp b/source/input/x11/synthesizer.cpp new file mode 100644 index 0000000..7326b33 --- /dev/null +++ b/source/input/x11/synthesizer.cpp @@ -0,0 +1,56 @@ +#include +#include +#include "keys_private.h" +#include "synthesizer.h" + +using namespace std; + +namespace Msp { +namespace Input { + +Synthesizer::Synthesizer(Graphics::Display &d): + display(d) +{ + ::Display *dpy = display.get_private().display; + int event_base; + int error_base; + int major_ver; + int minor_ver; + if(!XTestQueryExtension(dpy, &event_base, &error_base, &major_ver, &minor_ver)) + throw runtime_error("XTest is not supported"); +} + +void Synthesizer::press_key(Key key) +{ + ::Display *dpy = display.get_private().display; + unsigned code = XKeysymToKeycode(dpy, key_to_sys(key)); + XTestFakeKeyEvent(dpy, code, true, CurrentTime); +} + +void Synthesizer::release_key(Key key) +{ + ::Display *dpy = display.get_private().display; + unsigned code = XKeysymToKeycode(dpy, key_to_sys(key)); + XTestFakeKeyEvent(dpy, code, false, CurrentTime); +} + +void Synthesizer::move_mouse_to(int x, int y) +{ + ::Display *dpy = display.get_private().display; + XTestFakeMotionEvent(dpy, -1, x, y, CurrentTime); +} + +void Synthesizer::press_mouse_button(MouseButton button) +{ + ::Display *dpy = display.get_private().display; + XTestFakeButtonEvent(dpy, button, true, CurrentTime); +} + +void Synthesizer::release_mouse_button(MouseButton button) +{ + ::Display *dpy = display.get_private().display; + XTestFakeButtonEvent(dpy, button, false, CurrentTime); +} + +} // namespace Input +} // namespace Msp -- 2.45.2