]> git.saurik.com Git - wxWidgets.git/commitdiff
Adding wxUIActionSimulator, a class for programmatically controlling the mouse and...
authorKevin Ollivier <kevino@theolliviers.com>
Sat, 6 Mar 2010 20:09:23 +0000 (20:09 +0000)
committerKevin Ollivier <kevino@theolliviers.com>
Sat, 6 Mar 2010 20:09:23 +0000 (20:09 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@63644 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

build/bakefiles/files.bkl
include/wx/uiaction.h [new file with mode: 0644]
interface/wx/uiaction.h [new file with mode: 0644]
samples/samples.bkl
samples/uiaction/uiaction.bkl [new file with mode: 0644]
samples/uiaction/uiaction.cpp [new file with mode: 0644]
src/common/uiactioncmn.cpp [new file with mode: 0644]
src/msw/uiaction.cpp [new file with mode: 0644]
src/osx/uiaction_osx.cpp [new file with mode: 0644]
src/unix/uiactionx11.cpp [new file with mode: 0644]

index 9b26b772bd0632bb38363abb6dd27403543a4953..2605b2baf53853f6aedd2592a379230d2e8a19a5 100644 (file)
@@ -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
 </set>
 <set var="XWIN_LOWLEVEL_HDR" hints="files">
     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
 </set>
 <set var="MSW_HDR" hints="files">
     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
     <!-- wxWebKit files -->
     src/html/htmlctrl/webkit/webkit.mm
     <!-- Native color/font dialogs -->
diff --git a/include/wx/uiaction.h b/include/wx/uiaction.h
new file mode 100644 (file)
index 0000000..ebce484
--- /dev/null
@@ -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 <wx/defs.h>
+#include <wx/event.h>
+#include <wx/dynarray.h>
+
+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 (file)
index 0000000..dbb83cc
--- /dev/null
@@ -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
index a142ff119b68645da3d851529f8a1b196f262018..5073244c206199e7055ea096ee415b5c6e0ded59 100644 (file)
@@ -84,6 +84,7 @@
     <subproject id="toolbar" template="sub"/>
     <subproject id="treectrl" template="sub"/>
     <subproject id="typetest" template="sub"/>
+    <subproject id="uiaction" template="sub"/>
     <subproject id="validate" template="sub"/>
     <subproject id="vscroll" template="sub"/>
     <subproject id="widgets" template="sub"/>
diff --git a/samples/uiaction/uiaction.bkl b/samples/uiaction/uiaction.bkl
new file mode 100644 (file)
index 0000000..872f9df
--- /dev/null
@@ -0,0 +1,15 @@
+<?xml version="1.0" ?>
+<!-- $Id$ -->
+
+<makefile>
+
+    <include file="../../build/bakefiles/common_samples.bkl"/>
+
+    <exe id="uiaction" template="wx_sample" template_append="wx_append">
+        <sources>uiaction.cpp</sources>
+        <wx-lib>core</wx-lib>
+        <wx-lib>base</wx-lib>
+        <uid type="creatorid">wx06</uid>
+    </exe>
+
+</makefile>
diff --git a/samples/uiaction/uiaction.cpp b/samples/uiaction/uiaction.cpp
new file mode 100644 (file)
index 0000000..a9eeb43
--- /dev/null
@@ -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 (file)
index 0000000..52747d1
--- /dev/null
@@ -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 (file)
index 0000000..6bbbf1a
--- /dev/null
@@ -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 <windows.h>
+
+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 (file)
index 0000000..bd4afa1
--- /dev/null
@@ -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 <wx/defs.h>
+#include <wx/uiaction.h>
+
+#include <ApplicationServices/ApplicationServices.h>
+
+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 (file)
index 0000000..05497ef
--- /dev/null
@@ -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 <wx/defs.h>
+#include <wx/uiaction.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/extensions/XTest.h>
+
+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;
+}
+