From: Chris Bagwell <ch...@cnpbagwell.com>

This patch adds support for processing multi-touch (MT) kernel events.
To do this, it must filter out older style single touch (ST) events
to prevent conflicts.

For Bamboo's/Tablet PC, channel 0 == 1st finger and channel 1 == 2nd finger.

In older Bamboo kernel driver, serial #1 == 1st finger and serial #2 ==
2nd finger.  Mapping to channel was serial # - 1 and events had to
come in isolated by separate BTN_TOOL_DOUBLETAP/TRIPLETAP messages.

With newer MT kernel driver, MT slot 0 == 1st finger and MT slot 1 ==
2nd finger.  Take advantage of this straight mapping to channel.
Code will ignore ST-style events then MT packets will write to
either channel 0 or 1 or both.

Signed-off-by: Chris Bagwell <ch...@cnpbagwell.com>
---
 src/wcmUSB.c |  142 +++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 131 insertions(+), 11 deletions(-)

diff --git a/src/wcmUSB.c b/src/wcmUSB.c
index 1d54b3f..854ab03 100644
--- a/src/wcmUSB.c
+++ b/src/wcmUSB.c
@@ -33,6 +33,8 @@
 typedef struct {
        int wcmLastToolSerial;
        int wcmBTNChannel;
+       int wcmMTMode;
+       int wcmMTChannel;
        int wcmEventCnt;
        struct input_event wcmEvents[MAX_USB_EVENTS];
 } wcmUSBData;
@@ -403,6 +405,9 @@ static void usbInitProtocol4(WacomCommonPtr common, const 
char* id,
        common->wcmFlags &= ~TILT_ENABLED_FLAG;
 }
 
+/* FIXME: I'm compiling against 2.6.35 header files in /usr/include/linux */
+#define ABS_MT_SLOT 0x2f
+
 int usbWcmGetRanges(InputInfoPtr pInfo)
 {
        struct input_absinfo absinfo;
@@ -410,6 +415,7 @@ int usbWcmGetRanges(InputInfoPtr pInfo)
        unsigned long abs[NBITS(ABS_MAX)] = {0};
        WacomDevicePtr priv = (WacomDevicePtr)pInfo->private;
        WacomCommonPtr common = priv->common;
+       wcmUSBData* private = common->private;
        int is_touch = IsTouch(priv);
 
        /* Devices such as Bamboo P&T may have Pad data reported in the same
@@ -509,6 +515,8 @@ int usbWcmGetRanges(InputInfoPtr pInfo)
        if (ioctl(pInfo->fd, EVIOCGABS(ABS_DISTANCE), &absinfo) == 0)
                common->wcmMaxDist = absinfo.maximum;
 
+       if (ISBITSET(common->wcmKeys, ABS_MT_SLOT))
+               private->wcmMTMode = 1;
 
        if ((common->tablet_id >= 0xd0) && (common->tablet_id <= 0xd3))
        {
@@ -788,6 +796,52 @@ skipEvent:
        private->wcmEventCnt = 0;
 }
 
+static int usbFilterEvent(WacomCommonPtr common, struct input_event *event)
+{
+#ifdef ABS_MT_SLOT
+       wcmUSBData* private = common->private;
+
+       /* For devices that report multitouch, the following list is set of
+        * duplicate data from one slot and needs to be filtered out.
+        */
+       if (private->wcmMTMode) {
+               if (event->type == EV_KEY) {
+                       switch(event->code)
+                       {
+                               case BTN_TOUCH:
+                               case BTN_TOOL_FINGER:
+                                       return 1;
+                       }
+               } else if (event->type == EV_ABS) {
+                       switch(event->code)
+                       {
+                               case ABS_X:
+                               case ABS_Y:
+                               case ABS_PRESSURE:
+                                       return 1;
+                       }
+               }
+       }
+
+#endif
+
+       /* For generic devices, filter out doubletap/tripletap that
+        * can be confused with older protocol.
+        */
+       if (common->wcmProtocolLevel == WCM_PROTOCOL_GENERIC) {
+               if (event->type == EV_ABS) {
+                       switch(event->code)
+                       {
+                               case BTN_TOOL_DOUBLETAP:
+                               case BTN_TOOL_TRIPLETAP:
+                                       return 1;
+                       }
+               }
+       }
+
+       return 0;
+}
+
 static int usbParseAbsEvent(WacomCommonPtr common,
                            struct input_event *event, WacomDeviceState *ds)
 {
@@ -844,6 +898,60 @@ static int usbParseAbsEvent(WacomCommonPtr common,
        return change;
 }
 
+static int usbParseAbsMTEvent(WacomCommonPtr common, struct input_event *event)
+{
+#ifndef ABS_MT_SLOT
+       /* requires Linux 2.6.36 or newer */
+       return 0;
+#else
+       int change = 1;
+       wcmUSBData* private = common->private;
+       WacomDeviceState *ds;
+
+       ds = &common->wcmChannel[private->wcmMTChannel].work;
+
+       switch(event->code)
+       {
+               case ABS_MT_SLOT:
+                       if (event->value >= 0 && event->value < MAX_FINGERS)
+                       {
+                               WacomDeviceState *dsnew;
+
+                               private->wcmMTChannel = event->value;
+                               dsnew = &common->
+                                       wcmChannel[private->wcmMTChannel].work;
+
+                               dsnew->device_type = TOUCH_ID;
+                               dsnew->device_id = TOUCH_DEVICE_ID;
+                               dsnew->serial_num = event->value+1;
+                       }
+                       break;
+
+               case ABS_MT_TRACKING_ID:
+                       ds->proximity = (event->value != -1);
+
+                       ds->sample = (int)GetTimeInMillis();
+                       break;
+
+               case ABS_MT_POSITION_X:
+                       ds->x = event->value;
+                       break;
+
+               case ABS_MT_POSITION_Y:
+                       ds->y = event->value;
+                       break;
+
+               case ABS_MT_PRESSURE:
+                       ds->capacity = event->value;
+                       break;
+
+               default:
+                       change = 0;
+       }
+       return change;
+#endif
+}
+
 static struct
 {
        unsigned long device_type;
@@ -947,11 +1055,6 @@ static int usbParseKeyEvent(WacomCommonPtr common,
 
                        /* fall through */
                case BTN_TOOL_DOUBLETAP:
-                       /* If a real double tap report, ignore. */
-                       if (common->wcmProtocolLevel == WCM_PROTOCOL_GENERIC &&
-                           event->code == BTN_TOOL_DOUBLETAP)
-                               break;
-
                        DBG(6, common,
                            "USB Touch detected %x (value=%d)\n",
                            event->code, event->value);
@@ -977,10 +1080,6 @@ static int usbParseKeyEvent(WacomCommonPtr common,
                        break;
 
                case BTN_TOOL_TRIPLETAP:
-                       /* If a real triple tap report, ignore. */
-                       if (common->wcmProtocolLevel == WCM_PROTOCOL_GENERIC)
-                               break;
-
                        DBG(6, common,
                            "USB Touch second finger detected %x (value=%d)\n",
                            event->code, event->value);
@@ -1080,7 +1179,7 @@ static void usbDispatchEvents(InputInfoPtr pInfo)
        WacomDevicePtr priv = (WacomDevicePtr)pInfo->private;
        WacomCommonPtr common = priv->common;
        int channel;
-       int channel_change = 0, btn_channel_change = 0;
+       int channel_change = 0, btn_channel_change = 0, mt1_channel_change = 0;
        WacomChannelPtr pChannel;
        WacomDeviceState dslast;
        wcmUSBData* private = common->private;
@@ -1165,10 +1264,22 @@ static void usbDispatchEvents(InputInfoPtr pInfo)
                        "event[%d]->type=%d code=%d value=%d\n",
                        i, event->type, event->code, event->value);
 
+               /* Check for events to be ignored and skip them up front. */
+               if (usbFilterEvent(common, event))
+                       continue;
+
                /* absolute events */
                if (event->type == EV_ABS)
                {
-                       channel_change |= usbParseAbsEvent(common, event, ds);
+                       if (usbParseAbsEvent(common, event, ds))
+                               channel_change |= 1;
+                       else if (usbParseAbsMTEvent(common, event))
+                       {
+                               if (private->wcmMTChannel == 0)
+                                       channel_change |= 1;
+                               else if (private->wcmMTChannel == 1)
+                                       mt1_channel_change |= 1;
+                       }
                }
                else if (event->type == EV_REL)
                {
@@ -1232,6 +1343,15 @@ static void usbDispatchEvents(InputInfoPtr pInfo)
            (private->wcmBTNChannel == channel && btn_channel_change))
                wcmEvent(common, channel, ds);
 
+       /* dispatch for second finger.  first finger is handled above. */
+       if (mt1_channel_change)
+       {
+               WacomDeviceState *mt1_ds;
+
+               mt1_ds = &common->wcmChannel[1].work;
+               wcmEvent(common, 1, mt1_ds);
+       }
+
        /* dispatch butten events when re-routed */
        if (private->wcmBTNChannel != channel && btn_channel_change)
        {
-- 
1.7.3.3


------------------------------------------------------------------------------
Lotusphere 2011
Register now for Lotusphere 2011 and learn how
to connect the dots, take your collaborative environment
to the next level, and enter the era of Social Business.
http://p.sf.net/sfu/lotusphere-d2d
_______________________________________________
Linuxwacom-devel mailing list
Linuxwacom-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linuxwacom-devel

Reply via email to