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