aboutsummaryrefslogtreecommitdiffstats
path: root/vncviewer/XInputTouchHandler.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'vncviewer/XInputTouchHandler.cxx')
-rw-r--r--vncviewer/XInputTouchHandler.cxx163
1 files changed, 146 insertions, 17 deletions
diff --git a/vncviewer/XInputTouchHandler.cxx b/vncviewer/XInputTouchHandler.cxx
index f64b06ad..359802ea 100644
--- a/vncviewer/XInputTouchHandler.cxx
+++ b/vncviewer/XInputTouchHandler.cxx
@@ -26,9 +26,14 @@
#include <X11/extensions/XInput2.h>
#include <X11/extensions/XI2.h>
+#include <X11/XKBlib.h>
#include <FL/x.H>
+#ifndef XK_MISCELLANY
+#define XK_MISCELLANY
+#include <rfb/keysymdef.h>
+#endif
#include <rfb/LogWriter.h>
#include "i18n.h"
@@ -39,7 +44,7 @@ static rfb::LogWriter vlog("XInputTouchHandler");
static bool grabbed = false;
XInputTouchHandler::XInputTouchHandler(Window wnd)
- : wnd(wnd), fakeStateMask(0), trackingTouch(false)
+ : wnd(wnd), fakeStateMask(0)
{
XIEventMask eventmask;
unsigned char flags[XIMaskLen(XI_LASTEVENT)] = { 0 };
@@ -232,9 +237,6 @@ void XInputTouchHandler::processEvent(const XIDeviceEvent* devev)
fakeButtonEvent(false, devev->detail, devev);
break;
case XI_TouchBegin:
- if (trackingTouch)
- break;
-
// XInput2 wants us to explicitly accept touch sequences
// for grabbed devices before it will pass events
if (grabbed) {
@@ -245,22 +247,13 @@ void XInputTouchHandler::processEvent(const XIDeviceEvent* devev)
XIAcceptTouch);
}
- trackingTouch = true;
- trackedTouchPoint = devev->detail;
-
- fakeMotionEvent(devev);
- fakeButtonEvent(true, Button1, devev);
+ handleTouchBegin(devev->detail, devev->event_x, devev->event_y);
break;
case XI_TouchUpdate:
- if (!trackingTouch || (devev->detail != trackedTouchPoint))
- break;
- fakeMotionEvent(devev);
+ handleTouchUpdate(devev->detail, devev->event_x, devev->event_y);
break;
case XI_TouchEnd:
- if (!trackingTouch || (devev->detail != trackedTouchPoint))
- break;
- fakeButtonEvent(false, Button1, devev);
- trackingTouch = false;
+ handleTouchEnd(devev->detail);
break;
case XI_TouchOwnership:
// FIXME: Currently ignored, see constructor
@@ -297,13 +290,76 @@ void XInputTouchHandler::fakeMotionEvent(const XIDeviceEvent* origEvent)
fakeEvent.xmotion.is_hint = False;
preparePointerEvent(&fakeEvent, origEvent);
+ pushFakeEvent(&fakeEvent);
+}
+
+void XInputTouchHandler::fakeButtonEvent(bool press, int button,
+ const XIDeviceEvent* origEvent)
+{
+ XEvent fakeEvent;
+
+ memset(&fakeEvent, 0, sizeof(XEvent));
+
+ fakeEvent.type = press ? ButtonPress : ButtonRelease;
+ fakeEvent.xbutton.button = button;
+
+ // Apply the fake mask before pushing so it will be in sync
+ fakeEvent.xbutton.state |= fakeStateMask;
+ preparePointerEvent(&fakeEvent, origEvent);
+
+ pushFakeEvent(&fakeEvent);
+}
+
+void XInputTouchHandler::preparePointerEvent(XEvent* dst, const GestureEvent src)
+{
+ Window root, child;
+ int rootX, rootY;
+ XkbStateRec state;
+
+ // We don't have a real event to steal things from, so we'll have
+ // to fake these events based on the current state of things
+
+ root = XDefaultRootWindow(fl_display);
+ XTranslateCoordinates(fl_display, wnd, root,
+ src.eventX,
+ src.eventY,
+ &rootX, &rootY, &child);
+ XkbGetState(fl_display, XkbUseCoreKbd, &state);
+
+ // XButtonEvent and XMotionEvent are almost identical, so we
+ // don't have to care which it is for these fields
+ dst->xbutton.serial = XLastKnownRequestProcessed(fl_display);
+ dst->xbutton.display = fl_display;
+ dst->xbutton.window = wnd;
+ dst->xbutton.root = root;
+ dst->xbutton.subwindow = None;
+ dst->xbutton.time = fl_event_time;
+ dst->xbutton.x = src.eventX;
+ dst->xbutton.y = src.eventY;
+ dst->xbutton.x_root = rootX;
+ dst->xbutton.y_root = rootY;
+ dst->xbutton.state = state.mods;
+ dst->xbutton.state |= ((state.ptr_buttons >> 1) & 0x1f) << 8;
+ dst->xbutton.same_screen = True;
+}
+
+void XInputTouchHandler::fakeMotionEvent(const GestureEvent origEvent)
+{
+ XEvent fakeEvent;
+
+ memset(&fakeEvent, 0, sizeof(XEvent));
+
+ fakeEvent.type = MotionNotify;
+ fakeEvent.xmotion.is_hint = False;
+ preparePointerEvent(&fakeEvent, origEvent);
+
fakeEvent.xbutton.state |= fakeStateMask;
pushFakeEvent(&fakeEvent);
}
void XInputTouchHandler::fakeButtonEvent(bool press, int button,
- const XIDeviceEvent* origEvent)
+ const GestureEvent origEvent)
{
XEvent fakeEvent;
@@ -315,6 +371,8 @@ void XInputTouchHandler::fakeButtonEvent(bool press, int button,
fakeEvent.xbutton.state |= fakeStateMask;
+ // The button mask should indicate the button state just prior to
+ // the event, we update the button mask after pushing
pushFakeEvent(&fakeEvent);
// Set/unset the bit for the correct button
@@ -325,6 +383,77 @@ void XInputTouchHandler::fakeButtonEvent(bool press, int button,
}
}
+void XInputTouchHandler::fakeKeyEvent(bool press, int keysym,
+ const GestureEvent origEvent)
+{
+ XEvent fakeEvent;
+
+ Window root, child;
+ int rootX, rootY;
+ XkbStateRec state;
+
+ int modmask;
+
+ root = XDefaultRootWindow(fl_display);
+ XTranslateCoordinates(fl_display, wnd, root,
+ origEvent.eventX,
+ origEvent.eventY,
+ &rootX, &rootY, &child);
+ XkbGetState(fl_display, XkbUseCoreKbd, &state);
+
+ KeyCode kc = XKeysymToKeycode(fl_display, keysym);
+
+ memset(&fakeEvent, 0, sizeof(XEvent));
+
+ fakeEvent.type = press ? KeyPress : KeyRelease;
+ fakeEvent.xkey.type = press ? KeyPress : KeyRelease;
+ fakeEvent.xkey.keycode = kc;
+ fakeEvent.xkey.serial = XLastKnownRequestProcessed(fl_display);
+ fakeEvent.xkey.display = fl_display;
+ fakeEvent.xkey.window = wnd;
+ fakeEvent.xkey.root = root;
+ fakeEvent.xkey.subwindow = None;
+ fakeEvent.xkey.time = fl_event_time;
+ fakeEvent.xkey.x = origEvent.eventX;
+ fakeEvent.xkey.y = origEvent.eventY;
+ fakeEvent.xkey.x_root = rootX;
+ fakeEvent.xkey.y_root = rootY;
+ fakeEvent.xkey.state = state.mods;
+ fakeEvent.xkey.state |= ((state.ptr_buttons >> 1) & 0x1f) << 8;
+ fakeEvent.xkey.same_screen = True;
+
+ // Apply our fake mask
+ fakeEvent.xkey.state |= fakeStateMask;
+
+ pushFakeEvent(&fakeEvent);
+
+ switch(keysym) {
+ case XK_Shift_L:
+ case XK_Shift_R:
+ modmask = ShiftMask;
+ break;
+ case XK_Caps_Lock:
+ modmask = LockMask;
+ break;
+ case XK_Control_L:
+ case XK_Control_R:
+ modmask = ControlMask;
+ break;
+ default:
+ modmask = 0;
+ }
+
+ if (press)
+ fakeStateMask |= modmask;
+ else
+ fakeStateMask &= ~modmask;
+}
+
+void XInputTouchHandler::handleGestureEvent(const GestureEvent& event)
+{
+ BaseTouchHandler::handleGestureEvent(event);
+}
+
void XInputTouchHandler::pushFakeEvent(XEvent* event)
{
// Perhaps use XPutBackEvent() to avoid round trip latency?