Determine wxUIActionSimulatorX11Impl version to use dynamically

Choose between wxUIActionSimulatorXTestImpl and
wxUIActionSimulatorPlainX11Impl dynamically, depending on whether XTest
extension is available during run-time or not.

Also decouple the two implementation to keep them clearly separated.
This commit is contained in:
Vadim Zeitlin
2016-05-22 00:22:08 +02:00
parent 4a0938d2b7
commit 7cf5804465

View File

@@ -30,10 +30,15 @@
namespace
{
// Base class for both available X11 implementations.
class wxUIActionSimulatorX11Impl : public wxUIActionSimulatorImpl
{
public:
wxUIActionSimulatorX11Impl() { }
// 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;
@@ -41,15 +46,44 @@ public:
virtual bool DoKey(int keycode, int modifiers, bool isDown) wxOVERRIDE;
private:
// Common implementation of Mouse{Down,Up}()
bool SendButtonEvent(int button, bool isDown);
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);
};
// 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 wxUIActionSimulatorX11Impl::SendButtonEvent(int button, bool isDown)
{
if ( !m_display )
@@ -72,10 +106,11 @@ bool wxUIActionSimulatorX11Impl::SendButtonEvent(int button, bool isDown)
return false;
}
#if wxUSE_XTEST
XTestFakeButtonEvent(m_display, xbutton, isDown, 0);
return DoX11Button(xbutton, isDown);
}
#else // !wxUSE_XTEST
bool wxUIActionSimulatorPlainX11Impl::DoX11Button(int xbutton, bool isDown)
{
XEvent event;
memset(&event, 0x00, sizeof(event));
@@ -99,53 +134,22 @@ bool wxUIActionSimulatorX11Impl::SendButtonEvent(int button, bool isDown)
}
XSendEvent(m_display, PointerWindow, True, 0xfff, &event);
#endif // !wxUSE_XTEST
return true;
}
} // anonymous namespace
bool wxUIActionSimulatorX11Impl::MouseDown(int button)
bool wxUIActionSimulatorPlainX11Impl::DoX11MouseMove(long x, long y)
{
return SendButtonEvent(button, true);
}
bool wxUIActionSimulatorX11Impl::MouseMove(long x, long y)
{
if ( !m_display )
return false;
#if wxUSE_XTEST
XTestFakeMotionEvent(m_display, -1, x, y, 0);
#else // !wxUSE_XTEST
Window root = m_display.DefaultRoot();
XWarpPointer(m_display, None, root, 0, 0, 0, 0, x, y);
#endif // !wxUSE_XTEST
// 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)
bool
wxUIActionSimulatorPlainX11Impl::DoX11Key(KeyCode xkeycode,
int modifiers,
bool isDown)
{
return SendButtonEvent(button, false);
}
bool wxUIActionSimulatorX11Impl::DoKey(int keycode, int modifiers, bool isDown)
{
if ( !m_display )
return false;
int mask, type;
if ( isDown )
@@ -159,19 +163,6 @@ bool wxUIActionSimulatorX11Impl::DoKey(int keycode, int modifiers, bool isDown)
mask = KeyReleaseMask;
}
WXKeySym xkeysym = wxCharCodeWXToX(keycode);
KeyCode xkeycode = XKeysymToKeycode(m_display, xkeysym);
if ( xkeycode == NoSymbol )
return false;
#if wxUSE_XTEST
wxUnusedVar(modifiers);
wxUnusedVar(mask);
wxUnusedVar(type);
XTestFakeKeyEvent(m_display, xkeycode, isDown, 0);
return true;
#else // !wxUSE_XTEST
Window focus;
int revert;
XGetInputFocus(m_display, &focus, &revert);
@@ -206,11 +197,107 @@ bool wxUIActionSimulatorX11Impl::DoKey(int keycode, int modifiers, bool isDown)
XSendEvent(event.display, event.window, True, mask, (XEvent*) &event);
return true;
#endif // !wxUSE_XTEST
}
#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)
{
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
int dummy;
if ( XTestQueryExtension(display, &dummy, &dummy, &dummy, &dummy) )
return new wxUIActionSimulatorXTestImpl(display);
#endif // wxUSE_XTEST
return new wxUIActionSimulatorPlainX11Impl(display);
}
} // 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(new wxUIActionSimulatorX11Impl())
: m_impl(wxUIActionSimulatorX11Impl::New())
{
}