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> --- This patch contains updates based on comments from Peter. In mean time, I also found a bug/typo in filtering logic. Should have been EV_KEY for BTN_TOOL_* checks. v3 addresses spaces-instead-of-tabs issue Peter mentioned. src/wcmUSB.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++---- src/xf86WacomDefs.h | 28 ++++++++++ 2 files changed, 154 insertions(+), 11 deletions(-) diff --git a/src/wcmUSB.c b/src/wcmUSB.c index 1d54b3f..7bd65f4 100644 --- a/src/wcmUSB.c +++ b/src/wcmUSB.c @@ -33,6 +33,8 @@ typedef struct { int wcmLastToolSerial; int wcmBTNChannel; + Bool wcmUseMT; + int wcmMTChannel; int wcmEventCnt; struct input_event wcmEvents[MAX_USB_EVENTS]; } wcmUSBData; @@ -410,6 +412,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 +512,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->wcmUseMT = 1; if ((common->tablet_id >= 0xd0) && (common->tablet_id <= 0xd3)) { @@ -788,6 +793,55 @@ skipEvent: private->wcmEventCnt = 0; } +static int usbFilterEvent(WacomCommonPtr common, struct input_event *event) +{ + wcmUSBData* private = common->private; + + /* For devices that report multitouch, the following list is a set of + * duplicate data from one slot and needs to be filtered out. + */ + if (private->wcmUseMT) + { + 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; + } + } + } + + /* For generic devices, filter out doubletap/tripletap that + * can be confused with older protocol. + */ + if (common->wcmProtocolLevel == WCM_PROTOCOL_GENERIC) + { + if (event->type == EV_KEY) + { + 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,55 @@ static int usbParseAbsEvent(WacomCommonPtr common, return change; } +static int usbParseAbsMTEvent(WacomCommonPtr common, struct input_event *event) +{ + 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; +} + static struct { unsigned long device_type; @@ -947,11 +1050,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 +1075,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 +1174,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, mt_channel_change = 0; WacomChannelPtr pChannel; WacomDeviceState dslast; wcmUSBData* private = common->private; @@ -1165,10 +1259,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) + mt_channel_change |= 1; + } } else if (event->type == EV_REL) { @@ -1232,6 +1338,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 (mt_channel_change) + { + WacomDeviceState *mt_ds; + + mt_ds = &common->wcmChannel[1].work; + wcmEvent(common, 1, mt_ds); + } + /* dispatch butten events when re-routed */ if (private->wcmBTNChannel != channel && btn_channel_change) { diff --git a/src/xf86WacomDefs.h b/src/xf86WacomDefs.h index 87d75d5..b8c94b3 100644 --- a/src/xf86WacomDefs.h +++ b/src/xf86WacomDefs.h @@ -47,6 +47,8 @@ #define PROXOUT_INTUOS_DISTANCE 10 #define PROXOUT_GRAPHIRE_DISTANCE 42 +/* 2.6.28 */ + #ifndef BTN_TOOL_DOUBLETAP #define BTN_TOOL_DOUBLETAP 0x14d #endif @@ -55,6 +57,32 @@ #define BTN_TOOL_TRIPLETAP 0x14e #endif +/* 2.6.30 */ + +#ifndef ABS_MT_POSITION_X +#define ABS_MT_POSITION_X 0x35 +#endif + +#ifndef ABS_MT_POSITION_Y +#define ABS_MT_POSITION_Y 0x36 +#endif + +#ifndef ABS_MT_TRACKING_ID +#define ABS_MT_TRACKING_ID 0x39 +#endif + +/* 2.6.33 */ + +#ifndef ABS_MT_PRESSURE +#define ABS_MT_PRESSURE 0x3a +#endif + +/* 2.6.36 */ + +#ifndef ABS_MT_SLOT +#define ABS_MT_SLOT 0x2f +#endif + /* defines to discriminate second side button and the eraser */ #define ERASER_PROX 4 #define OTHER_PROX 1 -- 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