aboutsummaryrefslogtreecommitdiffstats
path: root/vncviewer/BaseTouchHandler.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'vncviewer/BaseTouchHandler.cxx')
-rw-r--r--vncviewer/BaseTouchHandler.cxx198
1 files changed, 198 insertions, 0 deletions
diff --git a/vncviewer/BaseTouchHandler.cxx b/vncviewer/BaseTouchHandler.cxx
new file mode 100644
index 00000000..ad27ffde
--- /dev/null
+++ b/vncviewer/BaseTouchHandler.cxx
@@ -0,0 +1,198 @@
+/* Copyright 2019 Aaron Sowry for Cendio AB
+ * Copyright 2019-2020 Pierre Ossman for Cendio AB
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <math.h>
+
+#define XK_MISCELLANY
+#include <rfb/keysymdef.h>
+#include <rfb/util.h>
+
+#include "GestureHandler.h"
+#include "BaseTouchHandler.h"
+
+// Sensitivity threshold for gestures
+static const int ZOOMSENS = 30;
+static const int SCRLSENS = 50;
+
+static const unsigned DOUBLE_TAP_TIMEOUT = 1000;
+static const unsigned DOUBLE_TAP_THRESHOLD = 50;
+
+BaseTouchHandler::BaseTouchHandler()
+{
+ gettimeofday(&lastTapTime, NULL);
+}
+
+BaseTouchHandler::~BaseTouchHandler()
+{
+}
+
+void BaseTouchHandler::handleGestureEvent(const GestureEvent& ev)
+{
+ double magnitude;
+
+ switch (ev.type) {
+ case GestureBegin:
+ switch (ev.gesture) {
+ case GestureOneTap:
+ handleTapEvent(ev, 1);
+ break;
+ case GestureTwoTap:
+ handleTapEvent(ev, 3);
+ break;
+ case GestureThreeTap:
+ handleTapEvent(ev, 2);
+ break;
+ case GestureDrag:
+ fakeMotionEvent(ev);
+ fakeButtonEvent(true, 1, ev);
+ break;
+ case GestureLongPress:
+ fakeMotionEvent(ev);
+ fakeButtonEvent(true, 3, ev);
+ break;
+ case GestureTwoDrag:
+ lastMagnitudeX = ev.magnitudeX;
+ lastMagnitudeY = ev.magnitudeY;
+ fakeMotionEvent(ev);
+ break;
+ case GesturePinch:
+ lastMagnitudeX = sqrt(ev.magnitudeX * ev.magnitudeX +
+ ev.magnitudeY * ev.magnitudeY);
+ fakeMotionEvent(ev);
+ break;
+ }
+ break;
+
+ case GestureUpdate:
+ switch (ev.gesture) {
+ case GestureOneTap:
+ case GestureTwoTap:
+ case GestureThreeTap:
+ break;
+ case GestureDrag:
+ case GestureLongPress:
+ fakeMotionEvent(ev);
+ break;
+ case GestureTwoDrag:
+ // Always scroll in the same position.
+ // We don't know if the mouse was moved so we need to move it
+ // every update.
+ fakeMotionEvent(ev);
+ while ((ev.magnitudeY - lastMagnitudeY) > SCRLSENS) {
+ fakeButtonEvent(true, 4, ev);
+ fakeButtonEvent(false, 4, ev);
+ lastMagnitudeY += SCRLSENS;
+ }
+ while ((ev.magnitudeY - lastMagnitudeY) < -SCRLSENS) {
+ fakeButtonEvent(true, 5, ev);
+ fakeButtonEvent(false, 5, ev);
+ lastMagnitudeY -= SCRLSENS;
+ }
+ while ((ev.magnitudeX - lastMagnitudeX) > SCRLSENS) {
+ fakeButtonEvent(true, 6, ev);
+ fakeButtonEvent(false, 6, ev);
+ lastMagnitudeX += SCRLSENS;
+ }
+ while ((ev.magnitudeX - lastMagnitudeX) < -SCRLSENS) {
+ fakeButtonEvent(true, 7, ev);
+ fakeButtonEvent(false, 7, ev);
+ lastMagnitudeX -= SCRLSENS;
+ }
+ break;
+ case GesturePinch:
+ // Always scroll in the same position.
+ // We don't know if the mouse was moved so we need to move it
+ // every update.
+ fakeMotionEvent(ev);
+ magnitude = sqrt(ev.magnitudeX * ev.magnitudeX +
+ ev.magnitudeY * ev.magnitudeY);
+ if (abs(magnitude - lastMagnitudeX) > ZOOMSENS) {
+ fakeKeyEvent(true, XK_Control_L, ev);
+
+ while ((magnitude - lastMagnitudeX) > ZOOMSENS) {
+ fakeButtonEvent(true, 4, ev);
+ fakeButtonEvent(false, 4, ev);
+ lastMagnitudeX += ZOOMSENS;
+ }
+ while ((magnitude - lastMagnitudeX) < -ZOOMSENS) {
+ fakeButtonEvent(true, 5, ev);
+ fakeButtonEvent(false, 5, ev);
+ lastMagnitudeX -= ZOOMSENS;
+ }
+
+ fakeKeyEvent(false, XK_Control_L, ev);
+ }
+ }
+ break;
+
+ case GestureEnd:
+ switch (ev.gesture) {
+ case GestureOneTap:
+ case GestureTwoTap:
+ case GestureThreeTap:
+ case GesturePinch:
+ case GestureTwoDrag:
+ break;
+ case GestureDrag:
+ fakeMotionEvent(ev);
+ fakeButtonEvent(false, 1, ev);
+ break;
+ case GestureLongPress:
+ fakeMotionEvent(ev);
+ fakeButtonEvent(false, 3, ev);
+ break;
+ }
+ break;
+ }
+}
+
+void BaseTouchHandler::handleTapEvent(const GestureEvent& ev,
+ int buttonEvent)
+{
+ GestureEvent newEv = ev;
+
+ // If the user quickly taps multiple times we assume they meant to
+ // hit the same spot, so slightly adjust coordinates
+ if ((rfb::msSince(&lastTapTime) < DOUBLE_TAP_TIMEOUT) &&
+ (firstDoubleTapEvent.type == ev.type)) {
+
+ double dx = firstDoubleTapEvent.eventX - ev.eventX;
+ double dy = firstDoubleTapEvent.eventY - ev.eventY;
+ double distance = sqrt((dx * dx) + (dy * dy));
+
+ if (distance < DOUBLE_TAP_THRESHOLD) {
+ newEv.eventX = firstDoubleTapEvent.eventX;
+ newEv.eventY = firstDoubleTapEvent.eventY;
+ } else {
+ firstDoubleTapEvent = ev;
+ }
+ } else {
+ firstDoubleTapEvent = ev;
+ }
+ gettimeofday(&lastTapTime, NULL);
+
+ fakeMotionEvent(newEv);
+ fakeButtonEvent(true, buttonEvent, newEv);
+ fakeButtonEvent(false, buttonEvent, newEv);
+}