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_IPV6=no
DEFAULT_wxUSE_GSTREAMER8=no
DEFAULT_wxUSE_UIACTIONSIMULATOR=no
DEFAULT_wxUSE_UNICODE_UTF8=auto
DEFAULT_wxUSE_OPENGL=auto

View File

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

View File

@ -407,6 +407,7 @@ All (GUI):
- Added wxRichMessageDialog (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).
- Added wxDataViewCtrl::Set/GetCurrentItem().
- 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{treectrl}
@li @sample{typetest}
@li @sample{uiaction}
@li @sample{validate}
@li @sample{vscroll}
@li @sample{widgets}
@ -989,6 +990,17 @@ demonstrated here as well - try the corresponding menu entries.
@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
@sampleabout{wxValidator}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,11 +1,13 @@
/////////////////////////////////////////////////////////////////////////////
// Name: wx/uiaction.h
// Purpose: wxUIActionSimulator interface
// Author: Kevin Ollivier
// Author: Kevin Ollivier, Steven Lamerton, Vadim Zeitlin
// Modified by:
// Created: 2010-03-06
// RCS-ID: $Id: menu.cpp 54129 2008-06-11 19:30:52Z SC $
// Copyright: (c) Kevin Ollivier
// (c) 2010 Steven Lamerton
// (c) 2010 Vadim Zeitlin
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
@ -16,39 +18,64 @@
#if wxUSE_UIACTIONSIMULATOR
#include "wx/event.h"
#include "wx/dynarray.h"
#include "wx/mousestate.h" // for wxMOUSE_BTN_XXX constants
class WXDLLIMPEXP_CORE wxUIActionSimulator
{
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)
{ return Key(keycode, false, shiftDown, cmdDown, altDown); }
// Mouse simulation
// ----------------
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:
// 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);
bool MouseDown(int button = wxMOUSE_BTN_LEFT);
bool MouseUp(int button = wxMOUSE_BTN_LEFT);
// Higher level interface, use it if possible instead
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 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

View File

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

View File

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

View File

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

View File

@ -12,31 +12,24 @@
wxUIActionSimulator is a class used to simulate user interface actions
such as a mouse click or a key press.
@note that this class is currently experimental and disabled by default,
you must set @c wxUSE_UIACTIONSIMULATOR to 1 in your setup.h file or use
configure @c --enable-uiactionsim option to enable it.
Common usage 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.
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 @ref page_samples_uiaction for an example of using this class.
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.
@since 2.9.2
@library{wxcore}
*/
class wxUIActionSimulator
{
public:
public:
/**
Constructor.
Default constructor.
*/
wxUIActionSimulator();
~wxUIActionSimulator();
/**
Move the mouse to the specified coordinates.
@ -47,37 +40,49 @@ class wxUIActionSimulator
@param y
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.
@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.
@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.
@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.
@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.
@ -95,59 +100,60 @@ class wxUIActionSimulator
y destination coordinate, in screen coordinates.
@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.
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
key to operate on, as an integer.
Key to operate on, as an integer. It is interpreted as a wxKeyCode.
@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.
@param modifiers
A combination of ::wxKeyModifier flags to be pressed with the given
keycode.
*/
bool KeyDown(int keycode, bool shiftDown=false, bool cmdDown=false, bool altDown=false);
bool KeyDown(int keycode, int modifiers = wxMOD_NONE);
/**
Release a key.
@param keycode
key to operate on, as an integer.
Key to operate on, as an integer. It is interpreted as a wxKeyCode.
@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.
@param modifiers
A combination of ::wxKeyModifier flags to be pressed with the given
keycode.
*/
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.
@param keycode
key to operate on, as an integer.
Key to operate on, as an integer. It is interpreted as a wxKeyCode.
@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.
@param modifiers
A combination of ::wxKeyModifier flags to be pressed with the given
keycode.
*/
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:
// Created: 04/01/98
// RCS-ID: $Id$
// Copyright: (c) Kevin Ollivier
// Copyright: (c) Kevin Ollivier, Steven Lamerton
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
@ -16,10 +16,10 @@
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
@ -52,8 +52,7 @@
enum
{
// menu items
TheButton = 100,
RunSimulation
RunSimulation = 1
};
// ----------------------------------------------------------------------------
@ -76,22 +75,21 @@ 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; }
void OnButtonPressed(wxCommandEvent& event);
void OnRunSimulation(wxCommandEvent& event);
void OnExit(wxCommandEvent& WXUNUSED(event)) { Close(); }
private:
bool m_buttonPressed;
bool m_menuSelected;
wxButton* m_button;
wxTextCtrl* m_text;
DECLARE_EVENT_TABLE()
};
BEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_BUTTON(TheButton, MyFrame::OnButtonPressed)
EVT_BUTTON(wxID_ANY, MyFrame::OnButtonPressed)
EVT_MENU(RunSimulation, MyFrame::OnRunSimulation)
EVT_MENU(wxID_EXIT, MyFrame::OnExit)
END_EVENT_TABLE()
#endif // wxUSE_UIACTIONSIMULATOR
@ -114,7 +112,7 @@ bool MyApp::OnInit()
#if wxUSE_UIACTIONSIMULATOR
MyFrame *frame = new MyFrame("wxUIActionSimulator sample application");
frame->Show(true);
return true;
#else // !wxUSE_UIACTIONSIMULATOR
wxLogError("wxUSE_UIACTIONSIMULATOR must be 1 for this sample");
@ -134,9 +132,6 @@ MyFrame::MyFrame(const wxString& title)
{
SetIcon(wxICON(sample));
m_buttonPressed = false;
m_menuSelected = false;
#if wxUSE_MENUS
// create a menu bar
wxMenu *fileMenu = new wxMenu;
@ -152,30 +147,48 @@ MyFrame::MyFrame(const wxString& title)
SetMenuBar(menuBar);
#endif // wxUSE_MENUS
wxButton* button = new wxButton(this, TheButton, "Button");
button->SetName("TheButton");
wxPanel *panel = new wxPanel(this);
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
void MyFrame::OnRunSimulation(wxCommandEvent&)
void MyFrame::OnRunSimulation(wxCommandEvent& WXUNUSED(event))
{
wxUIActionSimulator sim;
wxWindow* button = FindWindow(wxString("TheButton"));
wxPoint globalPoint = button->ClientToScreen(wxPoint(20, 10));
sim.MouseMove(globalPoint.x, globalPoint.y);
// Add some extra distance to take account of window decorations
sim.MouseMove(m_button->GetScreenPosition() + wxPoint(10, 10));
sim.MouseClick(wxMOUSE_BTN_LEFT);
// Process the resulting button event
wxYield();
if (ButtonPressed())
wxMessageBox("Button automagically pressed!");
m_text->SetFocus();
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

View File

@ -1,11 +1,13 @@
/////////////////////////////////////////////////////////////////////////////
// Name: src/common/uiactioncmn.cpp
// Purpose: wxUIActionSimulator common implementation
// Author: Kevin Ollivier
// Author: Kevin Ollivier, Steven Lamerton, Vadim Zeitlin
// Modified by:
// Created: 2010-03-06
// RCS-ID: $Id: menu.cpp 54129 2008-06-11 19:30:52Z SC $
// Copyright: (c) Kevin Ollivier
// (c) 2010 Steven Lamerton
// (c) 2010 Vadim Zeitlin
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
@ -15,15 +17,6 @@
#include "wx/uiaction.h"
wxUIActionSimulator::wxUIActionSimulator()
{
}
wxUIActionSimulator::~wxUIActionSimulator()
{
}
bool wxUIActionSimulator::MouseClick(int button)
{
MouseDown(button);
@ -42,7 +35,9 @@ bool wxUIActionSimulator::MouseDblClick(int button)
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);
MouseDown(button);
@ -52,10 +47,40 @@ bool wxUIActionSimulator::MouseDragDrop(long x1, long y1, long x2, long y2, int
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);
Key(keycode, true, shiftDown, cmdDown, altDown);
wxASSERT_MSG( !(modifiers & wxMOD_CONTROL),
"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;
}

View File

@ -1,11 +1,13 @@
/////////////////////////////////////////////////////////////////////////////
// Name: src/msw/uiaction.cpp
// Purpose: wxUIActionSimulator implementation
// Author: Kevin Ollivier
// Author: Kevin Ollivier, Steven Lamerton, Vadim Zeitlin
// Modified by:
// Created: 2010-03-06
// RCS-ID: $Id: menu.cpp 54129 2008-06-11 19:30:52Z SC $
// Copyright: (c) Kevin Ollivier
// (c) 2010 Steven Lamerton
// (c) 2010 Vadim Zeitlin
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
@ -17,32 +19,35 @@
#include "wx/msw/wrapwin.h"
namespace
{
DWORD EventTypeForMouseButton(int button, bool isDown)
{
switch (button)
{
case wxMOUSE_BTN_LEFT:
if (isDown)
return MOUSEEVENTF_LEFTDOWN;
else
return MOUSEEVENTF_LEFTUP;
return isDown ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_LEFTUP;
case wxMOUSE_BTN_RIGHT:
if (isDown)
return MOUSEEVENTF_RIGHTDOWN;
else
return MOUSEEVENTF_RIGHTUP;
return isDown ? MOUSEEVENTF_RIGHTDOWN : MOUSEEVENTF_RIGHTUP;
case wxMOUSE_BTN_MIDDLE:
if (isDown)
return MOUSEEVENTF_MIDDLEDOWN;
else
return MOUSEEVENTF_MIDDLEUP;
return isDown ? MOUSEEVENTF_MIDDLEDOWN : MOUSEEVENTF_MIDDLEUP;
default:
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)
{
POINT p;
@ -53,7 +58,13 @@ bool wxUIActionSimulator::MouseDown(int button)
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;
}
@ -65,12 +76,31 @@ bool wxUIActionSimulator::MouseUp(int button)
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)
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;
}

View File

@ -1,11 +1,13 @@
/////////////////////////////////////////////////////////////////////////////
// Name: src/osx/uiaction_osx.cpp
// Purpose: wxUIActionSimulator implementation
// Author: Kevin Ollivier
// Author: Kevin Ollivier, Steven Lamerton, Vadim Zeitlin
// Modified by:
// Created: 2010-03-06
// RCS-ID: $Id: menu.cpp 54129 2008-06-11 19:30:52Z SC $
// Copyright: (c) Kevin Ollivier
// (c) 2010 Steven Lamerton
// (c) 2010 Vadim Zeitlin
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
@ -15,61 +17,189 @@
#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;
CGEventType CGEventTypeForMouseButton(int button, bool isDown)
{
switch (button)
switch ( button )
{
case wxMOUSE_BTN_LEFT:
if (isDown)
return kCGEventLeftMouseDown;
else
return kCGEventLeftMouseUp;
return isDown ? kCGEventLeftMouseDown : kCGEventLeftMouseUp;
case wxMOUSE_BTN_RIGHT:
if (isDown)
return kCGEventRightMouseDown;
else
return kCGEventRightMouseUp;
// Apparently all other buttons use the constant OtherMouseDown
return isDown ? kCGEventRightMouseDown : kCGEventRightMouseUp;
// All the other buttons use the constant OtherMouseDown but we still
// want to check for invalid parameters so assert first
default:
if (isDown)
return kCGEventOtherMouseDown;
else
return kCGEventOtherMouseUp;
wxFAIL_MSG("Unsupported button passed in.");
// fall back to the only known remaining case
case wxMOUSE_BTN_MIDDLE:
return isDown ? kCGEventOtherMouseDown : kCGEventOtherMouseUp;
}
}
void SendCharCode(CGCharCode keycode, bool isDown)
CGPoint GetMousePosition()
{
CGEventRef event = CGEventCreateKeyboardEvent(NULL, keycode, isDown);
if (event)
{
CGEventPost(kCGHIDEventTap, event);
}
CFRelease(event);
int x, y;
wxGetMousePosition(&x, &y);
CGPoint pos;
pos.x = x;
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)
{
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);
wxCFRef<CGEventRef> event(
CGEventCreateMouseEvent(NULL, type, GetMousePosition(), button));
if ( !event )
return false;
CGEventSetType(event, type);
CGEventPost(tap, event);
if (event)
{
CGEventPost(tap, event);
}
CFRelease(event);
return true;
}
@ -78,56 +208,60 @@ 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);
CGEventType type = kCGEventMouseMoved;
wxCFRef<CGEventRef> event(
CGEventCreateMouseEvent(NULL, type, pos, kCGMouseButtonLeft));
if ( !event )
return false;
CGEventSetType(event, type);
CGEventPost(tap, 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);
wxCFRef<CGEventRef> event(
CGEventCreateMouseEvent(NULL, type, GetMousePosition(), button));
if (event)
{
CGEventPost(tap, event);
}
CFRelease(event);
if ( !event )
return false;
CGEventSetType(event, type);
CGEventPost(tap, event);
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)
SendCharCode((CGCharCode)56, true);
if (altDown)
SendCharCode((CGCharCode)58, true);
if (cmdDown)
SendCharCode((CGCharCode)55, true);
if (isDown)
{
if (modifiers & wxMOD_SHIFT)
SendCharCode(kVK_Shift, true);
if (modifiers & wxMOD_ALT)
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)
SendCharCode((CGCharCode)56, false);
if (altDown)
SendCharCode((CGCharCode)58, false);
if (cmdDown)
SendCharCode((CGCharCode)55, false);
if(!isDown)
{
if (modifiers & wxMOD_SHIFT)
SendCharCode(kVK_Shift, false);
if (modifiers & wxMOD_ALT)
SendCharCode(kVK_Option, false);
if (modifiers & wxMOD_CMD)
SendCharCode(kVK_Command, false);
}
return true;
}

View File

@ -1,11 +1,13 @@
/////////////////////////////////////////////////////////////////////////////
// Name: src/unix/uiactionx11.cpp
// Purpose: wxUIActionSimulator implementation
// Author: Kevin Ollivier
// Author: Kevin Ollivier, Steven Lamerton, Vadim Zeitlin
// Modified by:
// Created: 2010-03-06
// RCS-ID: $Id: menu.cpp 54129 2008-06-11 19:30:52Z SC $
// Copyright: (c) Kevin Ollivier
// (c) 2010 Steven Lamerton
// (c) 2010 Vadim Zeitlin
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
@ -15,57 +17,62 @@
#include "wx/uiaction.h"
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/XTest.h>
#include "wx/unix/utilsx11.h"
namespace
{
void SendButtonEvent(int button, bool isDown)
{
int xbutton = 0;
int xbutton;
switch (button)
{
case wxMOUSE_BTN_LEFT:
xbutton = 1;
break;
case wxMOUSE_BTN_RIGHT:
case wxMOUSE_BTN_MIDDLE:
xbutton = 2;
break;
case wxMOUSE_BTN_MIDDLE:
case wxMOUSE_BTN_RIGHT:
xbutton = 3;
break;
default:
wxFAIL_MSG("Unsupported button passed in.");
return;
}
wxX11Display display;
wxCHECK_RET(display, "No display available!");
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.type = isDown ? ButtonPress : 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);
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;
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);
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);
}
} // anonymous namespace
bool wxUIActionSimulator::MouseDown(int button)
{
SendButtonEvent(button, true);
@ -74,12 +81,12 @@ bool wxUIActionSimulator::MouseDown(int button)
bool wxUIActionSimulator::MouseMove(long x, long y)
{
Display *display = XOpenDisplay(0);
wxX11Display display;
wxASSERT_MSG(display, "No display available!");
Window root = DefaultRootWindow(display);
Window root = display.DefaultRoot();
XWarpPointer(display, None, root, 0, 0, 0, 0, x, y);
XFlush(display);
XCloseDisplay(display);
return true;
}
@ -89,37 +96,61 @@ bool wxUIActionSimulator::MouseUp(int button)
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);
wxASSERT_MSG(display, "No display available!");
wxX11Display display;
wxCHECK_MSG(display, false, "No display available!");
XKeyEvent event;
int mask = 0xfff;
memset(&event, 0x00, sizeof(event));
int mask, type;
if (isDown) {
event.type = KeyPress;
if ( isDown )
{
type = KeyPress;
mask = KeyPressMask;
}
else {
event.type = KeyRelease;
else
{
type = KeyRelease;
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.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);
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);
XSendEvent(event.display, event.window, True, mask, (XEvent*) &event);
return true;
}

View File

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