--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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