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:
@@ -30,10 +30,15 @@
|
|||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// Base class for both available X11 implementations.
|
||||||
class wxUIActionSimulatorX11Impl : public wxUIActionSimulatorImpl
|
class wxUIActionSimulatorX11Impl : public wxUIActionSimulatorImpl
|
||||||
{
|
{
|
||||||
public:
|
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 MouseMove(long x, long y) wxOVERRIDE;
|
||||||
virtual bool MouseDown(int button = wxMOUSE_BTN_LEFT) 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;
|
virtual bool DoKey(int keycode, int modifiers, bool isDown) wxOVERRIDE;
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
// Common implementation of Mouse{Down,Up}()
|
// This ctor takes ownership of the display.
|
||||||
bool SendButtonEvent(int button, bool isDown);
|
explicit wxUIActionSimulatorX11Impl(wxX11Display& display)
|
||||||
|
: m_display(display)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
wxX11Display m_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);
|
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)
|
bool wxUIActionSimulatorX11Impl::SendButtonEvent(int button, bool isDown)
|
||||||
{
|
{
|
||||||
if ( !m_display )
|
if ( !m_display )
|
||||||
@@ -72,10 +106,11 @@ bool wxUIActionSimulatorX11Impl::SendButtonEvent(int button, bool isDown)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if wxUSE_XTEST
|
return DoX11Button(xbutton, isDown);
|
||||||
XTestFakeButtonEvent(m_display, xbutton, isDown, 0);
|
}
|
||||||
|
|
||||||
#else // !wxUSE_XTEST
|
bool wxUIActionSimulatorPlainX11Impl::DoX11Button(int xbutton, bool isDown)
|
||||||
|
{
|
||||||
XEvent event;
|
XEvent event;
|
||||||
memset(&event, 0x00, sizeof(event));
|
memset(&event, 0x00, sizeof(event));
|
||||||
|
|
||||||
@@ -99,53 +134,22 @@ bool wxUIActionSimulatorX11Impl::SendButtonEvent(int button, bool isDown)
|
|||||||
}
|
}
|
||||||
|
|
||||||
XSendEvent(m_display, PointerWindow, True, 0xfff, &event);
|
XSendEvent(m_display, PointerWindow, True, 0xfff, &event);
|
||||||
#endif // !wxUSE_XTEST
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // anonymous namespace
|
bool wxUIActionSimulatorPlainX11Impl::DoX11MouseMove(long x, long y)
|
||||||
|
|
||||||
bool wxUIActionSimulatorX11Impl::MouseDown(int button)
|
|
||||||
{
|
{
|
||||||
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();
|
Window root = m_display.DefaultRoot();
|
||||||
XWarpPointer(m_display, None, root, 0, 0, 0, 0, x, y);
|
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;
|
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;
|
int mask, type;
|
||||||
|
|
||||||
if ( isDown )
|
if ( isDown )
|
||||||
@@ -159,19 +163,6 @@ bool wxUIActionSimulatorX11Impl::DoKey(int keycode, int modifiers, bool isDown)
|
|||||||
mask = KeyReleaseMask;
|
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;
|
Window focus;
|
||||||
int revert;
|
int revert;
|
||||||
XGetInputFocus(m_display, &focus, &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);
|
XSendEvent(event.display, event.window, True, mask, (XEvent*) &event);
|
||||||
|
|
||||||
return true;
|
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()
|
wxUIActionSimulator::wxUIActionSimulator()
|
||||||
: m_impl(new wxUIActionSimulatorX11Impl())
|
: m_impl(wxUIActionSimulatorX11Impl::New())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user