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
DEFAULT_wxUSE_ACCESSIBILITY=no
DEFAULT_wxUSE_IPV6=no
DEFAULT_wxUSE_GSTREAMER8=no
-DEFAULT_wxUSE_UIACTIONSIMULATOR=no
dnl automatic features
DEFAULT_wxUSE_UNICODE_UTF8=auto
- 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).
@li @sample{toolbar}
@li @sample{treectrl}
@li @sample{typetest}
+@li @sample{uiaction}
@li @sample{validate}
@li @sample{vscroll}
@li @sample{widgets}
@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}
// 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
// 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
// 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
// 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
// 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
// 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
// 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
/////////////////////////////////////////////////////////////////////////////
// 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
/////////////////////////////////////////////////////////////////////////////
#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
// 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
#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,
// 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 );
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.
@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.
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.
- @param keycode
- key to operate on, as an integer.
-
- @param shiftDown
- true if the shift key should be pressed, false otherwise.
+ 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 cmdDown
- true if the cmd key should be pressed, false otherwise.
+ @param keycode
+ Key to operate on, as an integer. It is interpreted as a wxKeyCode.
- @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.
-
- @param shiftDown
- true if the shift key should be pressed, false otherwise.
-
- @param cmdDown
- true if the cmd key should be pressed, false otherwise.
+ Key to operate on, as an integer. It is interpreted as a wxKeyCode.
- @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 modifiers
+ A combination of ::wxKeyModifier flags to be pressed with the given
+ keycode.
+ */
+ bool Char(int keycode, int modifiers = wxMOD_NONE);
+
+ /**
+ Emulate typing in the keys representing the given string.
- @param cmdDown
- true if the cmd key should be pressed, false otherwise.
+ Currently only the ASCII letters (i.e. characters @c a-z and @c A-Z)
+ are supported.
- @param altDown
- true if the alt key should be pressed, false otherwise.
+ @param text
+ The string to type.
*/
- bool Char(int keycode, bool shiftDown=false, bool cmdDown=false, bool altDown=false);
+ bool Text(const wxString& text);
};
// Modified by:
// Created: 04/01/98
// RCS-ID: $Id$
-// Copyright: (c) Kevin Ollivier
+// Copyright: (c) Kevin Ollivier, Steven Lamerton
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
-
+
// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"
-
+
#ifdef __BORLANDC__
#pragma hdrstop
#endif
enum
{
// menu items
- TheButton = 100,
- RunSimulation
+ RunSimulation = 1
};
// ----------------------------------------------------------------------------
// 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
#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");
{
SetIcon(wxICON(sample));
- m_buttonPressed = false;
- m_menuSelected = false;
-
#if wxUSE_MENUS
// create a menu bar
wxMenu *fileMenu = new wxMenu;
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
/////////////////////////////////////////////////////////////////////////////
// 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
/////////////////////////////////////////////////////////////////////////////
#include "wx/uiaction.h"
-wxUIActionSimulator::wxUIActionSimulator()
-{
-}
-
-wxUIActionSimulator::~wxUIActionSimulator()
-{
-}
-
-
bool wxUIActionSimulator::MouseClick(int button)
{
MouseDown(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);
return true;
}
-bool wxUIActionSimulator::Char(int keycode, bool shiftDown, bool cmdDown, bool altDown)
+bool
+wxUIActionSimulator::Key(int keycode, int modifiers, bool isDown)
+{
+ 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)
{
- Key(keycode, false, shiftDown, cmdDown, altDown);
- Key(keycode, true, shiftDown, cmdDown, altDown);
+ 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;
}
/////////////////////////////////////////////////////////////////////////////
// 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
/////////////////////////////////////////////////////////////////////////////
#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;
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;
}
-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;
}
/////////////////////////////////////////////////////////////////////////////
// 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
/////////////////////////////////////////////////////////////////////////////
#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;
- case wxMOUSE_BTN_RIGHT:
- if (isDown)
- return kCGEventRightMouseDown;
- else
- return kCGEventRightMouseUp;
+ return isDown ? kCGEventLeftMouseDown : kCGEventLeftMouseUp;
- // Apparently all other buttons use the constant OtherMouseDown
+ case wxMOUSE_BTN_RIGHT:
+ 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)
+ 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)
{
- CGEventPost(kCGHIDEventTap, event);
+ 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 );
}
- CFRelease(event);
+
+ 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);
+ 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;
}
CGPoint pos;
pos.x = x;
pos.y = y;
+
CGEventType type = kCGEventMouseMoved;
- CGEventRef event = CGEventCreateMouseEvent(NULL, type, pos, kCGMouseButtonLeft);
- CGEventSetType(event, type);
+ wxCFRef<CGEventRef> event(
+ CGEventCreateMouseEvent(NULL, type, pos, kCGMouseButtonLeft));
- if (event)
- {
- CGEventPost(tap, event);
- }
- CFRelease(event);
+ 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);
-
- SendCharCode((CGCharCode)keycode, isDown);
-
- 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, true);
+ if (modifiers & wxMOD_ALT)
+ SendCharCode(kVK_Option, true);
+ if (modifiers & wxMOD_CMD)
+ SendCharCode(kVK_Command, true);
+ }
+
+ CGKeyCode cgcode = wxCharCodeWXToOSX((wxKeyCode)keycode);
+ if ( !SendCharCode(cgcode, isDown) )
+ return 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;
}
/////////////////////////////////////////////////////////////////////////////
// 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
/////////////////////////////////////////////////////////////////////////////
#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;
}
- XEvent event;
-
- Display *display = XOpenDisplay(0);
- wxASSERT_MSG(display, "No display available!");
+ wxX11Display display;
+ wxCHECK_RET(display, "No display available!");
+ XEvent event;
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);
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;
}
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;
}
- 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;
+ WXKeySym xkeysym = wxCharCodeWXToX(keycode);
+ KeyCode xkeycode = XKeysymToKeycode(display, xkeysym);
+ if ( xkeycode == NoSymbol )
+ return false;
- 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);
- }
+ 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;
- XSendEvent(display, PointerWindow, True, mask, (XEvent*) &event);
- XFlush(display);
- XCloseDisplay(display);
+ XSendEvent(event.display, event.window, True, mask, (XEvent*) &event);
return true;
}
// FIXME what about tables??
-int wxCharCodeXToWX(KeySym keySym)
+int wxCharCodeXToWX(WXKeySym keySym)
{
int id;
switch (keySym)
return id;
}
-KeySym wxCharCodeWXToX(int id)
+WXKeySym wxCharCodeWXToX(int id)
{
- KeySym keySym;
+ WXKeySym keySym;
switch (id)
{