From a02a5cfcf33bb2c0edae246c1b19e286bf86d422 Mon Sep 17 00:00:00 2001 From: Kevin Ollivier Date: Sat, 6 Mar 2010 20:09:23 +0000 Subject: [PATCH] Adding wxUIActionSimulator, a class for programmatically controlling the mouse and keyboard. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@63644 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- build/bakefiles/files.bkl | 7 +- include/wx/uiaction.h | 51 +++++++++++ interface/wx/uiaction.h | 150 +++++++++++++++++++++++++++++++ samples/samples.bkl | 1 + samples/uiaction/uiaction.bkl | 15 ++++ samples/uiaction/uiaction.cpp | 161 ++++++++++++++++++++++++++++++++++ src/common/uiactioncmn.cpp | 59 +++++++++++++ src/msw/uiaction.cpp | 78 ++++++++++++++++ src/osx/uiaction_osx.cpp | 132 ++++++++++++++++++++++++++++ src/unix/uiactionx11.cpp | 123 ++++++++++++++++++++++++++ 10 files changed, 776 insertions(+), 1 deletion(-) create mode 100644 include/wx/uiaction.h create mode 100644 interface/wx/uiaction.h create mode 100644 samples/uiaction/uiaction.bkl create mode 100644 samples/uiaction/uiaction.cpp create mode 100644 src/common/uiactioncmn.cpp create mode 100644 src/msw/uiaction.cpp create mode 100644 src/osx/uiaction_osx.cpp create mode 100644 src/unix/uiactionx11.cpp diff --git a/build/bakefiles/files.bkl b/build/bakefiles/files.bkl index 9b26b772bd..2605b2baf5 100644 --- a/build/bakefiles/files.bkl +++ b/build/bakefiles/files.bkl @@ -727,6 +727,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! src/common/textentrycmn.cpp src/common/toplvcmn.cpp src/common/treebase.cpp + src/common/uiactioncmn.cpp src/common/valgen.cpp src/common/validate.cpp src/common/valtext.cpp @@ -966,6 +967,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! wx/treebase.h wx/treebook.h wx/treectrl.h + wx/uiaction.h wx/valgen.h wx/vidmode.h wx/vlbox.h @@ -991,10 +993,11 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! src/generic/caret.cpp src/generic/imaglist.cpp src/unix/dialup.cpp + src/unix/displayx11.cpp src/unix/fontenum.cpp src/unix/fontutil.cpp + src/unix/uiactionx11.cpp src/unix/utilsx11.cpp - src/unix/displayx11.cpp wx/generic/caret.h @@ -1710,6 +1713,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! src/msw/textentry.cpp src/msw/tglbtn.cpp src/msw/treectrl.cpp + src/msw/uiaction.cpp wx/generic/clrpickerg.h @@ -2257,6 +2261,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! src/osx/textctrl_osx.cpp src/osx/tglbtn_osx.cpp src/osx/toolbar_osx.cpp + src/osx/uiaction_osx.cpp src/html/htmlctrl/webkit/webkit.mm diff --git a/include/wx/uiaction.h b/include/wx/uiaction.h new file mode 100644 index 0000000000..ebce484040 --- /dev/null +++ b/include/wx/uiaction.h @@ -0,0 +1,51 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: include/wx/uiaction.cpp +// Purpose: wxUIActionSimulator interface +// Author: Kevin Ollivier +// Modified by: +// Created: 2010-03-06 +// RCS-ID: $Id: menu.cpp 54129 2008-06-11 19:30:52Z SC $ +// Copyright: (c) Kevin Ollivier +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _UIACTIONSIMULATOR_H_ +#define _UIACTIONSIMULATOR_H_ + +#include +#include +#include + +class WXDLLIMPEXP_CORE wxUIActionSimulator +{ +public: + wxUIActionSimulator(); + ~wxUIActionSimulator(); + + // Mouse related + bool MouseMove(long x, long y); + bool MouseDown(int button = wxMOUSE_BTN_LEFT); + bool MouseUp(int button = wxMOUSE_BTN_LEFT); + bool MouseClick(int button = wxMOUSE_BTN_LEFT); + bool MouseDblClick(int button = wxMOUSE_BTN_LEFT); + bool MouseDragDrop(long x1, long y1, long x2, long y2, int button = wxMOUSE_BTN_LEFT); + + // Keyboard related: + + bool KeyDown(int keycode, bool shiftDown=false, bool cmdDown=false, bool altDown=false) + { return Key(keycode, true, shiftDown, cmdDown, altDown); } + + bool KeyUp(int keycode, bool shiftDown=false, bool cmdDown=false, bool altDown=false) + { return Key(keycode, false, shiftDown, cmdDown, altDown); } + + bool Char(int keycode, bool shiftDown=false, bool cmdDown=false, bool altDown=false); + +protected: + // Implementation-wise, since key events take more code to set up on GTK and Mac, it makes + // sense to handle both key down and key up in one method. However, I wanted the API for pressing + // and releasing the mouse and keyboard to be consistent, and I don't really like using a bool + // for pressed state, so I'm leaving this as an implementation detail. + bool Key(int keycode, bool isDown=true, bool shiftDown=false, bool cmdDown=false, bool altDown=false); +}; + +#endif diff --git a/interface/wx/uiaction.h b/interface/wx/uiaction.h new file mode 100644 index 0000000000..dbb83ccf9f --- /dev/null +++ b/interface/wx/uiaction.h @@ -0,0 +1,150 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: uiaction.h +// Purpose: interface of wxUIActionSimulator +// Author: wxWidgets team +// RCS-ID: $Id$ +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// + +/** + @class wxUIActionSimulator + + wxUIActionSimulator is a class used to simulate user interface actions + such as a mouse click or a key press. + + Common usages for this class would be to provide playback and record (aka macro recording) + functionality for users, or to drive unit tests by simulating user sessions. + + See the uiaction sample for example usage of this class. + + NOTE: For keyboard operations, currently you must pass the keycode of the actual + key on the keyboard. To simulate, e.g. IME actions, you'd need to simulate the actual + keypresses needed to active the IME, then the keypresses needed to type and select + the desired character. + + @library{wxcore} +*/ + +class wxUIActionSimulator +{ + public: + /** + Constructor. + */ + wxUIActionSimulator(); + ~wxUIActionSimulator(); + + /** + Move the mouse to the specified coordinates. + + @param x + x coordinate to move to, in screen coordinates. + + @param y + y coordinate to move to, in screen coordinates. + */ + bool MouseMove(long x, long y); + + /** + Press a mouse button. + + @param button + Button to press. Valid constants are wxMOUSE_BTN_LEFT, wxMOUSE_BTN_MIDDLE, and wxMOUSE_BTN_RIGHT. + */ + bool MouseDown(int button = wxMOUSE_BTN_LEFT); + + /** + Release a mouse button. + + @param button + Button to press. See wxUIActionSimulator::MouseDown for a list of valid constants. + */ + bool MouseUp(int button = wxMOUSE_BTN_LEFT); + /** + Click a mouse button. + + @param button + Button to press. See wxUIActionSimulator::MouseDown for a list of valid constants. + */ + bool MouseClick(int button = wxMOUSE_BTN_LEFT); + /** + Double-click a mouse button. + + @param button + Button to press. See wxUIActionSimulator::MouseDown for a list of valid constants. + */ + bool MouseDblClick(int button = wxMOUSE_BTN_LEFT); + + /** + Perform a drag and drop operation. + + @param x1 + x start coordinate, in screen coordinates. + + @param y1 + y start coordinate, in screen coordinates. + + @param x2 + x desintation coordinate, in screen coordinates. + + @param y2 + y destination coordinate, in screen coordinates. + + @param button + Button to press. See wxUIActionSimulator::MouseDown for a list of valid constants. + */ + bool MouseDragDrop(long x1, long y1, long x2, long y2, int button = wxMOUSE_BTN_LEFT); + + /** + Press a key. + + @param keycode + key to operate on, as an integer. + + @param shiftDown + true if the shift key should be pressed, false otherwise. + + @param cmdDown + true if the cmd key should be pressed, false otherwise. + + @param altDown + true if the alt key should be pressed, false otherwise. + */ + bool KeyDown(int keycode, bool shiftDown=false, bool cmdDown=false, bool altDown=false); + + /** + Release a key. + + @param keycode + key to operate on, as an integer. + + @param shiftDown + true if the shift key should be pressed, false otherwise. + + @param cmdDown + true if the cmd key should be pressed, false otherwise. + + @param altDown + true if the alt key should be pressed, false otherwise. + */ + bool KeyUp(int keycode, bool shiftDown=false, bool cmdDown=false, bool altDown=false); + + /** + Press and release a key. + + @param keycode + key to operate on, as an integer. + + @param shiftDown + true if the shift key should be pressed, false otherwise. + + @param cmdDown + true if the cmd key should be pressed, false otherwise. + + @param altDown + true if the alt key should be pressed, false otherwise. + */ + bool Char(int keycode, bool shiftDown=false, bool cmdDown=false, bool altDown=false); +}; + +#endif diff --git a/samples/samples.bkl b/samples/samples.bkl index a142ff119b..5073244c20 100644 --- a/samples/samples.bkl +++ b/samples/samples.bkl @@ -84,6 +84,7 @@ + diff --git a/samples/uiaction/uiaction.bkl b/samples/uiaction/uiaction.bkl new file mode 100644 index 0000000000..872f9df1c1 --- /dev/null +++ b/samples/uiaction/uiaction.bkl @@ -0,0 +1,15 @@ + + + + + + + + + uiaction.cpp + core + base + wx06 + + + diff --git a/samples/uiaction/uiaction.cpp b/samples/uiaction/uiaction.cpp new file mode 100644 index 0000000000..a9eeb43519 --- /dev/null +++ b/samples/uiaction/uiaction.cpp @@ -0,0 +1,161 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: uiaction.cpp +// Purpose: wxUIActionSimulator sample +// Author: Kevin Ollivier +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id$ +// Copyright: (c) Kevin Ollivier +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx/wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +// for all others, include the necessary headers (this file is usually all you +// need because it includes almost all "standard" wxWidgets headers) +#ifndef WX_PRECOMP + #include "wx/wx.h" +#endif + +#include "wx/uiaction.h" + +// ---------------------------------------------------------------------------- +// resources +// ---------------------------------------------------------------------------- + +// the application icon (under Windows and OS/2 it is in resources and even +// though we could still include the XPM here it would be unused) +#if !defined(__WXMSW__) && !defined(__WXPM__) + #include "../sample.xpm" +#endif + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +// Define a new application type, each program should derive a class from wxApp +class MyApp : public wxApp +{ +public: + virtual bool OnInit(); +}; + +// Define a new frame type: this is going to be our main frame +class MyFrame : public wxFrame +{ +public: + // ctor(s) + MyFrame(const wxString& title); + + void OnButtonPressed(wxCommandEvent&); + void OnRunSimulation(wxCommandEvent&); + + bool ButtonPressed() const { return m_buttonPressed; } + bool MenuSelected() const { return m_menuSelected; } + +private: + bool m_buttonPressed; + bool m_menuSelected; +}; + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// IDs for the controls and the menu commands +enum +{ + // menu items + TheButton = wxID_ANY, + RunSimulation = wxID_ANY +}; + +IMPLEMENT_APP(MyApp) + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// the application class +// ---------------------------------------------------------------------------- + +bool MyApp::OnInit() +{ + if ( !wxApp::OnInit() ) + return false; + + MyFrame *frame = new MyFrame("wxUIActionSimulator sample application"); + frame->Show(true); + + return true; +} + +// ---------------------------------------------------------------------------- +// main frame +// ---------------------------------------------------------------------------- + +// frame constructor +MyFrame::MyFrame(const wxString& title) + : wxFrame(NULL, wxID_ANY, title) +{ + SetIcon(wxICON(sample)); + + m_buttonPressed = false; + m_menuSelected = false; + +#if wxUSE_MENUS + // create a menu bar + wxMenu *fileMenu = new wxMenu; + + fileMenu->Append(wxID_NEW, "&New File...", "Open a new file"); + fileMenu->Append(RunSimulation, "&Run Simulation...", "Run the UI action simulation"); + + fileMenu->Append(wxID_EXIT, "E&xit\tAlt-X", "Quit this program"); + + wxMenuBar *menuBar = new wxMenuBar(); + menuBar->Append(fileMenu, "&File"); + + SetMenuBar(menuBar); +#endif // wxUSE_MENUS + + wxButton* button = new wxButton(this, TheButton, "Button"); + button->SetName("TheButton"); + Bind(wxEVT_COMMAND_BUTTON_CLICKED, &MyFrame::OnButtonPressed, this, button->GetId()); + Bind(wxEVT_COMMAND_MENU_SELECTED, &MyFrame::OnRunSimulation, this, RunSimulation); +} + + +// event handlers + +void MyFrame::OnRunSimulation(wxCommandEvent&) +{ + wxUIActionSimulator sim; + wxWindow* button = FindWindow(wxString("TheButton")); + wxPoint globalPoint = button->ClientToScreen(wxPoint(20, 10)); + sim.MouseMove(globalPoint.x, globalPoint.y); + sim.MouseClick(wxMOUSE_BTN_LEFT); + + wxYield(); + + if (ButtonPressed()) + wxMessageBox("Button automagically pressed!"); +} + +void MyFrame::OnButtonPressed(wxCommandEvent&) +{ + m_buttonPressed = true; +} diff --git a/src/common/uiactioncmn.cpp b/src/common/uiactioncmn.cpp new file mode 100644 index 0000000000..52747d1284 --- /dev/null +++ b/src/common/uiactioncmn.cpp @@ -0,0 +1,59 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/uiactioncmn.cpp +// Purpose: wxUIActionSimulator common implementation +// Author: Kevin Ollivier +// Modified by: +// Created: 2010-03-06 +// RCS-ID: $Id: menu.cpp 54129 2008-06-11 19:30:52Z SC $ +// Copyright: (c) Kevin Ollivier +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#include "wx/wxprec.h" + +#include "wx/uiaction.h" + +wxUIActionSimulator::wxUIActionSimulator() +{ +} + +wxUIActionSimulator::~wxUIActionSimulator() +{ +} + + +bool wxUIActionSimulator::MouseClick(int button) +{ + MouseDown(button); + MouseUp(button); + + return true; +} + +bool wxUIActionSimulator::MouseDblClick(int button) +{ + MouseDown(button); + MouseUp(button); + MouseDown(button); + MouseUp(button); + + return true; +} + +bool wxUIActionSimulator::MouseDragDrop(long x1, long y1, long x2, long y2, int button) +{ + MouseMove(x1, y1); + MouseDown(button); + MouseMove(x2, y2); + MouseUp(button); + + return true; +} + +bool wxUIActionSimulator::Char(int keycode, bool shiftDown, bool cmdDown, bool altDown) +{ + Key(keycode, false, shiftDown, cmdDown, altDown); + Key(keycode, true, shiftDown, cmdDown, altDown); + + return true; +} diff --git a/src/msw/uiaction.cpp b/src/msw/uiaction.cpp new file mode 100644 index 0000000000..6bbbf1abdc --- /dev/null +++ b/src/msw/uiaction.cpp @@ -0,0 +1,78 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: src/msw/uiaction.cpp +// Purpose: wxUIActionSimulator implementation +// Author: Kevin Ollivier +// Modified by: +// Created: 2010-03-06 +// RCS-ID: $Id: menu.cpp 54129 2008-06-11 19:30:52Z SC $ +// Copyright: (c) Kevin Ollivier +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#include "wx/wxprec.h" + +#ifndef WX_PRECOMP +#include "wx/defs.h" +#endif + +#include "wx/uiaction.h" + +#include + +DWORD EventTypeForMouseButton(int button, bool isDown) +{ + switch (button) + { + case wxMOUSE_BTN_LEFT: + if (isDown) + return MOUSEEVENTF_LEFTDOWN; + else + return MOUSEEVENTF_LEFTUP; + case wxMOUSE_BTN_RIGHT: + if (isDown) + return MOUSEEVENTF_RIGHTDOWN; + else + return MOUSEEVENTF_RIGHTUP; + case wxMOUSE_BTN_MIDDLE: + if (isDown) + return MOUSEEVENTF_MIDDLEDOWN; + else + return MOUSEEVENTF_MIDDLEUP; + + default: + wxFAIL_MSG("Unsupported button passed in."); + return -1; + } +} + +bool wxUIActionSimulator::MouseDown(int button) +{ + POINT p; + GetCursorPos(&p); + mouse_event(EventTypeForMouseButton(button, true), p.x, p.y, 0, 0); + return true; +} + +bool wxUIActionSimulator::MouseMove(long x, long y) +{ + mouse_event(MOUSEEVENTF_MOVE, x, y, 0, 0); + return true; +} + +bool wxUIActionSimulator::MouseUp(int button) +{ + POINT p; + GetCursorPos(&p); + mouse_event(EventTypeForMouseButton(button, false), p.x, p.y, 0, 0); + return true; +} + +bool wxUIActionSimulator::Key(int keycode, bool isDown, bool shiftDown, bool cmdDown, bool altDown) +{ + DWORD flags = 0; + if (!isDown) + flags = KEYEVENTF_KEYUP; + keybd_event(keycode, 0, flags, 0); + return true; +} + diff --git a/src/osx/uiaction_osx.cpp b/src/osx/uiaction_osx.cpp new file mode 100644 index 0000000000..bd4afa12c1 --- /dev/null +++ b/src/osx/uiaction_osx.cpp @@ -0,0 +1,132 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: src/osx/uiaction_osx.cpp +// Purpose: wxUIActionSimulator implementation +// Author: Kevin Ollivier +// Modified by: +// Created: 2010-03-06 +// RCS-ID: $Id: menu.cpp 54129 2008-06-11 19:30:52Z SC $ +// Copyright: (c) Kevin Ollivier +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#include +#include + +#include + +CGEventTapLocation tap = kCGSessionEventTap; + +CGEventType CGEventTypeForMouseButton(int button, bool isDown) +{ + switch (button) + { + case wxMOUSE_BTN_LEFT: + if (isDown) + return kCGEventLeftMouseDown; + else + return kCGEventLeftMouseUp; + case wxMOUSE_BTN_RIGHT: + if (isDown) + return kCGEventRightMouseDown; + else + return kCGEventRightMouseUp; + + // Apparently all other buttons use the constant OtherMouseDown + + default: + if (isDown) + return kCGEventOtherMouseDown; + else + return kCGEventOtherMouseUp; + } +} + +void SendCharCode(CGCharCode keycode, bool isDown) +{ + CGEventRef event = CGEventCreateKeyboardEvent(NULL, keycode, isDown); + if (event) + { + CGEventPost(kCGHIDEventTap, event); + } + CFRelease(event); +} + +bool wxUIActionSimulator::MouseDown(int button) +{ + CGPoint pos; + int x, y; + wxGetMousePosition(&x, &y); + pos.x = x; + pos.y = y; + CGEventType type = CGEventTypeForMouseButton(button, true); + CGEventRef event = CGEventCreateMouseEvent(NULL, type, pos, button); + CGEventSetType(event, type); + + if (event) + { + CGEventPost(tap, event); + } + CFRelease(event); + return true; +} + +bool wxUIActionSimulator::MouseMove(long x, long y) +{ + CGPoint pos; + pos.x = x; + pos.y = y; + CGEventType type = kCGEventMouseMoved; + CGEventRef event = CGEventCreateMouseEvent(NULL, type, pos, kCGMouseButtonLeft); + CGEventSetType(event, type); + + if (event) + { + CGEventPost(tap, event); + } + CFRelease(event); + + return true; +} + +bool wxUIActionSimulator::MouseUp(int button) +{ + CGPoint pos; + int x, y; + wxGetMousePosition(&x, &y); + pos.x = x; + pos.y = y; + CGEventType type = CGEventTypeForMouseButton(button, false); + CGEventRef event = CGEventCreateMouseEvent(NULL, type, pos, button); + CGEventSetType(event, type); + + if (event) + { + CGEventPost(tap, event); + } + CFRelease(event); + + return true; +} + +bool wxUIActionSimulator::Key(int keycode, bool isDown, bool shiftDown, bool cmdDown, bool altDown) +{ + if (shiftDown) + SendCharCode((CGCharCode)56, true); + if (altDown) + SendCharCode((CGCharCode)58, true); + if (cmdDown) + SendCharCode((CGCharCode)55, true); + + SendCharCode((CGCharCode)keycode, isDown); + + if (shiftDown) + SendCharCode((CGCharCode)56, false); + if (altDown) + SendCharCode((CGCharCode)58, false); + if (cmdDown) + SendCharCode((CGCharCode)55, false); + + return true; +} + + diff --git a/src/unix/uiactionx11.cpp b/src/unix/uiactionx11.cpp new file mode 100644 index 0000000000..05497efa03 --- /dev/null +++ b/src/unix/uiactionx11.cpp @@ -0,0 +1,123 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: src/unix/uiactionx11.cpp +// Purpose: wxUIActionSimulator implementation +// Author: Kevin Ollivier +// Modified by: +// Created: 2010-03-06 +// RCS-ID: $Id: menu.cpp 54129 2008-06-11 19:30:52Z SC $ +// Copyright: (c) Kevin Ollivier +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#include +#include + +#include +#include +#include + +void SendButtonEvent(int button, bool isDown) +{ + int xbutton = 0; + switch (button) + { + case wxMOUSE_BTN_LEFT: + xbutton = 1; + break; + case wxMOUSE_BTN_RIGHT: + xbutton = 2; + break; + case wxMOUSE_BTN_MIDDLE: + xbutton = 3; + break; + default: + wxFAIL_MSG("Unsupported button passed in."); + } + + XEvent event; + + Display *display = XOpenDisplay(0); + wxASSERT_MSG(display, "No display available!"); + + memset(&event, 0x00, sizeof(event)); + + if (isDown) + event.type = ButtonPress; + else + event.type = ButtonRelease; + + event.xbutton.button = xbutton; + event.xbutton.same_screen = True; + + XQueryPointer(display, RootWindow(display, DefaultScreen(display)), &event.xbutton.root, &event.xbutton.window, &event.xbutton.x_root, &event.xbutton.y_root, &event.xbutton.x, &event.xbutton.y, &event.xbutton.state); + event.xbutton.subwindow = event.xbutton.window; + + while (event.xbutton.subwindow) + { + event.xbutton.window = event.xbutton.subwindow; + XQueryPointer(display, event.xbutton.window, &event.xbutton.root, &event.xbutton.subwindow, &event.xbutton.x_root, &event.xbutton.y_root, &event.xbutton.x, &event.xbutton.y, &event.xbutton.state); + } + + XSendEvent(display, PointerWindow, True, 0xfff, &event); + XFlush(display); + XCloseDisplay(display); +} + +bool wxUIActionSimulator::MouseDown(int button) +{ + SendButtonEvent(button, true); + return true; +} + +bool wxUIActionSimulator::MouseMove(long x, long y) +{ + Display *display = XOpenDisplay(0); + wxASSERT_MSG(display, "No display available!"); + Window root = DefaultRootWindow(display); + XWarpPointer(display, None, root, 0, 0, 0, 0, x, y); + XFlush(display); + XCloseDisplay(display); + return true; +} + +bool wxUIActionSimulator::MouseUp(int button) +{ + SendButtonEvent(button, false); + return true; +} + +bool wxUIActionSimulator::Key(int keycode, bool isDown, bool WXUNUSED(shiftDown), bool WXUNUSED(cmdDown), bool WXUNUSED(altDown)) +{ + Display *display = XOpenDisplay(0); + wxASSERT_MSG(display, "No display available!"); + + XKeyEvent event; + int mask = 0xfff; + memset(&event, 0x00, sizeof(event)); + + if (isDown) { + event.type = KeyPress; + mask = KeyPressMask; + } + else { + event.type = KeyRelease; + mask = KeyReleaseMask; + } + event.same_screen = True; + + XQueryPointer(display, RootWindow(display, DefaultScreen(display)), &event.root, &event.window, &event.x_root, &event.y_root, &event.x, &event.y, &event.state); + event.subwindow = event.window; + + while (event.subwindow) + { + event.window = event.subwindow; + XQueryPointer(display, event.window, &event.root, &event.subwindow, &event.x_root, &event.y_root, &event.x, &event.y, &event.state); + } + + XSendEvent(display, PointerWindow, True, mask, (XEvent*) &event); + XFlush(display); + XCloseDisplay(display); + + return true; +} + -- 2.47.2