Adds a new MULTITOUCH gesture mode that will redirect all in-contact
touches through the new multitouch code available in XI2.2 (ABI >= 16).

MULTITOUCH mode will only be entered when in-driver gestures have been
disabled and at least two fingers are present. The driver will remain
in this mode until *all* fingers have left the tablet.

For the moment, all touches are sent as XIDependentTouch. Direct touch
devices such as tablet PCs and Cintiqs are not an exception. This may
be changed in the future once frameworks are better equipped to handle
direct input touches.

Signed-off-by: Jason Gerecke <killert...@gmail.com>
---
 man/wacom.man        |  5 +--
 src/wcmTouchFilter.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/xf86Wacom.c      |  8 +++++
 src/xf86WacomDefs.h  |  6 ++--
 4 files changed, 109 insertions(+), 4 deletions(-)

diff --git a/man/wacom.man b/man/wacom.man
index 0502860..4438cc5 100644
--- a/man/wacom.man
+++ b/man/wacom.man
@@ -232,8 +232,9 @@ The threshold applies to the normalised pressure range of 
[0..2048].
 The default is 27.
 .TP 4
 .B Option \fI"Gesture"\fP \fI"bool"\fP
-Enable or disable gesture support on the device. Default: off unless the
-tablet supports multi-touch.
+Enable or disable in-driver gesture support on the device. Default: off unless 
the
+tablet supports multi-touch. Note that disabling this option may allow the 
desktop
+environment to detect gestures instead.
 .TP 4
 .B Option \fI"ZoomDistance"\fP \fI"number"\fP
 If
diff --git a/src/wcmTouchFilter.c b/src/wcmTouchFilter.c
index 41a9a74..b859973 100644
--- a/src/wcmTouchFilter.c
+++ b/src/wcmTouchFilter.c
@@ -37,12 +37,14 @@
 #define GESTURE_LAG_MODE              8
 #define GESTURE_PREDRAG_MODE         16
 #define GESTURE_DRAG_MODE            32
+#define GESTURE_MULTITOUCH_MODE      64
 
 #define WCM_SCROLL_UP                 5        /* vertical up */
 #define WCM_SCROLL_DOWN               4        /* vertical down */
 #define WCM_SCROLL_LEFT               6        /* horizontal left */
 #define WCM_SCROLL_RIGHT              7        /* horizontal right */
 
+static void wcmSendButtonClick(WacomDevicePtr priv, int button, int state);
 static void wcmFingerScroll(WacomDevicePtr priv);
 static void wcmFingerZoom(WacomDevicePtr priv);
 
@@ -95,6 +97,87 @@ static void getStateHistory(WacomCommonPtr common, 
WacomDeviceState states[], in
        }
 }
 
+/**
+ * Send a touch event for the provided contact ID. This makes use of
+ * the multitouch API available in XI2.2.
+ *
+ * @param[in] priv
+ * @param[in] channel    Channel to send a touch event for
+ * @param[in] no_update  If 'true', TouchUpdate events will not be created.
+ * This should be used when entering multitouch mode to ensure TouchBegin
+ * events are sent for already-in-prox contacts.
+ */
+static void
+wcmSendTouchEvent(WacomDevicePtr priv, WacomChannelPtr channel, Bool no_update)
+{
+#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 16
+       ValuatorMask *mask = priv->common->touch_mask;
+       WacomDeviceState state = channel->valid.state;
+       WacomDeviceState oldstate = channel->valid.states[1];
+       int type = -1;
+
+       valuator_mask_set(mask, 0, state.x);
+       valuator_mask_set(mask, 1, state.y);
+
+       if (!state.proximity) {
+               DBG(6, priv->common, "This is a touch end event\n");
+               type = XI_TouchEnd;
+       }
+       else if (!oldstate.proximity || no_update) {
+               DBG(6, priv->common, "This is a touch begin event\n");
+               type = XI_TouchBegin;
+       }
+       else {
+               DBG(6, priv->common, "This is a touch update event\n");
+               type = XI_TouchUpdate;
+       }
+
+       xf86PostTouchEvent(priv->pInfo->dev, state.serial_num - 1, type, 0, 
mask);
+#endif
+}
+
+/**
+ * Send multitouch events. If entering multitouch mode (indicated by
+ * GESTURE_LAG_MODE), then touch events are sent for all in-prox
+ * contacts. Otherwise, only the specified contact has a touch event
+ * generated.
+ *
+ * @param[in] priv
+ * @param[in] contact_id  ID of the contact to send event for (at minimum)
+ */
+static void
+wcmFingerMultitouch(WacomDevicePtr priv, int contact_id) {
+       Bool lag_mode = priv->common->wcmGestureMode == GESTURE_LAG_MODE;
+       Bool prox = FALSE;
+       int i;
+
+       if (lag_mode && TabletHasFeature(priv->common, WCM_LCD)) {
+               /* wcmSingleFingerPress triggers a button press as
+                * soon as a single finger appears. ensure we release
+                * that button before getting too far along
+                */
+               wcmSendButtonClick(priv, 1, 0);
+       }
+
+       for (i = 0; i < MAX_CHANNELS; i++) {
+               WacomChannelPtr channel = priv->common->wcmChannel+i;
+               WacomDeviceState state  = channel->valid.state;
+               if (state.device_type != TOUCH_ID)
+                       continue;
+
+               if (lag_mode || state.serial_num == contact_id + 1) {
+                       wcmSendTouchEvent(priv, channel, lag_mode);
+               }
+
+               prox |= state.proximity;
+       }
+
+       if (!prox)
+               priv->common->wcmGestureMode = GESTURE_NONE_MODE;
+       else if (lag_mode)
+               priv->common->wcmGestureMode = GESTURE_MULTITOUCH_MODE;
+}
+
 static double touchDistance(WacomDeviceState ds0, WacomDeviceState ds1)
 {
        int xDelta = ds0.x - ds1.x;
@@ -430,6 +513,17 @@ void wcmGestureFilter(WacomDevicePtr priv, int touch_id)
                }
        }
 ret:
+
+#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 16
+       /* Send multitouch data to X if appropriate */
+       if (!common->wcmGesture && ds[1].proximity && common->wcmGestureMode == 
GESTURE_NONE_MODE)
+               common->wcmGestureMode = GESTURE_LAG_MODE;
+       if (!common->wcmGesture && (common->wcmGestureMode == GESTURE_LAG_MODE 
||
+           common->wcmGestureMode == GESTURE_MULTITOUCH_MODE)) {
+               wcmFingerMultitouch(priv, touch_id);
+       }
+#endif
+
        if (common->wcmGestureMode == GESTURE_NONE_MODE && touch_id == 0)
        {
                /* Since this is in ret block, can not rely on generic
diff --git a/src/xf86Wacom.c b/src/xf86Wacom.c
index c52db8d..ee417c3 100644
--- a/src/xf86Wacom.c
+++ b/src/xf86Wacom.c
@@ -419,6 +419,14 @@ static int wcmDevInit(DeviceIntPtr pWcm)
                return FALSE;
        }
 
+#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 16
+       if (!InitTouchClassDeviceStruct(pInfo->dev, 0, XIDependentTouch, 2)) {
+               xf86Msg(X_ERROR, "Unable to init touch class device struct!\n");
+               return FALSE;
+       }
+       priv->common->touch_mask = valuator_mask_new(2);
+#endif
+
        if (!IsPad(priv))
        {
                wcmInitialToolSize(pInfo);
diff --git a/src/xf86WacomDefs.h b/src/xf86WacomDefs.h
index b39e426..2643e64 100644
--- a/src/xf86WacomDefs.h
+++ b/src/xf86WacomDefs.h
@@ -397,9 +397,9 @@ extern WacomDeviceClass gWacomISDV4Device;
 #define TILT_REQUEST_FLAG       1
 #define TILT_ENABLED_FLAG       2
 
-#define MAX_CHANNELS 3
+#define MAX_CHANNELS 15
 #define PAD_CHANNEL (MAX_CHANNELS-1)
-#define MAX_FINGERS  2
+#define MAX_FINGERS (MAX_CHANNELS-1)
 
 typedef struct {
        int wcmZoomDistance;           /* minimum distance for a zoom touch 
gesture */
@@ -497,6 +497,8 @@ struct _WacomCommonRec
 
        /* DO NOT TOUCH THIS. use wcmRefCommon() instead */
        int refcnt;                     /* number of devices sharing this 
struct */
+
+       ValuatorMask *touch_mask;
 };
 
 #define HANDLE_TILT(comm) ((comm)->wcmFlags & TILT_ENABLED_FLAG)
-- 
1.7.12


------------------------------------------------------------------------------
How fast is your code?
3 out of 4 devs don\\\'t know how their code performs in production.
Find out how slow your code is with AppDynamics Lite.
http://ad.doubleclick.net/clk;262219672;13503038;z?
http://info.appdynamics.com/FreeJavaPerformanceDownload.html
_______________________________________________
Linuxwacom-devel mailing list
Linuxwacom-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linuxwacom-devel

Reply via email to