Merge wxUIActionSimulator fixes from SOC2010_GUI_TEST branch.

Correct a lot of problems with the initial implementation, notably make the
API consistent across all platforms, e.g. all keyboard-related methods now
take just a wxKeyCode.

Add some useful higher-level helpers such as Text() and MouseDragDrop().

Improve documentation.

wxUIActionSimulator now works under MSW, GTK and OS X and is enabled by
default.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@65385 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin 2010-08-22 22:15:42 +00:00
parent 6f07c007a5
commit 571d991bb3
22 changed files with 551 additions and 289 deletions

1
configure vendored
View File

@ -2980,7 +2980,6 @@ DEFAULT_wxUSE_LIBSDL=no
DEFAULT_wxUSE_ACCESSIBILITY=no DEFAULT_wxUSE_ACCESSIBILITY=no
DEFAULT_wxUSE_IPV6=no DEFAULT_wxUSE_IPV6=no
DEFAULT_wxUSE_GSTREAMER8=no DEFAULT_wxUSE_GSTREAMER8=no
DEFAULT_wxUSE_UIACTIONSIMULATOR=no
DEFAULT_wxUSE_UNICODE_UTF8=auto DEFAULT_wxUSE_UNICODE_UTF8=auto
DEFAULT_wxUSE_OPENGL=auto DEFAULT_wxUSE_OPENGL=auto

View File

@ -387,7 +387,6 @@ dnl features disabled by default
DEFAULT_wxUSE_ACCESSIBILITY=no DEFAULT_wxUSE_ACCESSIBILITY=no
DEFAULT_wxUSE_IPV6=no DEFAULT_wxUSE_IPV6=no
DEFAULT_wxUSE_GSTREAMER8=no DEFAULT_wxUSE_GSTREAMER8=no
DEFAULT_wxUSE_UIACTIONSIMULATOR=no
dnl automatic features dnl automatic features
DEFAULT_wxUSE_UNICODE_UTF8=auto DEFAULT_wxUSE_UNICODE_UTF8=auto

View File

@ -407,6 +407,7 @@ All (GUI):
- Added wxRichMessageDialog (Rickard Westerlund, GSoC 2010 project). - Added wxRichMessageDialog (Rickard Westerlund, GSoC 2010 project).
- Added wxCommandLinkButton (Rickard Westerlund, GSoC 2010 project). - Added wxCommandLinkButton (Rickard Westerlund, GSoC 2010 project).
- Added wxUIActionSimulator (Steven Lamerton, GSoC 2010 project).
- wxAUI: support auto-orientable toolbars (wsu). - wxAUI: support auto-orientable toolbars (wsu).
- Added wxDataViewCtrl::Set/GetCurrentItem(). - Added wxDataViewCtrl::Set/GetCurrentItem().
- wxHTML: render in RTL order inside RTL window (Richard Bullington-McGuire). - wxHTML: render in RTL order inside RTL window (Richard Bullington-McGuire).

View File

@ -131,6 +131,7 @@ TODO: Organize them in a more human-readable way.
@li @sample{toolbar} @li @sample{toolbar}
@li @sample{treectrl} @li @sample{treectrl}
@li @sample{typetest} @li @sample{typetest}
@li @sample{uiaction}
@li @sample{validate} @li @sample{validate}
@li @sample{vscroll} @li @sample{vscroll}
@li @sample{widgets} @li @sample{widgets}
@ -989,6 +990,17 @@ demonstrated here as well - try the corresponding menu entries.
@sampledir{typetest} @sampledir{typetest}
@section page_samples_uiaction wxUIActionSimulator Sample
@sampleabout{wxUIActionSimulator}
This sample shows some features of wxUIActionSimulator class. When a simulation
is ran using its menu items, you can see that the button is pressed
programmatically and the characters generated by the program appear in the text
control.
@sampledir{uiaction}
@section page_samples_validate Validator Sample @section page_samples_validate Validator Sample
@sampleabout{wxValidator} @sampleabout{wxValidator}

View File

@ -1246,9 +1246,7 @@
// Include mouse wheel support // Include mouse wheel support
// Compile wxUIActionSimulator class? // Compile wxUIActionSimulator class?
// #define wxUSE_UIACTIONSIMULATOR 1
// This is experimental code subject to change. It's not fully implemented yet.
#define wxUSE_UIACTIONSIMULATOR 0
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// wxDC classes for various output formats // wxDC classes for various output formats

View File

@ -1246,9 +1246,7 @@
// Include mouse wheel support // Include mouse wheel support
// Compile wxUIActionSimulator class? // Compile wxUIActionSimulator class?
// #define wxUSE_UIACTIONSIMULATOR 1
// This is experimental code subject to change. It's not fully implemented yet.
#define wxUSE_UIACTIONSIMULATOR 0
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// wxDC classes for various output formats // wxDC classes for various output formats

View File

@ -1246,9 +1246,7 @@
// Include mouse wheel support // Include mouse wheel support
// Compile wxUIActionSimulator class? // Compile wxUIActionSimulator class?
// #define wxUSE_UIACTIONSIMULATOR 1
// This is experimental code subject to change. It's not fully implemented yet.
#define wxUSE_UIACTIONSIMULATOR 0
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// wxDC classes for various output formats // wxDC classes for various output formats

View File

@ -1246,9 +1246,7 @@
// Include mouse wheel support // Include mouse wheel support
// Compile wxUIActionSimulator class? // Compile wxUIActionSimulator class?
// #define wxUSE_UIACTIONSIMULATOR 1
// This is experimental code subject to change. It's not fully implemented yet.
#define wxUSE_UIACTIONSIMULATOR 0
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// wxDC classes for various output formats // wxDC classes for various output formats

View File

@ -1247,9 +1247,7 @@
// Include mouse wheel support // Include mouse wheel support
// Compile wxUIActionSimulator class? // Compile wxUIActionSimulator class?
// #define wxUSE_UIACTIONSIMULATOR 1
// This is experimental code subject to change. It's not fully implemented yet.
#define wxUSE_UIACTIONSIMULATOR 0
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// wxDC classes for various output formats // wxDC classes for various output formats

View File

@ -1246,9 +1246,7 @@
// Include mouse wheel support // Include mouse wheel support
// Compile wxUIActionSimulator class? // Compile wxUIActionSimulator class?
// #define wxUSE_UIACTIONSIMULATOR 1
// This is experimental code subject to change. It's not fully implemented yet.
#define wxUSE_UIACTIONSIMULATOR 0
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// wxDC classes for various output formats // wxDC classes for various output formats

View File

@ -1242,9 +1242,7 @@
// Include mouse wheel support // Include mouse wheel support
// Compile wxUIActionSimulator class? // Compile wxUIActionSimulator class?
// #define wxUSE_UIACTIONSIMULATOR 1
// This is experimental code subject to change. It's not fully implemented yet.
#define wxUSE_UIACTIONSIMULATOR 0
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// wxDC classes for various output formats // wxDC classes for various output formats

View File

@ -1,11 +1,13 @@
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// Name: wx/uiaction.h // Name: wx/uiaction.h
// Purpose: wxUIActionSimulator interface // Purpose: wxUIActionSimulator interface
// Author: Kevin Ollivier // Author: Kevin Ollivier, Steven Lamerton, Vadim Zeitlin
// Modified by: // Modified by:
// Created: 2010-03-06 // Created: 2010-03-06
// RCS-ID: $Id: menu.cpp 54129 2008-06-11 19:30:52Z SC $ // RCS-ID: $Id: menu.cpp 54129 2008-06-11 19:30:52Z SC $
// Copyright: (c) Kevin Ollivier // Copyright: (c) Kevin Ollivier
// (c) 2010 Steven Lamerton
// (c) 2010 Vadim Zeitlin
// Licence: wxWindows licence // Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
@ -16,39 +18,64 @@
#if wxUSE_UIACTIONSIMULATOR #if wxUSE_UIACTIONSIMULATOR
#include "wx/event.h" #include "wx/mousestate.h" // for wxMOUSE_BTN_XXX constants
#include "wx/dynarray.h"
class WXDLLIMPEXP_CORE wxUIActionSimulator class WXDLLIMPEXP_CORE wxUIActionSimulator
{ {
public: public:
wxUIActionSimulator(); 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: // Default dtor, copy ctor and assignment operator are ok (even though the
// last two don't make much sense for this class).
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) // Mouse simulation
{ return Key(keycode, false, shiftDown, cmdDown, altDown); } // ----------------
bool Char(int keycode, bool shiftDown=false, bool cmdDown=false, bool altDown=false); // Low level methods
bool MouseMove(long x, long y);
bool MouseMove(const wxPoint& point) { return MouseMove(point.x, point.y); }
protected: bool MouseDown(int button = wxMOUSE_BTN_LEFT);
// Implementation-wise, since key events take more code to set up on GTK and Mac, it makes bool MouseUp(int button = wxMOUSE_BTN_LEFT);
// 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 // Higher level interface, use it if possible instead
// for pressed state, so I'm leaving this as an implementation detail. bool MouseClick(int button = wxMOUSE_BTN_LEFT);
bool Key(int keycode, bool isDown=true, bool shiftDown=false, bool cmdDown=false, bool altDown=false); bool MouseDblClick(int button = wxMOUSE_BTN_LEFT);
bool MouseDragDrop(long x1, long y1, long x2, long y2,
int button = wxMOUSE_BTN_LEFT);
// Keyboard simulation
// -------------------
// Low level methods for generating key presses and releases
bool KeyDown(int keycode, int modifiers = wxMOD_NONE)
{ return Key(keycode, modifiers, true); }
bool KeyUp(int keycode, int modifiers = wxMOD_NONE)
{ return Key(keycode, modifiers, false); }
// Higher level methods for generating both the key press and release for a
// single key or for all characters in the ASCII string "text" which can
// currently contain letters only (no digits, no punctuation).
bool Char(int keycode, int modifiers = wxMOD_NONE);
bool Text(const char *text);
private:
// This is the common part of Key{Down,Up}() methods: while we keep them
// separate at public API level for consistency with Mouse{Down,Up}(), at
// implementation level it makes more sense to have them in a single
// function.
//
// This is a simple wrapper verifying the input parameters validity around
// the platform-specific DoKey() method implemented in platform-specific
// files.
bool Key(int keycode, int modifiers, bool isDown);
bool DoKey(int keycode, int modifiers, bool isDown);
}; };
#endif // wxUSE_UIACTIONSIMULATOR #endif // wxUSE_UIACTIONSIMULATOR

View File

@ -1245,9 +1245,7 @@
// Include mouse wheel support // Include mouse wheel support
// Compile wxUIActionSimulator class? // Compile wxUIActionSimulator class?
// #define wxUSE_UIACTIONSIMULATOR 1
// This is experimental code subject to change. It's not fully implemented yet.
#define wxUSE_UIACTIONSIMULATOR 0
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// wxDC classes for various output formats // wxDC classes for various output formats

View File

@ -26,8 +26,12 @@
#if defined(__WXGTK__) #if defined(__WXGTK__)
typedef void WXDisplay; typedef void WXDisplay;
typedef void* WXWindow; typedef void* WXWindow;
typedef unsigned long WXKeySym;
#endif #endif
int wxCharCodeXToWX(WXKeySym keySym);
WXKeySym wxCharCodeWXToX(int id);
class wxIconBundle; class wxIconBundle;
void wxSetIconsX11( WXDisplay* display, WXWindow window, void wxSetIconsX11( WXDisplay* display, WXWindow window,

View File

@ -35,9 +35,6 @@ class WXDLLIMPEXP_FWD_CORE wxRegion;
// key events related functions // key events related functions
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
extern int wxCharCodeXToWX(KeySym keySym);
extern KeySym wxCharCodeWXToX(int id);
WXPixel wxGetBestMatchingPixel(Display *display, XColor *desiredColor, Colormap cmap); WXPixel wxGetBestMatchingPixel(Display *display, XColor *desiredColor, Colormap cmap);
Pixmap XCreateInsensitivePixmap( Display *display, Pixmap pixmap ); Pixmap XCreateInsensitivePixmap( Display *display, Pixmap pixmap );

View File

@ -12,31 +12,24 @@
wxUIActionSimulator is a class used to simulate user interface actions wxUIActionSimulator is a class used to simulate user interface actions
such as a mouse click or a key press. such as a mouse click or a key press.
@note that this class is currently experimental and disabled by default, Common usage for this class would be to provide playback and record (aka
you must set @c wxUSE_UIACTIONSIMULATOR to 1 in your setup.h file or use macro recording) functionality for users, or to drive unit tests by
configure @c --enable-uiactionsim option to enable it. simulating user sessions.
Common usages for this class would be to provide playback and record (aka macro recording) See the @ref page_samples_uiaction for an example of using this class.
functionality for users, or to drive unit tests by simulating user sessions.
See the uiaction sample for example usage of this class. @since 2.9.2
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} @library{wxcore}
*/ */
class wxUIActionSimulator class wxUIActionSimulator
{ {
public: public:
/** /**
Constructor. Default constructor.
*/ */
wxUIActionSimulator(); wxUIActionSimulator();
~wxUIActionSimulator();
/** /**
Move the mouse to the specified coordinates. Move the mouse to the specified coordinates.
@ -47,37 +40,49 @@ class wxUIActionSimulator
@param y @param y
y coordinate to move to, in screen coordinates. y coordinate to move to, in screen coordinates.
*/ */
bool MouseMove(long x, long y); bool MouseMove(long x, long y);
/**
Move the mouse to the specified coordinates.
@param point
Point to move to, in screen coordinates.
*/
bool MouseMove(const wxPoint& point);
/** /**
Press a mouse button. Press a mouse button.
@param button @param button
Button to press. Valid constants are wxMOUSE_BTN_LEFT, wxMOUSE_BTN_MIDDLE, and wxMOUSE_BTN_RIGHT. Button to press. Valid constants are @c wxMOUSE_BTN_LEFT,
@c wxMOUSE_BTN_MIDDLE, and @c wxMOUSE_BTN_RIGHT.
*/ */
bool MouseDown(int button = wxMOUSE_BTN_LEFT); bool MouseDown(int button = wxMOUSE_BTN_LEFT);
/** /**
Release a mouse button. Release a mouse button.
@param button @param button
Button to press. See wxUIActionSimulator::MouseDown for a list of valid constants. Button to press. See wxUIActionSimulator::MouseDown for a list of
valid constants.
*/ */
bool MouseUp(int button = wxMOUSE_BTN_LEFT); bool MouseUp(int button = wxMOUSE_BTN_LEFT);
/** /**
Click a mouse button. Click a mouse button.
@param button @param button
Button to press. See wxUIActionSimulator::MouseDown for a list of valid constants. Button to press. See wxUIActionSimulator::MouseDown for a list of
valid constants.
*/ */
bool MouseClick(int button = wxMOUSE_BTN_LEFT); bool MouseClick(int button = wxMOUSE_BTN_LEFT);
/** /**
Double-click a mouse button. Double-click a mouse button.
@param button @param button
Button to press. See wxUIActionSimulator::MouseDown for a list of valid constants. Button to press. See wxUIActionSimulator::MouseDown for a list of
valid constants.
*/ */
bool MouseDblClick(int button = wxMOUSE_BTN_LEFT); bool MouseDblClick(int button = wxMOUSE_BTN_LEFT);
/** /**
Perform a drag and drop operation. Perform a drag and drop operation.
@ -95,59 +100,60 @@ class wxUIActionSimulator
y destination coordinate, in screen coordinates. y destination coordinate, in screen coordinates.
@param button @param button
Button to press. See wxUIActionSimulator::MouseDown for a list of valid constants. 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); bool MouseDragDrop(long x1, long y1, long x2, long y2,
int button = wxMOUSE_BTN_LEFT);
/** /**
Press a key. Press a key.
If you are using modifiers then it needs to be paired with an identical
KeyUp or the modifiers will not be released (MSW and OSX).
@param keycode @param keycode
key to operate on, as an integer. Key to operate on, as an integer. It is interpreted as a wxKeyCode.
@param shiftDown @param modifiers
true if the shift key should be pressed, false otherwise. A combination of ::wxKeyModifier flags to be pressed with the given
keycode.
@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); bool KeyDown(int keycode, int modifiers = wxMOD_NONE);
/** /**
Release a key. Release a key.
@param keycode @param keycode
key to operate on, as an integer. Key to operate on, as an integer. It is interpreted as a wxKeyCode.
@param shiftDown @param modifiers
true if the shift key should be pressed, false otherwise. A combination of ::wxKeyModifier flags to be pressed with the given
keycode.
@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); bool KeyUp(int keycode, int modifiers = wxMOD_NONE);
/** /**
Press and release a key. Press and release a key.
@param keycode @param keycode
key to operate on, as an integer. Key to operate on, as an integer. It is interpreted as a wxKeyCode.
@param shiftDown @param modifiers
true if the shift key should be pressed, false otherwise. A combination of ::wxKeyModifier flags to be pressed with the given
keycode.
@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); bool Char(int keycode, int modifiers = wxMOD_NONE);
/**
Emulate typing in the keys representing the given string.
Currently only the ASCII letters (i.e. characters @c a-z and @c A-Z)
are supported.
@param text
The string to type.
*/
bool Text(const wxString& text);
}; };

View File

@ -5,7 +5,7 @@
// Modified by: // Modified by:
// Created: 04/01/98 // Created: 04/01/98
// RCS-ID: $Id$ // RCS-ID: $Id$
// Copyright: (c) Kevin Ollivier // Copyright: (c) Kevin Ollivier, Steven Lamerton
// Licence: wxWindows licence // Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
@ -16,10 +16,10 @@
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// headers // headers
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// For compilers that support precompilation, includes "wx/wx.h". // For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h" #include "wx/wxprec.h"
#ifdef __BORLANDC__ #ifdef __BORLANDC__
#pragma hdrstop #pragma hdrstop
#endif #endif
@ -52,8 +52,7 @@
enum enum
{ {
// menu items // menu items
TheButton = 100, RunSimulation = 1
RunSimulation
}; };
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -76,22 +75,21 @@ public:
// ctor(s) // ctor(s)
MyFrame(const wxString& title); MyFrame(const wxString& title);
void OnButtonPressed(wxCommandEvent&); void OnButtonPressed(wxCommandEvent& event);
void OnRunSimulation(wxCommandEvent&); void OnRunSimulation(wxCommandEvent& event);
void OnExit(wxCommandEvent& WXUNUSED(event)) { Close(); }
bool ButtonPressed() const { return m_buttonPressed; }
bool MenuSelected() const { return m_menuSelected; }
private: private:
bool m_buttonPressed; wxButton* m_button;
bool m_menuSelected; wxTextCtrl* m_text;
DECLARE_EVENT_TABLE() DECLARE_EVENT_TABLE()
}; };
BEGIN_EVENT_TABLE(MyFrame, wxFrame) BEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_BUTTON(TheButton, MyFrame::OnButtonPressed) EVT_BUTTON(wxID_ANY, MyFrame::OnButtonPressed)
EVT_MENU(RunSimulation, MyFrame::OnRunSimulation) EVT_MENU(RunSimulation, MyFrame::OnRunSimulation)
EVT_MENU(wxID_EXIT, MyFrame::OnExit)
END_EVENT_TABLE() END_EVENT_TABLE()
#endif // wxUSE_UIACTIONSIMULATOR #endif // wxUSE_UIACTIONSIMULATOR
@ -114,7 +112,7 @@ bool MyApp::OnInit()
#if wxUSE_UIACTIONSIMULATOR #if wxUSE_UIACTIONSIMULATOR
MyFrame *frame = new MyFrame("wxUIActionSimulator sample application"); MyFrame *frame = new MyFrame("wxUIActionSimulator sample application");
frame->Show(true); frame->Show(true);
return true; return true;
#else // !wxUSE_UIACTIONSIMULATOR #else // !wxUSE_UIACTIONSIMULATOR
wxLogError("wxUSE_UIACTIONSIMULATOR must be 1 for this sample"); wxLogError("wxUSE_UIACTIONSIMULATOR must be 1 for this sample");
@ -134,9 +132,6 @@ MyFrame::MyFrame(const wxString& title)
{ {
SetIcon(wxICON(sample)); SetIcon(wxICON(sample));
m_buttonPressed = false;
m_menuSelected = false;
#if wxUSE_MENUS #if wxUSE_MENUS
// create a menu bar // create a menu bar
wxMenu *fileMenu = new wxMenu; wxMenu *fileMenu = new wxMenu;
@ -152,30 +147,48 @@ MyFrame::MyFrame(const wxString& title)
SetMenuBar(menuBar); SetMenuBar(menuBar);
#endif // wxUSE_MENUS #endif // wxUSE_MENUS
wxButton* button = new wxButton(this, TheButton, "Button"); wxPanel *panel = new wxPanel(this);
button->SetName("TheButton");
wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
panel->SetSizer(sizer);
m_button = new wxButton(panel, wxID_ANY, "&Button");
sizer->Add(m_button, wxSizerFlags().Centre().Border());
m_text = new wxTextCtrl(panel, wxID_ANY, "",
wxDefaultPosition, wxDefaultSize,
wxTE_MULTILINE);
sizer->Add(m_text, wxSizerFlags(1).Expand().Border());
} }
// event handlers // event handlers
void MyFrame::OnRunSimulation(wxCommandEvent&) void MyFrame::OnRunSimulation(wxCommandEvent& WXUNUSED(event))
{ {
wxUIActionSimulator sim; wxUIActionSimulator sim;
wxWindow* button = FindWindow(wxString("TheButton"));
wxPoint globalPoint = button->ClientToScreen(wxPoint(20, 10)); // Add some extra distance to take account of window decorations
sim.MouseMove(globalPoint.x, globalPoint.y); sim.MouseMove(m_button->GetScreenPosition() + wxPoint(10, 10));
sim.MouseClick(wxMOUSE_BTN_LEFT); sim.MouseClick(wxMOUSE_BTN_LEFT);
// Process the resulting button event
wxYield(); wxYield();
if (ButtonPressed()) m_text->SetFocus();
wxMessageBox("Button automagically pressed!"); sim.Char('A');
sim.Char('A', wxMOD_SHIFT);
sim.Char(WXK_RETURN);
sim.Char('Z');
sim.Char('Z', wxMOD_SHIFT);
sim.Char(WXK_RETURN);
sim.Text("aAbBcC");
sim.Char(WXK_RETURN);
} }
void MyFrame::OnButtonPressed(wxCommandEvent&) void MyFrame::OnButtonPressed(wxCommandEvent& WXUNUSED(event))
{ {
m_buttonPressed = true; m_text->AppendText("Button pressed.\n");
} }
#endif // wxUSE_UIACTIONSIMULATOR #endif // wxUSE_UIACTIONSIMULATOR

View File

@ -1,11 +1,13 @@
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// Name: src/common/uiactioncmn.cpp // Name: src/common/uiactioncmn.cpp
// Purpose: wxUIActionSimulator common implementation // Purpose: wxUIActionSimulator common implementation
// Author: Kevin Ollivier // Author: Kevin Ollivier, Steven Lamerton, Vadim Zeitlin
// Modified by: // Modified by:
// Created: 2010-03-06 // Created: 2010-03-06
// RCS-ID: $Id: menu.cpp 54129 2008-06-11 19:30:52Z SC $ // RCS-ID: $Id: menu.cpp 54129 2008-06-11 19:30:52Z SC $
// Copyright: (c) Kevin Ollivier // Copyright: (c) Kevin Ollivier
// (c) 2010 Steven Lamerton
// (c) 2010 Vadim Zeitlin
// Licence: wxWindows licence // Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
@ -15,15 +17,6 @@
#include "wx/uiaction.h" #include "wx/uiaction.h"
wxUIActionSimulator::wxUIActionSimulator()
{
}
wxUIActionSimulator::~wxUIActionSimulator()
{
}
bool wxUIActionSimulator::MouseClick(int button) bool wxUIActionSimulator::MouseClick(int button)
{ {
MouseDown(button); MouseDown(button);
@ -42,7 +35,9 @@ bool wxUIActionSimulator::MouseDblClick(int button)
return true; return true;
} }
bool wxUIActionSimulator::MouseDragDrop(long x1, long y1, long x2, long y2, int button) bool
wxUIActionSimulator::MouseDragDrop(long x1, long y1, long x2, long y2,
int button)
{ {
MouseMove(x1, y1); MouseMove(x1, y1);
MouseDown(button); MouseDown(button);
@ -52,10 +47,40 @@ bool wxUIActionSimulator::MouseDragDrop(long x1, long y1, long x2, long y2, int
return true; return true;
} }
bool wxUIActionSimulator::Char(int keycode, bool shiftDown, bool cmdDown, bool altDown) bool
wxUIActionSimulator::Key(int keycode, int modifiers, bool isDown)
{ {
Key(keycode, false, shiftDown, cmdDown, altDown); wxASSERT_MSG( !(modifiers & wxMOD_CONTROL),
Key(keycode, true, shiftDown, cmdDown, altDown); "wxMOD_CONTROL is not implemented, use wxMOD_CMD instead" );
wxASSERT_MSG( (modifiers & wxMOD_ALTGR) != wxMOD_ALTGR,
"wxMOD_ALTGR is not implemented" );
wxASSERT_MSG( !(modifiers & wxMOD_META ),
"wxMOD_META is not implemented" );
wxASSERT_MSG( !(modifiers & wxMOD_WIN ),
"wxMOD_WIN is not implemented" );
return DoKey(keycode, modifiers, isDown);
}
bool wxUIActionSimulator::Char(int keycode, int modifiers)
{
Key(keycode, modifiers, true);
Key(keycode, modifiers, false);
return true;
}
bool wxUIActionSimulator::Text(const char *s)
{
while ( *s != '\0' )
{
const char ch = *s++;
wxASSERT_MSG( ch, "Only letters are allowed" );
if ( !Char(ch, isupper(ch) ? wxMOD_SHIFT : 0) )
return false;
}
return true; return true;
} }

View File

@ -1,11 +1,13 @@
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// Name: src/msw/uiaction.cpp // Name: src/msw/uiaction.cpp
// Purpose: wxUIActionSimulator implementation // Purpose: wxUIActionSimulator implementation
// Author: Kevin Ollivier // Author: Kevin Ollivier, Steven Lamerton, Vadim Zeitlin
// Modified by: // Modified by:
// Created: 2010-03-06 // Created: 2010-03-06
// RCS-ID: $Id: menu.cpp 54129 2008-06-11 19:30:52Z SC $ // RCS-ID: $Id: menu.cpp 54129 2008-06-11 19:30:52Z SC $
// Copyright: (c) Kevin Ollivier // Copyright: (c) Kevin Ollivier
// (c) 2010 Steven Lamerton
// (c) 2010 Vadim Zeitlin
// Licence: wxWindows licence // Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
@ -17,32 +19,35 @@
#include "wx/msw/wrapwin.h" #include "wx/msw/wrapwin.h"
namespace
{
DWORD EventTypeForMouseButton(int button, bool isDown) DWORD EventTypeForMouseButton(int button, bool isDown)
{ {
switch (button) switch (button)
{ {
case wxMOUSE_BTN_LEFT: case wxMOUSE_BTN_LEFT:
if (isDown) return isDown ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_LEFTUP;
return MOUSEEVENTF_LEFTDOWN;
else
return MOUSEEVENTF_LEFTUP;
case wxMOUSE_BTN_RIGHT: case wxMOUSE_BTN_RIGHT:
if (isDown) return isDown ? MOUSEEVENTF_RIGHTDOWN : MOUSEEVENTF_RIGHTUP;
return MOUSEEVENTF_RIGHTDOWN;
else
return MOUSEEVENTF_RIGHTUP;
case wxMOUSE_BTN_MIDDLE: case wxMOUSE_BTN_MIDDLE:
if (isDown) return isDown ? MOUSEEVENTF_MIDDLEDOWN : MOUSEEVENTF_MIDDLEUP;
return MOUSEEVENTF_MIDDLEDOWN;
else
return MOUSEEVENTF_MIDDLEUP;
default: default:
wxFAIL_MSG("Unsupported button passed in."); wxFAIL_MSG("Unsupported button passed in.");
return -1; return (DWORD)-1;
} }
} }
void DoSimulateKbdEvent(DWORD vk, bool isDown)
{
keybd_event(vk, 0, isDown ? 0 : KEYEVENTF_KEYUP, 0);
}
} // anonymous namespace
bool wxUIActionSimulator::MouseDown(int button) bool wxUIActionSimulator::MouseDown(int button)
{ {
POINT p; POINT p;
@ -53,7 +58,13 @@ bool wxUIActionSimulator::MouseDown(int button)
bool wxUIActionSimulator::MouseMove(long x, long y) bool wxUIActionSimulator::MouseMove(long x, long y)
{ {
mouse_event(MOUSEEVENTF_MOVE, x, y, 0, 0); // Because MOUSEEVENTF_ABSOLUTE takes measurements scaled between 0 & 65535
// we need to scale our input too
int displayx, displayy, scaledx, scaledy;
wxDisplaySize(&displayx, &displayy);
scaledx = ((float)x / displayx) * 65535;
scaledy = ((float)y / displayy) * 65535;
mouse_event(MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE, scaledx, scaledy, 0, 0);
return true; return true;
} }
@ -65,12 +76,31 @@ bool wxUIActionSimulator::MouseUp(int button)
return true; return true;
} }
bool wxUIActionSimulator::Key(int keycode, bool isDown, bool shiftDown, bool cmdDown, bool altDown) bool wxUIActionSimulator::DoKey(int keycode, int modifiers, bool isDown)
{ {
DWORD flags = 0; if (isDown)
{
if (modifiers & wxMOD_SHIFT)
DoSimulateKbdEvent(VK_SHIFT, true);
if (modifiers & wxMOD_ALT)
DoSimulateKbdEvent(VK_MENU, true);
if (modifiers & wxMOD_CMD)
DoSimulateKbdEvent(VK_CONTROL, true);
}
DWORD vkkeycode = wxCharCodeWXToMSW(keycode);
keybd_event(vkkeycode, 0, isDown ? 0 : KEYEVENTF_KEYUP, 0);
if (!isDown) if (!isDown)
flags = KEYEVENTF_KEYUP; {
keybd_event(keycode, 0, flags, 0); if (modifiers & wxMOD_SHIFT)
DoSimulateKbdEvent(VK_SHIFT, false);
if (modifiers & wxMOD_ALT)
DoSimulateKbdEvent(VK_MENU, false);
if (modifiers & wxMOD_CMD)
DoSimulateKbdEvent(VK_CONTROL, false);
}
return true; return true;
} }

View File

@ -1,11 +1,13 @@
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// Name: src/osx/uiaction_osx.cpp // Name: src/osx/uiaction_osx.cpp
// Purpose: wxUIActionSimulator implementation // Purpose: wxUIActionSimulator implementation
// Author: Kevin Ollivier // Author: Kevin Ollivier, Steven Lamerton, Vadim Zeitlin
// Modified by: // Modified by:
// Created: 2010-03-06 // Created: 2010-03-06
// RCS-ID: $Id: menu.cpp 54129 2008-06-11 19:30:52Z SC $ // RCS-ID: $Id: menu.cpp 54129 2008-06-11 19:30:52Z SC $
// Copyright: (c) Kevin Ollivier // Copyright: (c) Kevin Ollivier
// (c) 2010 Steven Lamerton
// (c) 2010 Vadim Zeitlin
// Licence: wxWindows licence // Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
@ -15,61 +17,189 @@
#include "wx/uiaction.h" #include "wx/uiaction.h"
#include <ApplicationServices/ApplicationServices.h> #include "wx/log.h"
#include "wx/osx/private.h"
#include "wx/osx/core/cfref.h"
namespace
{
CGEventTapLocation tap = kCGSessionEventTap; CGEventTapLocation tap = kCGSessionEventTap;
CGEventType CGEventTypeForMouseButton(int button, bool isDown) CGEventType CGEventTypeForMouseButton(int button, bool isDown)
{ {
switch (button) switch ( button )
{ {
case wxMOUSE_BTN_LEFT: case wxMOUSE_BTN_LEFT:
if (isDown) return isDown ? kCGEventLeftMouseDown : kCGEventLeftMouseUp;
return kCGEventLeftMouseDown;
else
return kCGEventLeftMouseUp;
case wxMOUSE_BTN_RIGHT: case wxMOUSE_BTN_RIGHT:
if (isDown) return isDown ? kCGEventRightMouseDown : kCGEventRightMouseUp;
return kCGEventRightMouseDown;
else
return kCGEventRightMouseUp;
// Apparently all other buttons use the constant OtherMouseDown
// All the other buttons use the constant OtherMouseDown but we still
// want to check for invalid parameters so assert first
default: default:
if (isDown) wxFAIL_MSG("Unsupported button passed in.");
return kCGEventOtherMouseDown; // fall back to the only known remaining case
else
return kCGEventOtherMouseUp; case wxMOUSE_BTN_MIDDLE:
return isDown ? kCGEventOtherMouseDown : kCGEventOtherMouseUp;
} }
} }
void SendCharCode(CGCharCode keycode, bool isDown) CGPoint GetMousePosition()
{ {
CGEventRef event = CGEventCreateKeyboardEvent(NULL, keycode, isDown); int x, y;
if (event) wxGetMousePosition(&x, &y);
{
CGEventPost(kCGHIDEventTap, event); CGPoint pos;
} pos.x = x;
CFRelease(event); pos.y = y;
return pos;
} }
bool SendCharCode(CGKeyCode keycode, bool isDown)
{
wxCFRef<CGEventRef>
event(CGEventCreateKeyboardEvent(NULL, keycode, isDown));
if ( !event )
return false;
CGEventPost(kCGHIDEventTap, event);
return true;
}
CGKeyCode wxCharCodeWXToOSX(wxKeyCode code)
{
CGKeyCode keycode;
switch (code)
{
case 'a': case 'A': keycode = kVK_ANSI_A; break;
case 'b': case 'B': keycode = kVK_ANSI_B; break;
case 'c': case 'C': keycode = kVK_ANSI_C; break;
case 'd': case 'D': keycode = kVK_ANSI_D; break;
case 'e': case 'E': keycode = kVK_ANSI_E; break;
case 'f': case 'F': keycode = kVK_ANSI_F; break;
case 'g': case 'G': keycode = kVK_ANSI_G; break;
case 'h': case 'H': keycode = kVK_ANSI_H; break;
case 'i': case 'I': keycode = kVK_ANSI_I; break;
case 'j': case 'J': keycode = kVK_ANSI_J; break;
case 'k': case 'K': keycode = kVK_ANSI_K; break;
case 'l': case 'L': keycode = kVK_ANSI_L; break;
case 'm': case 'M': keycode = kVK_ANSI_M; break;
case 'n': case 'N': keycode = kVK_ANSI_N; break;
case 'o': case 'O': keycode = kVK_ANSI_O; break;
case 'p': case 'P': keycode = kVK_ANSI_P; break;
case 'q': case 'Q': keycode = kVK_ANSI_Q; break;
case 'r': case 'R': keycode = kVK_ANSI_R; break;
case 's': case 'S': keycode = kVK_ANSI_S; break;
case 't': case 'T': keycode = kVK_ANSI_T; break;
case 'u': case 'U': keycode = kVK_ANSI_U; break;
case 'v': case 'V': keycode = kVK_ANSI_V; break;
case 'w': case 'W': keycode = kVK_ANSI_W; break;
case 'x': case 'X': keycode = kVK_ANSI_X; break;
case 'y': case 'Y': keycode = kVK_ANSI_Y; break;
case 'z': case 'Z': keycode = kVK_ANSI_Z; break;
case '0': keycode = kVK_ANSI_0; break;
case '1': keycode = kVK_ANSI_1; break;
case '2': keycode = kVK_ANSI_2; break;
case '3': keycode = kVK_ANSI_3; break;
case '4': keycode = kVK_ANSI_4; break;
case '5': keycode = kVK_ANSI_5; break;
case '6': keycode = kVK_ANSI_6; break;
case '7': keycode = kVK_ANSI_7; break;
case '8': keycode = kVK_ANSI_8; break;
case '9': keycode = kVK_ANSI_9; break;
case WXK_BACK: keycode = kVK_Delete; break;
case WXK_TAB: keycode = kVK_Tab; break;
case WXK_RETURN: keycode = kVK_Return; break;
case WXK_ESCAPE: keycode = kVK_Escape; break;
case WXK_SPACE: keycode = kVK_Space; break;
case WXK_DELETE: keycode = kVK_Delete; break;
case WXK_SHIFT: keycode = kVK_Shift; break;
case WXK_ALT: keycode = kVK_Option; break;
case WXK_CONTROL: keycode = kVK_Control; break;
case WXK_COMMAND: keycode = kVK_Command; break;
case WXK_CAPITAL: keycode = kVK_CapsLock; break;
case WXK_END: keycode = kVK_End; break;
case WXK_HOME: keycode = kVK_Home; break;
case WXK_LEFT: keycode = kVK_LeftArrow; break;
case WXK_UP: keycode = kVK_UpArrow; break;
case WXK_RIGHT: keycode = kVK_RightArrow; break;
case WXK_DOWN: keycode = kVK_DownArrow; break;
case WXK_HELP: keycode = kVK_Help; break;
case WXK_NUMPAD0: keycode = kVK_ANSI_Keypad0; break;
case WXK_NUMPAD1: keycode = kVK_ANSI_Keypad1; break;
case WXK_NUMPAD2: keycode = kVK_ANSI_Keypad2; break;
case WXK_NUMPAD3: keycode = kVK_ANSI_Keypad3; break;
case WXK_NUMPAD4: keycode = kVK_ANSI_Keypad4; break;
case WXK_NUMPAD5: keycode = kVK_ANSI_Keypad5; break;
case WXK_NUMPAD6: keycode = kVK_ANSI_Keypad6; break;
case WXK_NUMPAD7: keycode = kVK_ANSI_Keypad7; break;
case WXK_NUMPAD8: keycode = kVK_ANSI_Keypad8; break;
case WXK_NUMPAD9: keycode = kVK_ANSI_Keypad9; break;
case WXK_F1: keycode = kVK_F1; break;
case WXK_F2: keycode = kVK_F2; break;
case WXK_F3: keycode = kVK_F3; break;
case WXK_F4: keycode = kVK_F4; break;
case WXK_F5: keycode = kVK_F5; break;
case WXK_F6: keycode = kVK_F6; break;
case WXK_F7: keycode = kVK_F7; break;
case WXK_F8: keycode = kVK_F8; break;
case WXK_F9: keycode = kVK_F9; break;
case WXK_F10: keycode = kVK_F10; break;
case WXK_F11: keycode = kVK_F11; break;
case WXK_F12: keycode = kVK_F12; break;
case WXK_F13: keycode = kVK_F13; break;
case WXK_F14: keycode = kVK_F14; break;
case WXK_F15: keycode = kVK_F15; break;
case WXK_F16: keycode = kVK_F16; break;
case WXK_F17: keycode = kVK_F17; break;
case WXK_F18: keycode = kVK_F18; break;
case WXK_F19: keycode = kVK_F19; break;
case WXK_F20: keycode = kVK_F20; break;
case WXK_PAGEUP: keycode = kVK_PageUp; break;
case WXK_PAGEDOWN: keycode = kVK_PageDown; break;
case WXK_NUMPAD_DELETE: keycode = kVK_ANSI_KeypadClear; break;
case WXK_NUMPAD_EQUAL: keycode = kVK_ANSI_KeypadEquals; break;
case WXK_NUMPAD_MULTIPLY: keycode = kVK_ANSI_KeypadMultiply; break;
case WXK_NUMPAD_ADD: keycode = kVK_ANSI_KeypadPlus; break;
case WXK_NUMPAD_SUBTRACT: keycode = kVK_ANSI_KeypadMinus; break;
case WXK_NUMPAD_DECIMAL: keycode = kVK_ANSI_KeypadDecimal; break;
case WXK_NUMPAD_DIVIDE: keycode = kVK_ANSI_KeypadDivide; break;
default: wxLogDebug( "Unrecognised keycode %d", code );
}
return keycode;
}
} // anonymous namespace
bool wxUIActionSimulator::MouseDown(int button) bool wxUIActionSimulator::MouseDown(int button)
{ {
CGPoint pos;
int x, y;
wxGetMousePosition(&x, &y);
pos.x = x;
pos.y = y;
CGEventType type = CGEventTypeForMouseButton(button, true); CGEventType type = CGEventTypeForMouseButton(button, true);
CGEventRef event = CGEventCreateMouseEvent(NULL, type, pos, button); wxCFRef<CGEventRef> event(
CGEventSetType(event, type); CGEventCreateMouseEvent(NULL, type, GetMousePosition(), button));
if ( !event )
return false;
CGEventSetType(event, type);
CGEventPost(tap, event);
if (event)
{
CGEventPost(tap, event);
}
CFRelease(event);
return true; return true;
} }
@ -78,56 +208,60 @@ bool wxUIActionSimulator::MouseMove(long x, long y)
CGPoint pos; CGPoint pos;
pos.x = x; pos.x = x;
pos.y = y; pos.y = y;
CGEventType type = kCGEventMouseMoved;
CGEventRef event = CGEventCreateMouseEvent(NULL, type, pos, kCGMouseButtonLeft);
CGEventSetType(event, type);
if (event) CGEventType type = kCGEventMouseMoved;
{ wxCFRef<CGEventRef> event(
CGEventPost(tap, event); CGEventCreateMouseEvent(NULL, type, pos, kCGMouseButtonLeft));
}
CFRelease(event); if ( !event )
return false;
CGEventSetType(event, type);
CGEventPost(tap, event);
return true; return true;
} }
bool wxUIActionSimulator::MouseUp(int button) bool wxUIActionSimulator::MouseUp(int button)
{ {
CGPoint pos;
int x, y;
wxGetMousePosition(&x, &y);
pos.x = x;
pos.y = y;
CGEventType type = CGEventTypeForMouseButton(button, false); CGEventType type = CGEventTypeForMouseButton(button, false);
CGEventRef event = CGEventCreateMouseEvent(NULL, type, pos, button); wxCFRef<CGEventRef> event(
CGEventSetType(event, type); CGEventCreateMouseEvent(NULL, type, GetMousePosition(), button));
if (event) if ( !event )
{ return false;
CGEventPost(tap, event);
} CGEventSetType(event, type);
CFRelease(event); CGEventPost(tap, event);
return true; return true;
} }
bool wxUIActionSimulator::Key(int keycode, bool isDown, bool shiftDown, bool cmdDown, bool altDown) bool wxUIActionSimulator::DoKey(int keycode, int modifiers, bool isDown)
{ {
if (shiftDown) if (isDown)
SendCharCode((CGCharCode)56, true); {
if (altDown) if (modifiers & wxMOD_SHIFT)
SendCharCode((CGCharCode)58, true); SendCharCode(kVK_Shift, true);
if (cmdDown) if (modifiers & wxMOD_ALT)
SendCharCode((CGCharCode)55, true); SendCharCode(kVK_Option, true);
if (modifiers & wxMOD_CMD)
SendCharCode(kVK_Command, true);
}
SendCharCode((CGCharCode)keycode, isDown); CGKeyCode cgcode = wxCharCodeWXToOSX((wxKeyCode)keycode);
if ( !SendCharCode(cgcode, isDown) )
return false;
if (shiftDown) if(!isDown)
SendCharCode((CGCharCode)56, false); {
if (altDown) if (modifiers & wxMOD_SHIFT)
SendCharCode((CGCharCode)58, false); SendCharCode(kVK_Shift, false);
if (cmdDown) if (modifiers & wxMOD_ALT)
SendCharCode((CGCharCode)55, false); SendCharCode(kVK_Option, false);
if (modifiers & wxMOD_CMD)
SendCharCode(kVK_Command, false);
}
return true; return true;
} }

View File

@ -1,11 +1,13 @@
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// Name: src/unix/uiactionx11.cpp // Name: src/unix/uiactionx11.cpp
// Purpose: wxUIActionSimulator implementation // Purpose: wxUIActionSimulator implementation
// Author: Kevin Ollivier // Author: Kevin Ollivier, Steven Lamerton, Vadim Zeitlin
// Modified by: // Modified by:
// Created: 2010-03-06 // Created: 2010-03-06
// RCS-ID: $Id: menu.cpp 54129 2008-06-11 19:30:52Z SC $ // RCS-ID: $Id: menu.cpp 54129 2008-06-11 19:30:52Z SC $
// Copyright: (c) Kevin Ollivier // Copyright: (c) Kevin Ollivier
// (c) 2010 Steven Lamerton
// (c) 2010 Vadim Zeitlin
// Licence: wxWindows licence // Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
@ -15,57 +17,62 @@
#include "wx/uiaction.h" #include "wx/uiaction.h"
#include <X11/Xlib.h>
#include <X11/Xutil.h> #include <X11/Xutil.h>
#include <X11/extensions/XTest.h>
#include "wx/unix/utilsx11.h"
namespace
{
void SendButtonEvent(int button, bool isDown) void SendButtonEvent(int button, bool isDown)
{ {
int xbutton = 0; int xbutton;
switch (button) switch (button)
{ {
case wxMOUSE_BTN_LEFT: case wxMOUSE_BTN_LEFT:
xbutton = 1; xbutton = 1;
break; break;
case wxMOUSE_BTN_RIGHT: case wxMOUSE_BTN_MIDDLE:
xbutton = 2; xbutton = 2;
break; break;
case wxMOUSE_BTN_MIDDLE: case wxMOUSE_BTN_RIGHT:
xbutton = 3; xbutton = 3;
break; break;
default: default:
wxFAIL_MSG("Unsupported button passed in."); wxFAIL_MSG("Unsupported button passed in.");
return;
} }
wxX11Display display;
wxCHECK_RET(display, "No display available!");
XEvent event; XEvent event;
Display *display = XOpenDisplay(0);
wxASSERT_MSG(display, "No display available!");
memset(&event, 0x00, sizeof(event)); memset(&event, 0x00, sizeof(event));
if (isDown) event.type = isDown ? ButtonPress : ButtonRelease;
event.type = ButtonPress;
else
event.type = ButtonRelease;
event.xbutton.button = xbutton; event.xbutton.button = xbutton;
event.xbutton.same_screen = True; 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); XQueryPointer(display, display.DefaultRoot(),
&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; event.xbutton.subwindow = event.xbutton.window;
while (event.xbutton.subwindow) while (event.xbutton.subwindow)
{ {
event.xbutton.window = 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); 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); XSendEvent(display, PointerWindow, True, 0xfff, &event);
XFlush(display);
XCloseDisplay(display);
} }
} // anonymous namespace
bool wxUIActionSimulator::MouseDown(int button) bool wxUIActionSimulator::MouseDown(int button)
{ {
SendButtonEvent(button, true); SendButtonEvent(button, true);
@ -74,12 +81,12 @@ bool wxUIActionSimulator::MouseDown(int button)
bool wxUIActionSimulator::MouseMove(long x, long y) bool wxUIActionSimulator::MouseMove(long x, long y)
{ {
Display *display = XOpenDisplay(0); wxX11Display display;
wxASSERT_MSG(display, "No display available!"); wxASSERT_MSG(display, "No display available!");
Window root = DefaultRootWindow(display);
Window root = display.DefaultRoot();
XWarpPointer(display, None, root, 0, 0, 0, 0, x, y); XWarpPointer(display, None, root, 0, 0, 0, 0, x, y);
XFlush(display);
XCloseDisplay(display);
return true; return true;
} }
@ -89,37 +96,61 @@ bool wxUIActionSimulator::MouseUp(int button)
return true; return true;
} }
bool wxUIActionSimulator::Key(int keycode, bool isDown, bool WXUNUSED(shiftDown), bool WXUNUSED(cmdDown), bool WXUNUSED(altDown)) bool wxUIActionSimulator::DoKey(int keycode, int modifiers, bool isDown)
{ {
Display *display = XOpenDisplay(0); wxX11Display display;
wxASSERT_MSG(display, "No display available!"); wxCHECK_MSG(display, false, "No display available!");
XKeyEvent event; int mask, type;
int mask = 0xfff;
memset(&event, 0x00, sizeof(event));
if (isDown) { if ( isDown )
event.type = KeyPress; {
type = KeyPress;
mask = KeyPressMask; mask = KeyPressMask;
} }
else { else
event.type = KeyRelease; {
type = KeyRelease;
mask = KeyReleaseMask; mask = KeyReleaseMask;
} }
WXKeySym xkeysym = wxCharCodeWXToX(keycode);
KeyCode xkeycode = XKeysymToKeycode(display, xkeysym);
if ( xkeycode == NoSymbol )
return false;
Window focus;
int revert;
XGetInputFocus(display, &focus, &revert);
if (focus == None)
return false;
int mod = 0;
if (modifiers & wxMOD_SHIFT)
mod |= ShiftMask;
//Mod1 is alt in the vast majority of cases
if (modifiers & wxMOD_ALT)
mod |= Mod1Mask;
if (modifiers & wxMOD_CMD)
mod |= ControlMask;
XKeyEvent event;
event.display = display;
event.window = focus;
event.root = DefaultRootWindow(event.display);
event.subwindow = None;
event.time = CurrentTime;
event.x = 1;
event.y = 1;
event.x_root = 1;
event.y_root = 1;
event.same_screen = True; event.same_screen = True;
event.type = type;
event.state = mod;
event.keycode = xkeycode;
XQueryPointer(display, RootWindow(display, DefaultScreen(display)), &event.root, &event.window, &event.x_root, &event.y_root, &event.x, &event.y, &event.state); XSendEvent(event.display, event.window, True, mask, (XEvent*) &event);
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; return true;
} }

View File

@ -537,7 +537,7 @@ void wxSetFullScreenStateX11(WXDisplay* display, WXWindow rootWindow,
// FIXME what about tables?? // FIXME what about tables??
int wxCharCodeXToWX(KeySym keySym) int wxCharCodeXToWX(WXKeySym keySym)
{ {
int id; int id;
switch (keySym) switch (keySym)
@ -717,9 +717,9 @@ int wxCharCodeXToWX(KeySym keySym)
return id; return id;
} }
KeySym wxCharCodeWXToX(int id) WXKeySym wxCharCodeWXToX(int id)
{ {
KeySym keySym; WXKeySym keySym;
switch (id) switch (id)
{ {