From: Ping Cheng <pi...@wacom.com> If a tablet has pen and touch interfaces, they appear to the system as seperate devices. Because it is necessary for these devices to share information, `wcmLinkTouchAndPen` was introduced to connect the two "halves" of the single physical tablet together (similar to how `wcmMatchDevice` links logical devices together).
`wcmLinkTouchAndPen` has a few bugs in its implementation which prevent it from doing its job as well as it should. This patch introduces a new funcation named `wcmIsSiblingDevice` which is responsible for determining if two devices are part of the same tablet. It includes a slightly stricter (but still imperfect) check to reduce the number of false-positives in the linking process. Signed-off-by: Jason Gerecke <killert...@gmail.com> --- Changes from v4: * Pretty much everything ;) src/wcmConfig.c | 164 ++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 112 insertions(+), 52 deletions(-) diff --git a/src/wcmConfig.c b/src/wcmConfig.c index bb2c975..e18613f 100644 --- a/src/wcmConfig.c +++ b/src/wcmConfig.c @@ -299,6 +299,85 @@ out: xf86DeleteInput(pInfo, 0); } +/** + * Splits a wacom device name into its constituent pieces. For instance, + * "Wacom Intuos Pro Finger touch" would be split into "Wacom Intuos Pro" + * (the base kernel device name), "Finger" (an descriptor of the specific + * event interface), and "touch" (a suffix added by this driver to indicate + * the specific tool). + */ +static void wcmSplitName(char* devicename, char *basename, char *subdevice, char *tool, size_t len) +{ + char *name = strdupa(devicename); + char *a, *b; + + *basename = *subdevice = *tool = '\0'; + + a = strrchr(name, ' '); + if (a) + { + *a = '\0'; + b = strrchr(name, ' '); + if (b && (!strcmp(b, " Pen") || !strcmp(b, " Finger") || !strcmp(b, " Pad"))) + { + *b = '\0'; + strncat(subdevice, b+1, len-1); + } + strncat(tool, a+1, len-1); + } + strncat(basename, name, len-1); +} + +/** + * Determines if two input devices represent independent parts (stylus, + * eraser, pad) of the same underlying device. If the 'logical_only' + * flag is set, the function will only return true if the two devices + * are represented by the same logical device (i.e., share the same + * input device node). Otherwise, the function will attempt to determine + * if the two devices are part of the same physical tablet, such as + * when a tablet reports 'pen' and 'touch' through separate device + * nodes. + */ +static Bool wcmIsSiblingDevice(InputInfoPtr a, InputInfoPtr b, Bool logical_only) +{ + WacomDevicePtr privA = (WacomDevicePtr)a->private; + WacomDevicePtr privB = (WacomDevicePtr)b->private; + + if (strcmp(a->drv->driverName, "wacom") || strcmp(b->drv->driverName, "wacom")) + return FALSE; + + if (privA == privB) + return FALSE; + + if (DEVICE_ID(privA->flags) == DEVICE_ID(privB->flags)) + return FALSE; + + if (!strcmp(privA->common->device_path, privB->common->device_path)) + return TRUE; + + if (!logical_only) + { + // TODO: Udev might provide more accurate data, but this should + // be good enough in practice. + const int len = 50; + char baseA[len], subA[len], toolA[len]; + char baseB[len], subB[len], toolB[len]; + wcmSplitName(privA->name, baseA, subA, toolA, len); + wcmSplitName(privB->name, baseB, subB, toolB, len); + + if (strcmp(baseA, baseB)) + { + // Fallback for (arbitrary) static xorg.conf device names + return (privA->common->tablet_id == privB->common->tablet_id); + } + + if (strlen(subA) != 0 && strlen(subB) != 0) + return TRUE; + } + + return FALSE; +} + /* wcmMatchDevice - locate matching device and merge common structure. If an * already initialized device shares the same device file and driver, remove * the new device's "common" struct and point to the one of the already @@ -323,9 +402,7 @@ static Bool wcmMatchDevice(InputInfoPtr pLocal, WacomCommonPtr *common_return) { WacomDevicePtr privMatch = (WacomDevicePtr)pMatch->private; - if ((pLocal != pMatch) && - strstr(pMatch->drv->driverName, "wacom") && - !strcmp(privMatch->common->device_path, common->device_path)) + if (wcmIsSiblingDevice(pLocal, pMatch, TRUE)) { DBG(2, priv, "port share between %s and %s\n", pLocal->name, pMatch->name); @@ -389,8 +466,11 @@ wcmInitModel(InputInfoPtr pInfo) /** * Link the touch tool to the pen of the same device * so we can arbitrate the events when posting them. + * + * @return True if found a touch tool for hybrid devices. + * false otherwise. */ -static void wcmLinkTouchAndPen(InputInfoPtr pInfo) +static Bool wcmLinkTouchAndPen(InputInfoPtr pInfo) { WacomDevicePtr priv = pInfo->private; WacomCommonPtr common = priv->common; @@ -398,65 +478,45 @@ static void wcmLinkTouchAndPen(InputInfoPtr pInfo) WacomCommonPtr tmpcommon = NULL; WacomDevicePtr tmppriv = NULL; - /* Lookup to find the associated pen and touch with same product id */ + /* Lookup to find the associated pen and touch */ for (; device != NULL; device = device->next) { - if (!strcmp(device->drv->driverName, "wacom")) - { - tmppriv = (WacomDevicePtr) device->private; - tmpcommon = tmppriv->common; - - /* skip the same tool or already linked devices */ - if ((tmppriv == priv) || tmpcommon->wcmTouchDevice) - continue; + if (!wcmIsSiblingDevice(pInfo, device, FALSE)) + continue; - if (tmpcommon->tablet_id == common->tablet_id) - { - if (IsTouch(tmppriv) && IsTablet(priv)) - common->wcmTouchDevice = tmppriv; - else if (IsTouch(priv) && IsTablet(tmppriv)) - tmpcommon->wcmTouchDevice = priv; - - if (common->wcmTouchDevice || - tmpcommon->wcmTouchDevice) - { - TabletSetFeature(common, WCM_PENTOUCH); - TabletSetFeature(tmpcommon, WCM_PENTOUCH); - } - } + tmppriv = (WacomDevicePtr) device->private; + tmpcommon = tmppriv->common; - if (common->wcmTouchDevice) - return; - } - } + DBG(4, priv, "Considering link with %s...\n", tmppriv->name); - /* Lookup for pen and touch devices with different product ids */ - for (; device != NULL; device = device->next) - { - if (!strcmp(device->drv->driverName, "wacom")) + /* already linked devices */ + if (tmpcommon->wcmTouchDevice) { - tmppriv = (WacomDevicePtr) device->private; - tmpcommon = tmppriv->common; - - /* skip the same tool or already linked devices */ - if ((tmppriv == priv) || tmpcommon->wcmTouchDevice) - continue; + DBG(4, priv, "A link is already in place. Ignoring.\n"); + continue; + } - if (IsTouch(tmppriv) && IsTablet(priv)) - common->wcmTouchDevice = tmppriv; - else if (IsTouch(priv) && IsTablet(tmppriv)) - tmpcommon->wcmTouchDevice = priv; + if (IsTouch(tmppriv) && IsTablet(priv)) + common->wcmTouchDevice = tmppriv; + else if (IsTouch(priv) && IsTablet(tmppriv)) + tmpcommon->wcmTouchDevice = priv; + else + DBG(4, priv, "A link is not necessary. Ignoring.\n"); - if (common->wcmTouchDevice || tmpcommon->wcmTouchDevice) - { - TabletSetFeature(common, WCM_PENTOUCH); - TabletSetFeature(tmpcommon, WCM_PENTOUCH); - } + if (common->wcmTouchDevice || tmpcommon->wcmTouchDevice) + { + TabletSetFeature(common, WCM_PENTOUCH); + TabletSetFeature(tmpcommon, WCM_PENTOUCH); + } - if (common->wcmTouchDevice) - return; + if (common->wcmTouchDevice) + { + DBG(4, priv, "Link created!\n"); + return TRUE; } } + DBG(4, priv, "No suitable device to link with found.\n"); + return FALSE; } /** -- 1.9.0 ------------------------------------------------------------------------------ Flow-based real-time traffic analytics software. Cisco certified tool. Monitor traffic, SLAs, QoS, Medianet, WAAS etc. with NetFlow Analyzer Customize your own dashboards, set traffic alerts and generate reports. Network behavioral analysis & security monitoring. All-in-one tool. http://pubads.g.doubleclick.net/gampad/clk?id=126839071&iu=/4140/ostg.clktrk _______________________________________________ Linuxwacom-devel mailing list Linuxwacom-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxwacom-devel