Merge branch 'uisim-xtest'

Make wxUIActionSimulator work with GTK+3, including when using DPI scaling.
This commit is contained in:
Vadim Zeitlin
2016-06-04 22:44:25 +02:00
15 changed files with 705 additions and 100 deletions

137
configure vendored
View File

@@ -945,6 +945,8 @@ WEBKIT_LIBS
WEBKIT_CFLAGS WEBKIT_CFLAGS
COND_PYTHON COND_PYTHON
PYTHON PYTHON
XTST_LIBS
XTST_CFLAGS
LIBNOTIFY_LIBS LIBNOTIFY_LIBS
LIBNOTIFY_CFLAGS LIBNOTIFY_CFLAGS
GNOMEVFS_LIBS GNOMEVFS_LIBS
@@ -1094,6 +1096,7 @@ with_gtkprint
with_gnomevfs with_gnomevfs
with_libnotify with_libnotify
with_opengl with_opengl
with_xtest
with_dmalloc with_dmalloc
with_sdl with_sdl
with_regex with_regex
@@ -1402,6 +1405,8 @@ GNOMEVFS_CFLAGS
GNOMEVFS_LIBS GNOMEVFS_LIBS
LIBNOTIFY_CFLAGS LIBNOTIFY_CFLAGS
LIBNOTIFY_LIBS LIBNOTIFY_LIBS
XTST_CFLAGS
XTST_LIBS
WEBKIT_CFLAGS WEBKIT_CFLAGS
WEBKIT_LIBS WEBKIT_LIBS
CAIRO_CFLAGS CAIRO_CFLAGS
@@ -2324,6 +2329,7 @@ Optional Packages:
--with-gnomevfs use GNOME VFS for associating MIME types --with-gnomevfs use GNOME VFS for associating MIME types
--with-libnotify use libnotify for notifications --with-libnotify use libnotify for notifications
--with-opengl use OpenGL (or Mesa) --with-opengl use OpenGL (or Mesa)
--with-xtest use XTest extension
--with-dmalloc use dmalloc library (http://dmalloc.com/) --with-dmalloc use dmalloc library (http://dmalloc.com/)
--with-sdl use SDL for audio on Unix --with-sdl use SDL for audio on Unix
--with-regex enable support for wxRegEx class --with-regex enable support for wxRegEx class
@@ -2401,6 +2407,8 @@ Some influential environment variables:
C compiler flags for LIBNOTIFY, overriding pkg-config C compiler flags for LIBNOTIFY, overriding pkg-config
LIBNOTIFY_LIBS LIBNOTIFY_LIBS
linker flags for LIBNOTIFY, overriding pkg-config linker flags for LIBNOTIFY, overriding pkg-config
XTST_CFLAGS C compiler flags for XTST, overriding pkg-config
XTST_LIBS linker flags for XTST, overriding pkg-config
WEBKIT_CFLAGS WEBKIT_CFLAGS
C compiler flags for WEBKIT, overriding pkg-config C compiler flags for WEBKIT, overriding pkg-config
WEBKIT_LIBS linker flags for WEBKIT, overriding pkg-config WEBKIT_LIBS linker flags for WEBKIT, overriding pkg-config
@@ -4833,6 +4841,35 @@ fi
eval "$wx_cv_use_opengl" eval "$wx_cv_use_opengl"
withstring=
defaultval=$wxUSE_ALL_FEATURES
if test -z "$defaultval"; then
if test x"$withstring" = xwithout; then
defaultval=yes
else
defaultval=no
fi
fi
# Check whether --with-xtest was given.
if test "${with_xtest+set}" = set; then :
withval=$with_xtest;
if test "$withval" = yes; then
wx_cv_use_xtest='wxUSE_XTEST=yes'
else
wx_cv_use_xtest='wxUSE_XTEST=no'
fi
else
wx_cv_use_xtest='wxUSE_XTEST=${'DEFAULT_wxUSE_XTEST":-$defaultval}"
fi
eval "$wx_cv_use_xtest"
fi fi
@@ -33666,9 +33703,109 @@ if test "$wxUSE_MOUSEWHEEL" = "yes" ; then
fi fi
if test "$wxUSE_UIACTIONSIMULATOR" = "yes" ; then if test "$wxUSE_UIACTIONSIMULATOR" = "yes" ; then
if test "$wxUSE_GTK" = 1 -o "$wxUSE_MOTIF" = 1 -o "$wxUSE_X11" = 1; then
if test "$wxUSE_XTEST" = "yes" ; then
pkg_failed=no
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for XTST" >&5
$as_echo_n "checking for XTST... " >&6; }
if test -n "$PKG_CONFIG"; then
if test -n "$XTST_CFLAGS"; then
pkg_cv_XTST_CFLAGS="$XTST_CFLAGS"
else
if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"xtst\""; } >&5
($PKG_CONFIG --exists --print-errors "xtst") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_XTST_CFLAGS=`$PKG_CONFIG --cflags "xtst" 2>/dev/null`
else
pkg_failed=yes
fi
fi
else
pkg_failed=untried
fi
if test -n "$PKG_CONFIG"; then
if test -n "$XTST_LIBS"; then
pkg_cv_XTST_LIBS="$XTST_LIBS"
else
if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"xtst\""; } >&5
($PKG_CONFIG --exists --print-errors "xtst") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_XTST_LIBS=`$PKG_CONFIG --libs "xtst" 2>/dev/null`
else
pkg_failed=yes
fi
fi
else
pkg_failed=untried
fi
if test $pkg_failed = yes; then
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
XTST_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "xtst"`
else
XTST_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "xtst"`
fi
# Put the nasty error message in config.log where it belongs
echo "$XTST_PKG_ERRORS" >&5
if test "$WXGTK3" = 1; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: XTest not found, disabling wxUIActionSimulator" >&5
$as_echo "$as_me: WARNING: XTest not found, disabling wxUIActionSimulator" >&2;}
wxUSE_UIACTIONSIMULATOR=no
fi
wxUSE_XTEST="no"
elif test $pkg_failed = untried; then
if test "$WXGTK3" = 1; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: XTest not found, disabling wxUIActionSimulator" >&5
$as_echo "$as_me: WARNING: XTest not found, disabling wxUIActionSimulator" >&2;}
wxUSE_UIACTIONSIMULATOR=no
fi
wxUSE_XTEST="no"
else
XTST_CFLAGS=$pkg_cv_XTST_CFLAGS
XTST_LIBS=$pkg_cv_XTST_LIBS
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
GUI_TK_LIBRARY="$GUI_TK_LIBRARY $XTST_LIBS"
CFLAGS="$XTST_CFLAGS $CFLAGS"
CXXFLAGS="$XTST_CFLAGS $CXXFLAGS"
$as_echo "#define wxUSE_XTEST 1" >>confdefs.h
fi
elif test "$WXGTK3" = 1; then
wxUSE_UIACTIONSIMULATOR=no
fi
fi
if test "$wxUSE_UIACTIONSIMULATOR" = "yes" ; then
$as_echo "#define wxUSE_UIACTIONSIMULATOR 1" >>confdefs.h $as_echo "#define wxUSE_UIACTIONSIMULATOR 1" >>confdefs.h
SAMPLES_SUBDIRS="$SAMPLES_SUBDIRS uiaction" SAMPLES_SUBDIRS="$SAMPLES_SUBDIRS uiaction"
fi
fi fi
if test "$wxUSE_DC_TRANSFORM_MATRIX" = "yes" ; then if test "$wxUSE_DC_TRANSFORM_MATRIX" = "yes" ; then

View File

@@ -542,6 +542,7 @@ WX_ARG_WITHOUT(gtkprint, [ --without-gtkprint don't use GTK printing sup
WX_ARG_WITH(gnomevfs, [ --with-gnomevfs use GNOME VFS for associating MIME types], wxUSE_LIBGNOMEVFS) WX_ARG_WITH(gnomevfs, [ --with-gnomevfs use GNOME VFS for associating MIME types], wxUSE_LIBGNOMEVFS)
WX_ARG_WITH(libnotify, [ --with-libnotify use libnotify for notifications], wxUSE_LIBNOTIFY) WX_ARG_WITH(libnotify, [ --with-libnotify use libnotify for notifications], wxUSE_LIBNOTIFY)
WX_ARG_WITH(opengl, [ --with-opengl use OpenGL (or Mesa)], wxUSE_OPENGL) WX_ARG_WITH(opengl, [ --with-opengl use OpenGL (or Mesa)], wxUSE_OPENGL)
WX_ARG_WITH(xtest, [ --with-xtest use XTest extension], wxUSE_XTEST)
fi fi
dnl for GUI only dnl for GUI only
@@ -6389,8 +6390,38 @@ if test "$wxUSE_MOUSEWHEEL" = "yes" ; then
fi fi
if test "$wxUSE_UIACTIONSIMULATOR" = "yes" ; then if test "$wxUSE_UIACTIONSIMULATOR" = "yes" ; then
if test "$wxUSE_GTK" = 1 -o "$wxUSE_MOTIF" = 1 -o "$wxUSE_X11" = 1; then
if test "$wxUSE_XTEST" = "yes" ; then
PKG_CHECK_MODULES(XTST, xtst,
[
GUI_TK_LIBRARY="$GUI_TK_LIBRARY $XTST_LIBS"
CFLAGS="$XTST_CFLAGS $CFLAGS"
CXXFLAGS="$XTST_CFLAGS $CXXFLAGS"
AC_DEFINE(wxUSE_XTEST)
],
[
if test "$WXGTK3" = 1; then
dnl This class can't work without XTest with GTK+ 3
dnl which uses XInput2 and so ignores XSendEvent().
AC_MSG_WARN([XTest not found, disabling wxUIActionSimulator])
wxUSE_UIACTIONSIMULATOR=no
fi
dnl The other ports can use XSendEvent(), so don't warn
wxUSE_XTEST="no"
]
)
elif test "$WXGTK3" = 1; then
dnl As per above, wxUIActionSimulator can't be used in this case,
dnl but there is no need to warn, presumably the user knows what
dnl he's doing if --without-xtest was explicitly specified.
wxUSE_UIACTIONSIMULATOR=no
fi
fi
if test "$wxUSE_UIACTIONSIMULATOR" = "yes" ; then
AC_DEFINE(wxUSE_UIACTIONSIMULATOR) AC_DEFINE(wxUSE_UIACTIONSIMULATOR)
SAMPLES_SUBDIRS="$SAMPLES_SUBDIRS uiaction" SAMPLES_SUBDIRS="$SAMPLES_SUBDIRS uiaction"
fi
fi fi
if test "$wxUSE_DC_TRANSFORM_MATRIX" = "yes" ; then if test "$wxUSE_DC_TRANSFORM_MATRIX" = "yes" ; then

View File

@@ -88,6 +88,7 @@ All (GUI):
wxGTK: wxGTK:
- Make wxUIActionSimulator work with GTK+ 3 (Scott Talbert).
- Implement setting link colours in wxHyperlinkCtrl for GTK+3 (Hanmac). - Implement setting link colours in wxHyperlinkCtrl for GTK+3 (Hanmac).
- Support background colour in wxDataViewCtrl attributes. - Support background colour in wxDataViewCtrl attributes.
- Improve wxSpinCtrl best size calculation. - Improve wxSpinCtrl best size calculation.

View File

@@ -267,6 +267,7 @@ library:
@itemdef{wxUSE_LIBSDL, Use SDL for wxSound implementation.} @itemdef{wxUSE_LIBSDL, Use SDL for wxSound implementation.}
@itemdef{wxUSE_PLUGINS, See also wxUSE_LIBSDL.} @itemdef{wxUSE_PLUGINS, See also wxUSE_LIBSDL.}
@itemdef{wxUSE_UNIX, Enabled on Unix Platform.} @itemdef{wxUSE_UNIX, Enabled on Unix Platform.}
@itemdef(wxUSE_XTEST, Use XTest extension.}
@endDefList @endDefList

View File

@@ -0,0 +1,44 @@
///////////////////////////////////////////////////////////////////////////////
// Name: wx/private/uiaction.h
// Purpose: wxUIActionSimulatorImpl declaration
// Author: Vadim Zeitlin
// Created: 2016-05-21
// Copyright: (c) 2016 Vadim Zeitlin <vadim@wxwidgets.org>
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
#ifndef _WX_PRIVATE_UIACTION_H_
#define _WX_PRIVATE_UIACTION_H_
// ----------------------------------------------------------------------------
// Platform-specific implementation of wxUIActionSimulator
// ----------------------------------------------------------------------------
class wxUIActionSimulatorImpl
{
public:
wxUIActionSimulatorImpl() { }
virtual ~wxUIActionSimulatorImpl() { }
// Low level mouse methods which must be implemented in the derived class.
virtual bool MouseMove(long x, long y) = 0;
virtual bool MouseDown(int button = wxMOUSE_BTN_LEFT) = 0;
virtual bool MouseUp(int button = wxMOUSE_BTN_LEFT) = 0;
// Higher level mouse methods which have default implementation in the base
// class but can be overridden if necessary.
virtual bool MouseClick(int button = wxMOUSE_BTN_LEFT);
virtual bool MouseDblClick(int button = wxMOUSE_BTN_LEFT);
virtual bool MouseDragDrop(long x1, long y1, long x2, long y2,
int button = wxMOUSE_BTN_LEFT);
// The low-level port-specific function which really generates the key
// presses. It should generate exactly one key event with the given
// parameters.
virtual bool DoKey(int keycode, int modifiers, bool isDown) = 0;
private:
wxDECLARE_NO_COPY_CLASS(wxUIActionSimulatorImpl);
};
#endif // _WX_PRIVATE_UIACTION_H_

View File

@@ -2,11 +2,10 @@
// Name: wx/uiaction.h // Name: wx/uiaction.h
// Purpose: wxUIActionSimulator interface // Purpose: wxUIActionSimulator interface
// Author: Kevin Ollivier, Steven Lamerton, Vadim Zeitlin // Author: Kevin Ollivier, Steven Lamerton, Vadim Zeitlin
// Modified by:
// Created: 2010-03-06 // Created: 2010-03-06
// Copyright: (c) Kevin Ollivier // Copyright: (c) 2010 Kevin Ollivier
// (c) 2010 Steven Lamerton // (c) 2010 Steven Lamerton
// (c) 2010 Vadim Zeitlin // (c) 2010-2016 Vadim Zeitlin
// Licence: wxWindows licence // Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
@@ -22,11 +21,8 @@
class WXDLLIMPEXP_CORE wxUIActionSimulator class WXDLLIMPEXP_CORE wxUIActionSimulator
{ {
public: public:
wxUIActionSimulator() { } wxUIActionSimulator();
~wxUIActionSimulator();
// Default dtor, copy ctor and assignment operator are ok (even though the
// last two don't make much sense for this class).
// Mouse simulation // Mouse simulation
@@ -82,10 +78,12 @@ private:
void SimulateModifiers(int modifier, bool isDown); void SimulateModifiers(int modifier, bool isDown);
// The low-level port-specific function which really generates the key
// presses. It should generate exactly one key event with the given // This pointer is allocated in the ctor and points to the
// parameters. // platform-specific implementation.
bool DoKey(int keycode, int modifiers, bool isDown); class wxUIActionSimulatorImpl* const m_impl;
wxDECLARE_NO_COPY_CLASS(wxUIActionSimulator);
}; };
#endif // wxUSE_UIACTIONSIMULATOR #endif // wxUSE_UIACTIONSIMULATOR

View File

@@ -41,3 +41,11 @@
# endif # endif
# endif # endif
#endif /* wxUSE_GSTREAMER */ #endif /* wxUSE_GSTREAMER */
#ifndef wxUSE_XTEST
# ifdef wxABORT_ON_CONFIG_ERROR
# error "wxUSE_XTEST must be defined, please read comment near the top of this file."
# else
# define wxUSE_XTEST 0
# endif
#endif /* !defined(wxUSE_XTEST) */

View File

@@ -67,6 +67,13 @@ public:
wxX11Display() { m_dpy = XOpenDisplay(NULL); } wxX11Display() { m_dpy = XOpenDisplay(NULL); }
~wxX11Display() { if ( m_dpy ) XCloseDisplay(m_dpy); } ~wxX11Display() { if ( m_dpy ) XCloseDisplay(m_dpy); }
// Pseudo move ctor: steals the open display from the other object.
explicit wxX11Display(wxX11Display& display)
{
m_dpy = display.m_dpy;
display.m_dpy = NULL;
}
operator Display *() const { return m_dpy; } operator Display *() const { return m_dpy; }
// Using DefaultRootWindow() with an object of wxX11Display class doesn't // Using DefaultRootWindow() with an object of wxX11Display class doesn't

View File

@@ -2,9 +2,9 @@
// Name: uiaction.cpp // Name: uiaction.cpp
// Purpose: wxUIActionSimulator sample // Purpose: wxUIActionSimulator sample
// Author: Kevin Ollivier // Author: Kevin Ollivier
// Modified by:
// Created: 04/01/98 // Created: 04/01/98
// Copyright: (c) Kevin Ollivier, Steven Lamerton // Copyright: (c) 2010 Kevin Ollivier, Steven Lamerton
// (c) 2016 Vadim Zeitlin
// Licence: wxWindows licence // Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
@@ -33,6 +33,8 @@
#include "wx/uiaction.h" #include "wx/uiaction.h"
#endif #endif
#include "wx/stopwatch.h"
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// resources // resources
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -76,6 +78,7 @@ public:
MyFrame(const wxString& title); MyFrame(const wxString& title);
void OnButtonPressed(wxCommandEvent& event); void OnButtonPressed(wxCommandEvent& event);
void OnNew(wxCommandEvent& event);
void OnRunSimulation(wxCommandEvent& event); void OnRunSimulation(wxCommandEvent& event);
void OnSimulateText(wxCommandEvent& event); void OnSimulateText(wxCommandEvent& event);
void OnExit(wxCommandEvent& WXUNUSED(event)) { Close(); } void OnExit(wxCommandEvent& WXUNUSED(event)) { Close(); }
@@ -89,6 +92,7 @@ private:
wxBEGIN_EVENT_TABLE(MyFrame, wxFrame) wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_BUTTON(wxID_ANY, MyFrame::OnButtonPressed) EVT_BUTTON(wxID_ANY, MyFrame::OnButtonPressed)
EVT_MENU(wxID_NEW, MyFrame::OnNew)
EVT_MENU(RunSimulation, MyFrame::OnRunSimulation) EVT_MENU(RunSimulation, MyFrame::OnRunSimulation)
EVT_MENU(SimulateText, MyFrame::OnSimulateText) EVT_MENU(SimulateText, MyFrame::OnSimulateText)
EVT_MENU(wxID_EXIT, MyFrame::OnExit) EVT_MENU(wxID_EXIT, MyFrame::OnExit)
@@ -139,9 +143,9 @@ MyFrame::MyFrame(const wxString& title)
wxMenu *fileMenu = new wxMenu; wxMenu *fileMenu = new wxMenu;
fileMenu->Append(wxID_NEW, "&New File...", "Open a new file"); fileMenu->Append(wxID_NEW, "&New File...", "Open a new file");
fileMenu->Append(RunSimulation, "&Run Simulation", fileMenu->Append(RunSimulation, "&Run Simulation\tCtrl-R",
"Run predefined UI action simulation"); "Run predefined UI action simulation");
fileMenu->Append(SimulateText, "Simulate &text input...", fileMenu->Append(SimulateText, "Simulate &text input...\tCtrl-T",
"Enter text to simulate"); "Enter text to simulate");
fileMenu->AppendSeparator(); fileMenu->AppendSeparator();
@@ -170,8 +174,25 @@ MyFrame::MyFrame(const wxString& title)
// event handlers // event handlers
void MyFrame::OnNew(wxCommandEvent& WXUNUSED(event))
{
m_text->AppendText("\"New\" menu item was selected\n");
}
void MyFrame::OnRunSimulation(wxCommandEvent& WXUNUSED(event)) void MyFrame::OnRunSimulation(wxCommandEvent& WXUNUSED(event))
{ {
m_text->SetValue("=== Starting the simulation "
"(release any pressed keys) ===\n");
// This sleep is needed to give the time for the currently pressed modifier
// keys, if any, to be released. Notice that Control modifier could well be
// pressed if this command was activated from the menu using accelerator
// and keeping it pressed would totally derail the test below, e.g. "A" key
// press would actually become "Ctrl+A" selecting the entire text and so on.
wxMilliSleep(500);
wxStopWatch sw;
wxUIActionSimulator sim; wxUIActionSimulator sim;
// Add some extra distance to take account of window decorations // Add some extra distance to take account of window decorations
@@ -193,6 +214,15 @@ void MyFrame::OnRunSimulation(wxCommandEvent& WXUNUSED(event))
sim.Text("1 234.57e-8"); sim.Text("1 234.57e-8");
sim.Char(WXK_RETURN); sim.Char(WXK_RETURN);
// Process the resulting text events
wxYield();
// Emulate opening a menu from keyboard.
sim.Char('F', wxMOD_ALT);
sim.Char('N');
wxYield();
m_text->AppendText(wxString::Format("\n=== Done in %ldms ===\n", sw.Time()));
} }
void MyFrame::OnSimulateText(wxCommandEvent& WXUNUSED(event)) void MyFrame::OnSimulateText(wxCommandEvent& WXUNUSED(event))

View File

@@ -639,6 +639,16 @@
#define wxUSE_GSTREAMER_PLAYER 0 #define wxUSE_GSTREAMER_PLAYER 0
/*
Use XTest extension to implement wxUIActionSimulator?
Default is 1, it is set to 0 if the necessary headers/libraries are not
found by configure.
Recommended setting: 1, wxUIActionSimulator won't work in wxGTK3 without it.
*/
#define wxUSE_XTEST 0
/* --- start MSW options --- */ /* --- start MSW options --- */

View File

@@ -2,11 +2,10 @@
// Name: src/common/uiactioncmn.cpp // Name: src/common/uiactioncmn.cpp
// Purpose: wxUIActionSimulator common implementation // Purpose: wxUIActionSimulator common implementation
// Author: Kevin Ollivier, Steven Lamerton, Vadim Zeitlin // Author: Kevin Ollivier, Steven Lamerton, Vadim Zeitlin
// Modified by:
// Created: 2010-03-06 // Created: 2010-03-06
// Copyright: (c) Kevin Ollivier // Copyright: (c) 2010 Kevin Ollivier
// (c) 2010 Steven Lamerton // (c) 2010 Steven Lamerton
// (c) 2010 Vadim Zeitlin // (c) 2010-2016 Vadim Zeitlin
// Licence: wxWindows licence // Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
@@ -24,8 +23,48 @@
#include "wx/listbox.h" #include "wx/listbox.h"
#endif // wxNO_RTTI #endif // wxNO_RTTI
#include "wx/private/uiaction.h"
// ----------------------------------------------------------------------------
// Methods forwarded to wxUIActionSimulatorImpl
// ----------------------------------------------------------------------------
bool wxUIActionSimulator::MouseMove(long x, long y)
{
return m_impl->MouseMove(x, y);
}
bool wxUIActionSimulator::MouseDown(int button)
{
return m_impl->MouseDown(button);
}
bool wxUIActionSimulator::MouseUp(int button)
{
return m_impl->MouseUp(button);
}
bool wxUIActionSimulator::MouseClick(int button) bool wxUIActionSimulator::MouseClick(int button)
{
return m_impl->MouseClick(button);
}
bool wxUIActionSimulator::MouseDblClick(int button)
{
return m_impl->MouseDblClick(button);
}
bool wxUIActionSimulator::MouseDragDrop(long x1, long y1, long x2, long y2,
int button)
{
return m_impl->MouseDragDrop(x1, y1, x2, y2, button);
}
// ----------------------------------------------------------------------------
// Methods implemented in wxUIActionSimulatorImpl itself
// ----------------------------------------------------------------------------
bool wxUIActionSimulatorImpl::MouseClick(int button)
{ {
MouseDown(button); MouseDown(button);
MouseUp(button); MouseUp(button);
@@ -33,9 +72,7 @@ bool wxUIActionSimulator::MouseClick(int button)
return true; return true;
} }
#ifndef __WXOSX__ bool wxUIActionSimulatorImpl::MouseDblClick(int button)
bool wxUIActionSimulator::MouseDblClick(int button)
{ {
MouseDown(button); MouseDown(button);
MouseUp(button); MouseUp(button);
@@ -45,7 +82,7 @@ bool wxUIActionSimulator::MouseDblClick(int button)
return true; return true;
} }
bool wxUIActionSimulator::MouseDragDrop(long x1, long y1, long x2, long y2, bool wxUIActionSimulatorImpl::MouseDragDrop(long x1, long y1, long x2, long y2,
int button) int button)
{ {
MouseMove(x1, y1); MouseMove(x1, y1);
@@ -56,8 +93,6 @@ bool wxUIActionSimulator::MouseDragDrop(long x1, long y1, long x2, long y2,
return true; return true;
} }
#endif
bool bool
wxUIActionSimulator::Key(int keycode, int modifiers, bool isDown) wxUIActionSimulator::Key(int keycode, int modifiers, bool isDown)
{ {
@@ -69,7 +104,7 @@ wxUIActionSimulator::Key(int keycode, int modifiers, bool isDown)
if ( isDown ) if ( isDown )
SimulateModifiers(modifiers, true); SimulateModifiers(modifiers, true);
bool rc = DoKey(keycode, modifiers, isDown); bool rc = m_impl->DoKey(keycode, modifiers, isDown);
if ( !isDown ) if ( !isDown )
SimulateModifiers(modifiers, false); SimulateModifiers(modifiers, false);
@@ -80,11 +115,11 @@ wxUIActionSimulator::Key(int keycode, int modifiers, bool isDown)
void wxUIActionSimulator::SimulateModifiers(int modifiers, bool isDown) void wxUIActionSimulator::SimulateModifiers(int modifiers, bool isDown)
{ {
if ( modifiers & wxMOD_SHIFT ) if ( modifiers & wxMOD_SHIFT )
DoKey(WXK_SHIFT, modifiers, isDown); m_impl->DoKey(WXK_SHIFT, modifiers, isDown);
if ( modifiers & wxMOD_ALT ) if ( modifiers & wxMOD_ALT )
DoKey(WXK_ALT, modifiers, isDown); m_impl->DoKey(WXK_ALT, modifiers, isDown);
if ( modifiers & wxMOD_CONTROL ) if ( modifiers & wxMOD_CONTROL )
DoKey(WXK_CONTROL, modifiers, isDown); m_impl->DoKey(WXK_CONTROL, modifiers, isDown);
} }
bool wxUIActionSimulator::Char(int keycode, int modifiers) bool wxUIActionSimulator::Char(int keycode, int modifiers)

View File

@@ -19,6 +19,8 @@
#endif #endif
#include "wx/uiaction.h" #include "wx/uiaction.h"
#include "wx/private/uiaction.h"
#include "wx/msw/wrapwin.h" #include "wx/msw/wrapwin.h"
#include "wx/msw/private/keyboard.h" #include "wx/msw/private/keyboard.h"
@@ -28,6 +30,31 @@
namespace namespace
{ {
class wxUIActionSimulatorMSWImpl : public wxUIActionSimulatorImpl
{
public:
// Returns a pointer to the global simulator object: as it's stateless, we
// can reuse the same one without having to allocate it on the heap all the
// time.
static wxUIActionSimulatorMSWImpl* Get()
{
static wxUIActionSimulatorMSWImpl s_impl;
return &s_impl;
}
virtual bool MouseMove(long x, long y) wxOVERRIDE;
virtual bool MouseDown(int button = wxMOUSE_BTN_LEFT) wxOVERRIDE;
virtual bool MouseUp(int button = wxMOUSE_BTN_LEFT) wxOVERRIDE;
virtual bool DoKey(int keycode, int modifiers, bool isDown) wxOVERRIDE;
private:
// This class has no public ctors, use Get() instead.
wxUIActionSimulatorMSWImpl() { }
wxDECLARE_NO_COPY_CLASS(wxUIActionSimulatorMSWImpl);
};
DWORD EventTypeForMouseButton(int button, bool isDown) DWORD EventTypeForMouseButton(int button, bool isDown)
{ {
switch (button) switch (button)
@@ -49,7 +76,7 @@ DWORD EventTypeForMouseButton(int button, bool isDown)
} // anonymous namespace } // anonymous namespace
bool wxUIActionSimulator::MouseDown(int button) bool wxUIActionSimulatorMSWImpl::MouseDown(int button)
{ {
POINT p; POINT p;
wxGetCursorPosMSW(&p); wxGetCursorPosMSW(&p);
@@ -57,7 +84,7 @@ bool wxUIActionSimulator::MouseDown(int button)
return true; return true;
} }
bool wxUIActionSimulator::MouseMove(long x, long y) bool wxUIActionSimulatorMSWImpl::MouseMove(long x, long y)
{ {
// Because MOUSEEVENTF_ABSOLUTE takes measurements scaled between 0 & 65535 // Because MOUSEEVENTF_ABSOLUTE takes measurements scaled between 0 & 65535
// we need to scale our input too // we need to scale our input too
@@ -73,7 +100,7 @@ bool wxUIActionSimulator::MouseMove(long x, long y)
return true; return true;
} }
bool wxUIActionSimulator::MouseUp(int button) bool wxUIActionSimulatorMSWImpl::MouseUp(int button)
{ {
POINT p; POINT p;
wxGetCursorPosMSW(&p); wxGetCursorPosMSW(&p);
@@ -82,7 +109,7 @@ bool wxUIActionSimulator::MouseUp(int button)
} }
bool bool
wxUIActionSimulator::DoKey(int keycode, int WXUNUSED(modifiers), bool isDown) wxUIActionSimulatorMSWImpl::DoKey(int keycode, int WXUNUSED(modifiers), bool isDown)
{ {
bool isExtended; bool isExtended;
DWORD vkkeycode = wxMSWKeyboard::WXToVK(keycode, &isExtended); DWORD vkkeycode = wxMSWKeyboard::WXToVK(keycode, &isExtended);
@@ -98,4 +125,15 @@ wxUIActionSimulator::DoKey(int keycode, int WXUNUSED(modifiers), bool isDown)
return true; return true;
} }
wxUIActionSimulator::wxUIActionSimulator()
: m_impl(wxUIActionSimulatorMSWImpl::Get())
{
}
wxUIActionSimulator::~wxUIActionSimulator()
{
// We can use a static wxUIActionSimulatorMSWImpl object because it's
// stateless, so no need to delete it.
}
#endif // wxUSE_UIACTIONSIMULATOR #endif // wxUSE_UIACTIONSIMULATOR

View File

@@ -1,6 +1,6 @@
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// Name: src/osx/uiaction_osx.cpp // Name: src/osx/uiaction_osx.cpp
// Purpose: wxUIActionSimulator implementation // Purpose: wxUIActionSimulatorOSXImpl implementation
// Author: Kevin Ollivier, Steven Lamerton, Vadim Zeitlin // Author: Kevin Ollivier, Steven Lamerton, Vadim Zeitlin
// Modified by: // Modified by:
// Created: 2010-03-06 // Created: 2010-03-06
@@ -19,6 +19,7 @@
#if wxUSE_UIACTIONSIMULATOR #if wxUSE_UIACTIONSIMULATOR
#include "wx/uiaction.h" #include "wx/uiaction.h"
#include "wx/private/uiaction.h"
#include "wx/log.h" #include "wx/log.h"
@@ -111,9 +112,38 @@ CGPoint GetMousePosition()
return pos; return pos;
} }
class wxUIActionSimulatorOSXImpl : public wxUIActionSimulatorImpl
{
public:
// Returns a pointer to the global simulator object: as it's stateless, we
// can reuse the same one without having to allocate it on the heap all the
// time.
static wxUIActionSimulatorOSXImpl* Get()
{
static wxUIActionSimulatorOSXImpl s_impl;
return &s_impl;
}
virtual bool MouseMove(long x, long y) wxOVERRIDE;
virtual bool MouseDown(int button = wxMOUSE_BTN_LEFT) wxOVERRIDE;
virtual bool MouseUp(int button = wxMOUSE_BTN_LEFT) wxOVERRIDE;
virtual bool MouseDblClick(int button = wxMOUSE_BTN_LEFT) wxOVERRIDE;
virtual bool MouseDragDrop(long x1, long y1, long x2, long y2,
int button = wxMOUSE_BTN_LEFT) wxOVERRIDE;
virtual bool DoKey(int keycode, int modifiers, bool isDown) wxOVERRIDE;
private:
// This class has no public ctors, use Get() instead.
wxUIActionSimulatorOSXImpl() { }
wxDECLARE_NO_COPY_CLASS(wxUIActionSimulatorOSXImpl);
};
} // anonymous namespace } // anonymous namespace
bool wxUIActionSimulator::MouseDown(int button) bool wxUIActionSimulatorOSXImpl::MouseDown(int button)
{ {
CGEventType type = CGEventTypeForMouseButton(button, true); CGEventType type = CGEventTypeForMouseButton(button, true);
wxCFRef<CGEventRef> event( wxCFRef<CGEventRef> event(
@@ -131,7 +161,7 @@ bool wxUIActionSimulator::MouseDown(int button)
return true; return true;
} }
bool wxUIActionSimulator::MouseMove(long x, long y) bool wxUIActionSimulatorOSXImpl::MouseMove(long x, long y)
{ {
CGPoint pos; CGPoint pos;
pos.x = x; pos.x = x;
@@ -154,7 +184,7 @@ bool wxUIActionSimulator::MouseMove(long x, long y)
return true; return true;
} }
bool wxUIActionSimulator::MouseUp(int button) bool wxUIActionSimulatorOSXImpl::MouseUp(int button)
{ {
CGEventType type = CGEventTypeForMouseButton(button, false); CGEventType type = CGEventTypeForMouseButton(button, false);
wxCFRef<CGEventRef> event( wxCFRef<CGEventRef> event(
@@ -172,7 +202,7 @@ bool wxUIActionSimulator::MouseUp(int button)
return true; return true;
} }
bool wxUIActionSimulator::MouseDblClick(int button) bool wxUIActionSimulatorOSXImpl::MouseDblClick(int button)
{ {
CGEventType downtype = CGEventTypeForMouseButton(button, true); CGEventType downtype = CGEventTypeForMouseButton(button, true);
CGEventType uptype = CGEventTypeForMouseButton(button, false); CGEventType uptype = CGEventTypeForMouseButton(button, false);
@@ -201,7 +231,7 @@ bool wxUIActionSimulator::MouseDblClick(int button)
return true; return true;
} }
bool wxUIActionSimulator::MouseDragDrop(long x1, long y1, long x2, long y2, bool wxUIActionSimulatorOSXImpl::MouseDragDrop(long x1, long y1, long x2, long y2,
int button) int button)
{ {
CGPoint pos1,pos2; CGPoint pos1,pos2;
@@ -241,7 +271,7 @@ bool wxUIActionSimulator::MouseDragDrop(long x1, long y1, long x2, long y2,
} }
bool bool
wxUIActionSimulator::DoKey(int keycode, int WXUNUSED(modifiers), bool isDown) wxUIActionSimulatorOSXImpl::DoKey(int keycode, int WXUNUSED(modifiers), bool isDown)
{ {
CGKeyCode cgcode = wxCharCodeWXToOSX((wxKeyCode)keycode); CGKeyCode cgcode = wxCharCodeWXToOSX((wxKeyCode)keycode);
@@ -258,5 +288,15 @@ wxUIActionSimulator::DoKey(int keycode, int WXUNUSED(modifiers), bool isDown)
return true; return true;
} }
#endif // wxUSE_UIACTIONSIMULATOR wxUIActionSimulator::wxUIActionSimulator()
: m_impl(wxUIActionSimulatorOSXImpl::Get())
{
}
wxUIActionSimulator::~wxUIActionSimulator()
{
// We can use a static wxUIActionSimulatorOSXImpl object because it's
// stateless, so no need to delete it.
}
#endif // wxUSE_UIACTIONSIMULATOR

View File

@@ -12,13 +12,15 @@
#pragma hdrstop #pragma hdrstop
#endif #endif
#include "wx/uiaction.h"
#include "wx/private/uiaction.h"
#include <QtTest/QtTestGui> #include <QtTest/QtTestGui>
#include <QApplication> #include <QApplication>
#include <QWidget> #include <QWidget>
#include "wx/qt/defs.h" #include "wx/qt/defs.h"
#include "wx/qt/private/utils.h" #include "wx/qt/private/utils.h"
#include "wx/uiaction.h"
#include "wx/qt/private/converter.h" #include "wx/qt/private/converter.h"
@@ -37,6 +39,31 @@ inline QWindow* argForEvents(QWidget* w) { return w->windowHandle(); }
inline QWidget* argForEvents(QWidget* w) { return w; } inline QWidget* argForEvents(QWidget* w) { return w; }
#endif #endif
class wxUIActionSimulatorQtImpl : public wxUIActionSimulatorImpl
{
public:
// Returns a pointer to the global simulator object: as it's stateless, we
// can reuse the same one without having to allocate it on the heap all the
// time.
static wxUIActionSimulatorQtImpl* Get()
{
static wxUIActionSimulatorQtImpl s_impl;
return &s_impl;
}
virtual bool MouseMove(long x, long y) wxOVERRIDE;
virtual bool MouseDown(int button = wxMOUSE_BTN_LEFT) wxOVERRIDE;
virtual bool MouseUp(int button = wxMOUSE_BTN_LEFT) wxOVERRIDE;
virtual bool DoKey(int keycode, int modifiers, bool isDown) wxOVERRIDE;
private:
// This class has no public ctors, use Get() instead.
wxUIActionSimulatorQtImpl() { }
wxDECLARE_NO_COPY_CLASS(wxUIActionSimulatorQtImpl);
};
static MouseButton ConvertMouseButton( int button ) static MouseButton ConvertMouseButton( int button )
{ {
MouseButton qtButton; MouseButton qtButton;
@@ -95,24 +122,24 @@ static bool SimulateKeyboardKey( KeyAction keyAction, Key key )
return widget != NULL; return widget != NULL;
} }
bool wxUIActionSimulator::MouseDown( int button ) bool wxUIActionSimulatorQtImpl::MouseDown( int button )
{ {
return SimulateMouseButton( MousePress, ConvertMouseButton( button )); return SimulateMouseButton( MousePress, ConvertMouseButton( button ));
} }
bool wxUIActionSimulator::MouseUp(int button) bool wxUIActionSimulatorQtImpl::MouseUp(int button)
{ {
return SimulateMouseButton( MouseRelease, ConvertMouseButton( button )); return SimulateMouseButton( MouseRelease, ConvertMouseButton( button ));
} }
bool wxUIActionSimulator::MouseMove(long x, long y) bool wxUIActionSimulatorQtImpl::MouseMove(long x, long y)
{ {
QCursor::setPos( x, y ); QCursor::setPos( x, y );
return true; return true;
} }
bool wxUIActionSimulator::DoKey(int keyCode, int modifiers, bool isDown) bool wxUIActionSimulatorQtImpl::DoKey(int keyCode, int modifiers, bool isDown)
{ {
Qt::KeyboardModifiers qtmodifiers; Qt::KeyboardModifiers qtmodifiers;
enum Key key; enum Key key;
@@ -124,5 +151,16 @@ bool wxUIActionSimulator::DoKey(int keyCode, int modifiers, bool isDown)
return SimulateKeyboardKey( keyAction, key ); return SimulateKeyboardKey( keyAction, key );
} }
#endif // wxUSE_UIACTIONSIMULATOR
wxUIActionSimulator::wxUIActionSimulator()
: m_impl(wxUIActionSimulatorQtImpl::Get())
{
}
wxUIActionSimulator::~wxUIActionSimulator()
{
// We can use a static wxUIActionSimulatorQtImpl object because it's
// stateless, so no need to delete it.
}
#endif // wxUSE_UIACTIONSIMULATOR

View File

@@ -2,11 +2,10 @@
// Name: src/unix/uiactionx11.cpp // Name: src/unix/uiactionx11.cpp
// Purpose: wxUIActionSimulator implementation // Purpose: wxUIActionSimulator implementation
// Author: Kevin Ollivier, Steven Lamerton, Vadim Zeitlin // Author: Kevin Ollivier, Steven Lamerton, Vadim Zeitlin
// Modified by:
// Created: 2010-03-06 // Created: 2010-03-06
// Copyright: (c) Kevin Ollivier // Copyright: (c) 2010 Kevin Ollivier
// (c) 2010 Steven Lamerton // (c) 2010 Steven Lamerton
// (c) 2010 Vadim Zeitlin // (c) 2010-2016 Vadim Zeitlin
// Licence: wxWindows licence // Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
@@ -18,16 +17,72 @@
#include "wx/event.h" #include "wx/event.h"
#include "wx/evtloop.h" #include "wx/evtloop.h"
#include "wx/private/uiaction.h"
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <X11/Xutil.h> #include <X11/Xutil.h>
#if wxUSE_XTEST
#include <X11/extensions/XTest.h>
#endif
#include "wx/unix/utilsx11.h" #include "wx/unix/utilsx11.h"
#ifdef __WXGTK3__
#include <gdk/gdk.h>
#include <gtk/gtk.h>
#endif
// Normally we fall back on "plain X" implementation if XTest is not available,
// but it's useless to do it when using GTK+ 3 as it's not going to work with
// it anyhow because GTK+ 3 needs XInput2 events and not the "classic" ones we
// synthesize here, so don't even compile in this code for wxGTK3 port.
#define wxUSE_PLAINX_IMPL (!defined(__WXGTK3__))
namespace namespace
{ {
void SendButtonEvent(int button, bool isDown) // Base class for both available X11 implementations.
class wxUIActionSimulatorX11Impl : public wxUIActionSimulatorImpl
{ {
public:
// Return the most appopriate implementation to use: if XTest is available,
// use it, otherwise use plain X11 calls.
//
// The returned pointer is owned by the caller.
static wxUIActionSimulatorImpl* New();
virtual bool MouseMove(long x, long y) wxOVERRIDE;
virtual bool MouseDown(int button = wxMOUSE_BTN_LEFT) wxOVERRIDE;
virtual bool MouseUp(int button = wxMOUSE_BTN_LEFT) wxOVERRIDE;
virtual bool DoKey(int keycode, int modifiers, bool isDown) wxOVERRIDE;
protected:
// This ctor takes ownership of the display.
explicit wxUIActionSimulatorX11Impl(wxX11Display& display)
: m_display(display)
{
}
wxX11Display m_display;
private:
// Common implementation of Mouse{Down,Up}() which just forwards to
// DoX11Button() after translating wx button to X button constant.
bool SendButtonEvent(int button, bool isDown);
virtual bool DoX11Button(int xbutton, bool isDown) = 0;
virtual bool DoX11MouseMove(long x, long y) = 0;
virtual bool DoX11Key(KeyCode xkeycode, int modifiers, bool isDown) = 0;
wxDECLARE_NO_COPY_CLASS(wxUIActionSimulatorX11Impl);
};
bool wxUIActionSimulatorX11Impl::SendButtonEvent(int button, bool isDown)
{
if ( !m_display )
return false;
int xbutton; int xbutton;
switch (button) switch (button)
{ {
@@ -42,12 +97,37 @@ void SendButtonEvent(int button, bool isDown)
break; break;
default: default:
wxFAIL_MSG("Unsupported button passed in."); wxFAIL_MSG("Unsupported button passed in.");
return; return false;
} }
wxX11Display display; // Ensure that the event is received by the correct window by processing
wxCHECK_RET(display, "No display available!"); // all pending events, notably mouse moves.
XSync(m_display, False /* don't discard */);
return DoX11Button(xbutton, isDown);
}
#if wxUSE_PLAINX_IMPL
// Implementation using just plain X11 calls.
class wxUIActionSimulatorPlainX11Impl : public wxUIActionSimulatorX11Impl
{
public:
explicit wxUIActionSimulatorPlainX11Impl(wxX11Display& display)
: wxUIActionSimulatorX11Impl(display)
{
}
private:
virtual bool DoX11Button(int xbutton, bool isDown) wxOVERRIDE;
virtual bool DoX11MouseMove(long x, long y) wxOVERRIDE;
virtual bool DoX11Key(KeyCode xkeycode, int modifiers, bool isDown) wxOVERRIDE;
wxDECLARE_NO_COPY_CLASS(wxUIActionSimulatorPlainX11Impl);
};
bool wxUIActionSimulatorPlainX11Impl::DoX11Button(int xbutton, bool isDown)
{
XEvent event; XEvent event;
memset(&event, 0x00, sizeof(event)); memset(&event, 0x00, sizeof(event));
@@ -55,7 +135,7 @@ void SendButtonEvent(int button, bool isDown)
event.xbutton.button = xbutton; event.xbutton.button = xbutton;
event.xbutton.same_screen = True; event.xbutton.same_screen = True;
XQueryPointer(display, display.DefaultRoot(), XQueryPointer(m_display, m_display.DefaultRoot(),
&event.xbutton.root, &event.xbutton.window, &event.xbutton.root, &event.xbutton.window,
&event.xbutton.x_root, &event.xbutton.y_root, &event.xbutton.x_root, &event.xbutton.y_root,
&event.xbutton.x, &event.xbutton.y, &event.xbutton.state); &event.xbutton.x, &event.xbutton.y, &event.xbutton.state);
@@ -64,54 +144,29 @@ void SendButtonEvent(int button, bool isDown)
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, XQueryPointer(m_display, event.xbutton.window,
&event.xbutton.root, &event.xbutton.subwindow, &event.xbutton.root, &event.xbutton.subwindow,
&event.xbutton.x_root, &event.xbutton.y_root, &event.xbutton.x_root, &event.xbutton.y_root,
&event.xbutton.x, &event.xbutton.y, &event.xbutton.state); &event.xbutton.x, &event.xbutton.y, &event.xbutton.state);
} }
XSendEvent(display, PointerWindow, True, 0xfff, &event); XSendEvent(m_display, PointerWindow, True, 0xfff, &event);
}
} // anonymous namespace
bool wxUIActionSimulator::MouseDown(int button)
{
SendButtonEvent(button, true);
return true;
}
bool wxUIActionSimulator::MouseMove(long x, long y)
{
wxX11Display display;
wxASSERT_MSG(display, "No display available!");
Window root = display.DefaultRoot();
XWarpPointer(display, None, root, 0, 0, 0, 0, x, y);
// At least with wxGTK we must always process the pending events before the
// mouse position change really takes effect, so just do it from here
// instead of forcing the client code using this function to always use
// wxYield() which is unnecessary under the other platforms.
if ( wxEventLoopBase* const loop = wxEventLoop::GetActive() )
{
loop->YieldFor(wxEVT_CATEGORY_USER_INPUT);
}
return true; return true;
} }
bool wxUIActionSimulator::MouseUp(int button) bool wxUIActionSimulatorPlainX11Impl::DoX11MouseMove(long x, long y)
{ {
SendButtonEvent(button, false); Window root = m_display.DefaultRoot();
XWarpPointer(m_display, None, root, 0, 0, 0, 0, x, y);
return true; return true;
} }
bool wxUIActionSimulator::DoKey(int keycode, int modifiers, bool isDown) bool
wxUIActionSimulatorPlainX11Impl::DoX11Key(KeyCode xkeycode,
int modifiers,
bool isDown)
{ {
wxX11Display display;
wxCHECK_MSG(display, false, "No display available!");
int mask, type; int mask, type;
if ( isDown ) if ( isDown )
@@ -125,14 +180,9 @@ bool wxUIActionSimulator::DoKey(int keycode, int modifiers, bool isDown)
mask = KeyReleaseMask; mask = KeyReleaseMask;
} }
WXKeySym xkeysym = wxCharCodeWXToX(keycode);
KeyCode xkeycode = XKeysymToKeycode(display, xkeysym);
if ( xkeycode == NoSymbol )
return false;
Window focus; Window focus;
int revert; int revert;
XGetInputFocus(display, &focus, &revert); XGetInputFocus(m_display, &focus, &revert);
if (focus == None) if (focus == None)
return false; return false;
@@ -147,7 +197,7 @@ bool wxUIActionSimulator::DoKey(int keycode, int modifiers, bool isDown)
mod |= ControlMask; mod |= ControlMask;
XKeyEvent event; XKeyEvent event;
event.display = display; event.display = m_display;
event.window = focus; event.window = focus;
event.root = DefaultRootWindow(event.display); event.root = DefaultRootWindow(event.display);
event.subwindow = None; event.subwindow = None;
@@ -166,4 +216,141 @@ bool wxUIActionSimulator::DoKey(int keycode, int modifiers, bool isDown)
return true; return true;
} }
#endif // wxUSE_PLAINX_IMPL
#if wxUSE_XTEST
// Implementation using XTest extension.
class wxUIActionSimulatorXTestImpl : public wxUIActionSimulatorX11Impl
{
public:
explicit wxUIActionSimulatorXTestImpl(wxX11Display& display)
: wxUIActionSimulatorX11Impl(display)
{
}
private:
virtual bool DoX11Button(int xbutton, bool isDown) wxOVERRIDE;
virtual bool DoX11MouseMove(long x, long y) wxOVERRIDE;
virtual bool DoX11Key(KeyCode xkeycode, int modifiers, bool isDown) wxOVERRIDE;
wxDECLARE_NO_COPY_CLASS(wxUIActionSimulatorXTestImpl);
};
bool wxUIActionSimulatorXTestImpl::DoX11Button(int xbutton, bool isDown)
{
return XTestFakeButtonEvent(m_display, xbutton, isDown, 0) != 0;
}
bool wxUIActionSimulatorXTestImpl::DoX11MouseMove(long x, long y)
{
#ifdef __WXGTK3__
// We need to take into account the scaling factor as the input coordinates
// are in GTK logical "application pixels", while we need the physical
// "device pixels" for the X call below, so scale them if we have the
// required support at both compile- and run-time.
#if GTK_CHECK_VERSION(3,10,0)
if ( gtk_check_version(3, 10, 0) == NULL )
{
if ( GdkScreen* const screen = gdk_screen_get_default() )
{
// For multi-monitor support we would need to determine to which
// monitor the point (x, y) belongs, for now just use the scale
// factor of the main one.
gint const scale = gdk_screen_get_monitor_scale_factor(screen, 0);
x *= scale;
y *= scale;
}
}
#endif // GTK+ 3.10+
#endif // __WXGTK3__
return XTestFakeMotionEvent(m_display, -1, x, y, 0) != 0;
}
bool
wxUIActionSimulatorXTestImpl::DoX11Key(KeyCode xkeycode,
int WXUNUSED(modifiers),
bool isDown)
{
return XTestFakeKeyEvent(m_display, xkeycode, isDown, 0) != 0;
}
#endif // wxUSE_XTEST
wxUIActionSimulatorImpl* wxUIActionSimulatorX11Impl::New()
{
wxX11Display display;
#if wxUSE_XTEST
// If we can fall back on plain X implementation, check if XTest extension
// is available and if it isn't, use the other one. OTOH if we don't have
// the other one anyhow, then testing for XTest availability is useless.
#if wxUSE_PLAINX_IMPL
int dummy;
if ( XTestQueryExtension(display, &dummy, &dummy, &dummy, &dummy) )
#endif // wxUSE_PLAINX_IMPL
return new wxUIActionSimulatorXTestImpl(display);
#endif // wxUSE_XTEST
#if wxUSE_PLAINX_IMPL
return new wxUIActionSimulatorPlainX11Impl(display);
#endif // wxUSE_PLAINX_IMPL
}
} // anonymous namespace
bool wxUIActionSimulatorX11Impl::MouseDown(int button)
{
return SendButtonEvent(button, true);
}
bool wxUIActionSimulatorX11Impl::MouseMove(long x, long y)
{
if ( !m_display )
return false;
if ( !DoX11MouseMove(x, y) )
return false;
// At least with wxGTK we must always process the pending events before the
// mouse position change really takes effect, so just do it from here
// instead of forcing the client code using this function to always use
// wxYield() which is unnecessary under the other platforms.
if ( wxEventLoopBase* const loop = wxEventLoop::GetActive() )
{
loop->YieldFor(wxEVT_CATEGORY_USER_INPUT);
}
return true;
}
bool wxUIActionSimulatorX11Impl::MouseUp(int button)
{
return SendButtonEvent(button, false);
}
bool wxUIActionSimulatorX11Impl::DoKey(int keycode, int modifiers, bool isDown)
{
if ( !m_display )
return false;
WXKeySym xkeysym = wxCharCodeWXToX(keycode);
KeyCode xkeycode = XKeysymToKeycode(m_display, xkeysym);
if ( xkeycode == NoSymbol )
return false;
return DoX11Key(xkeycode, modifiers, isDown);
}
wxUIActionSimulator::wxUIActionSimulator()
: m_impl(wxUIActionSimulatorX11Impl::New())
{
}
wxUIActionSimulator::~wxUIActionSimulator()
{
delete m_impl;
}
#endif // wxUSE_UIACTIONSIMULATOR #endif // wxUSE_UIACTIONSIMULATOR