]> git.tdb.fi Git - libs/gui.git/commitdiff
Add an input event synthetizer class
authorMikko Rasa <tdb@tdb.fi>
Tue, 5 Sep 2023 12:33:20 +0000 (15:33 +0300)
committerMikko Rasa <tdb@tdb.fi>
Tue, 5 Sep 2023 12:39:08 +0000 (15:39 +0300)
source/input/synthesizer.cpp [new file with mode: 0644]
source/input/synthesizer.h [new file with mode: 0644]
source/input/windows/synthesizer.cpp [new file with mode: 0644]
source/input/x11/synthesizer.cpp [new file with mode: 0644]

diff --git a/source/input/synthesizer.cpp b/source/input/synthesizer.cpp
new file mode 100644 (file)
index 0000000..4b34490
--- /dev/null
@@ -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 (file)
index 0000000..844c39a
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef MSP_INPUT_SYNTHESIZER_H_
+#define MSP_INPUT_SYNTHESIZER_H_
+
+#include <msp/graphics/display.h>
+#include <msp/graphics/mspgui_api.h>
+#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 (file)
index 0000000..deef9a3
--- /dev/null
@@ -0,0 +1,98 @@
+#include <windows.h>
+#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 (file)
index 0000000..7326b33
--- /dev/null
@@ -0,0 +1,56 @@
+#include <X11/extensions/XTest.h>
+#include <msp/graphics/display_private.h>
+#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