From: Dmitry Torokhov Date: Wed, 15 Oct 2008 22:47:46 -0400 Subject: [PATCH] Add support for touchpads (such as Elantech) that do not report pressure. Signed-off-by: Dmitry Torokhov --- src/eventcomm.c | 77 +++++++++++++++++++++++++++++++++++----------------- src/synapticsstr.h | 1 + 2 files changed, 53 insertions(+), 25 deletions(-) diff --git a/src/eventcomm.c b/src/eventcomm.c index b2d0891..b5076e3 100644 --- a/src/eventcomm.c +++ b/src/eventcomm.c @@ -77,7 +77,9 @@ static Bool event_query_is_touchpad(int fd) { int ret; - unsigned long evbits[NBITS(KEY_MAX)]; + unsigned long evbits[NBITS(EV_MAX)]; + unsigned long absbits[NBITS(ABS_MAX)]; + unsigned long keybits[NBITS(KEY_MAX)]; /* Check for ABS_X, ABS_Y, ABS_PRESSURE and BTN_TOOL_FINGER */ @@ -89,20 +91,24 @@ event_query_is_touchpad(int fd) !TEST_BIT(EV_KEY, evbits)) return FALSE; - SYSCALL(ret = ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(evbits)), evbits)); + SYSCALL(ret = ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbits)), absbits)); if (ret < 0) return FALSE; - if (!TEST_BIT(ABS_X, evbits) || - !TEST_BIT(ABS_Y, evbits) || - !TEST_BIT(ABS_PRESSURE, evbits)) + if (!TEST_BIT(ABS_X, absbits) || + !TEST_BIT(ABS_Y, absbits)) return FALSE; - SYSCALL(ret = ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(evbits)), evbits)); + SYSCALL(ret = ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybits)), keybits)); if (ret < 0) return FALSE; - if (!TEST_BIT(BTN_TOOL_FINGER, evbits)) + + /* we expect touchpad either report raw pressure or touches */ + if (!TEST_BIT(ABS_PRESSURE, absbits) && !TEST_BIT(BTN_TOUCH, keybits)) + return FALSE; + /* all Synaptics-like touchpad report BTN_TOOL_FINGER */ + if (!TEST_BIT(BTN_TOOL_FINGER, keybits)) return FALSE; - if (TEST_BIT(BTN_TOOL_PEN, evbits)) + if (TEST_BIT(BTN_TOOL_PEN, keybits)) return FALSE; /* Don't match wacom tablets */ return TRUE; @@ -114,12 +120,13 @@ event_query_axis_ranges(LocalDevicePtr local) { SynapticsPrivate *priv = (SynapticsPrivate *)local->private; struct input_absinfo abs; - unsigned long evbits[NBITS(KEY_MAX)]; + unsigned long absbits[NBITS(ABS_MAX)]; + unsigned long keybits[NBITS(KEY_MAX)]; char buf[256]; int rc; SYSCALL(rc = ioctl(local->fd, EVIOCGABS(ABS_X), &abs)); - if (rc == 0) + if (rc >= 0) { xf86Msg(X_INFO, "%s: x-axis range %d - %d\n", local->name, abs.minimum, abs.maximum); @@ -130,7 +137,7 @@ event_query_axis_ranges(LocalDevicePtr local) strerror(errno)); SYSCALL(rc = ioctl(local->fd, EVIOCGABS(ABS_Y), &abs)); - if (rc == 0) + if (rc >= 0) { xf86Msg(X_INFO, "%s: y-axis range %d - %d\n", local->name, abs.minimum, abs.maximum); @@ -140,17 +147,31 @@ event_query_axis_ranges(LocalDevicePtr local) xf86Msg(X_ERROR, "%s: failed to query axis range (%s)\n", local->name, strerror(errno)); - SYSCALL(rc = ioctl(local->fd, EVIOCGABS(ABS_PRESSURE), &abs)); - if (rc == 0) + priv->has_pressure = FALSE; + SYSCALL(rc = ioctl(local->fd, EVIOCGBIT(EV_ABS, sizeof(absbits)), absbits)); + if (rc >= 0) + priv->has_pressure = TEST_BIT(ABS_PRESSURE, absbits); + else + xf86Msg(X_ERROR, "%s: failed to query ABS bits (%s)\n", local->name, + strerror(errno)); + + if (priv->has_pressure) { - xf86Msg(X_INFO, "%s: pressure range %d - %d\n", local->name, - abs.minimum, abs.maximum); - priv->minp = abs.minimum; - priv->maxp = abs.maximum; - } + SYSCALL(rc = ioctl(local->fd, EVIOCGABS(ABS_PRESSURE), &abs)); + if (rc >= 0) + { + xf86Msg(X_INFO, "%s: pressure range %d - %d\n", local->name, + abs.minimum, abs.maximum); + priv->minp = abs.minimum; + priv->maxp = abs.maximum; + } + } else + xf86Msg(X_ERROR, + "%s: device does not report pressure, will use touch data\n", + local->name, strerror(errno)); SYSCALL(rc = ioctl(local->fd, EVIOCGABS(ABS_TOOL_WIDTH), &abs)); - if (rc == 0) + if (rc >= 0) { xf86Msg(X_INFO, "%s: finger width range %d - %d\n", local->name, abs.minimum, abs.maximum); @@ -158,19 +179,19 @@ event_query_axis_ranges(LocalDevicePtr local) priv->maxw = abs.maximum; } - SYSCALL(rc = ioctl(local->fd, EVIOCGBIT(EV_KEY, sizeof(evbits)), evbits)); + SYSCALL(rc = ioctl(local->fd, EVIOCGBIT(EV_KEY, sizeof(keybits)), keybits)); if (rc >= 0) { buf[0] = 0; - if ((priv->has_left = TEST_BIT(BTN_LEFT, evbits))) + if ((priv->has_left = TEST_BIT(BTN_LEFT, keybits))) strcat(buf, " left"); - if ((priv->has_right = TEST_BIT(BTN_RIGHT, evbits))) + if ((priv->has_right = TEST_BIT(BTN_RIGHT, keybits))) strcat(buf, " right"); - if ((priv->has_middle = TEST_BIT(BTN_MIDDLE, evbits))) + if ((priv->has_middle = TEST_BIT(BTN_MIDDLE, keybits))) strcat(buf, " middle"); - if ((priv->has_double = TEST_BIT(BTN_TOOL_DOUBLETAP, evbits))) + if ((priv->has_double = TEST_BIT(BTN_TOOL_DOUBLETAP, keybits))) strcat(buf, " double"); - if ((priv->has_triple = TEST_BIT(BTN_TOOL_TRIPLETAP, evbits))) + if ((priv->has_triple = TEST_BIT(BTN_TOOL_TRIPLETAP, keybits))) strcat(buf, " triple"); xf86Msg(X_INFO, "%s: buttons:%s\n", local->name, buf); } @@ -229,6 +250,8 @@ EventReadHwState(LocalDevicePtr local, struct SynapticsHwInfo *synhw, struct input_event ev; Bool v; struct SynapticsHwState *hw = &(comm->hwState); + SynapticsPrivate *priv = (SynapticsPrivate *)local->private; + SynapticsSHM *para = priv->synpara; while (SynapticsReadEvent(comm, &ev)) { switch (ev.type) { @@ -304,6 +327,10 @@ EventReadHwState(LocalDevicePtr local, struct SynapticsHwInfo *synhw, case BTN_B: hw->guest_right = v; break; + case BTN_TOUCH: + if (!priv->has_pressure) + hw->z = v ? para->finger_high + 1 : 0; + break; } break; case EV_ABS: diff --git a/src/synapticsstr.h b/src/synapticsstr.h index cc0a29f..688167c 100644 --- a/src/synapticsstr.h +++ b/src/synapticsstr.h @@ -145,6 +145,7 @@ typedef struct _SynapticsPrivateRec Bool has_middle; /* middle button detected for this device */ Bool has_double; /* double click detected for this device */ Bool has_triple; /* triple click detected for this device */ + Bool has_pressure; /* device reports pressure */ } SynapticsPrivate; #endif /* _SYNAPTICSSTR_H_ */ -- 1.5.5.1