The tap-and-drag gesture doesn't work reliably with the ALPS touchpads supported by pms. To make it work, it is necessary to start dragging immediately with the second touch, which doesn't always succeed. Increasing the tap timeout helps, but doesn't change the principle. The patch below solves that problem. Tests and comments would be welcome.
In case someone is interested in the background: I have observed the same problem with a Linux installation on a machine with an ALPS touchpad; however, increasing the tap timeout to a sufficiently high value (>= 260ms) makes it work normally. The somewhat special behaviour of those ALPS models is described in this LKML posting: https://lkml.org/lkml/2004/7/28/210 The approach put forward there - which is partially reproduced in the current version of pms - is improved by the patch as follows: When the hardware signals a tap, the handler does nothing. The missing events will be emulated when the next packet arrives, which either signals the end of the gesture, or the start of a drag action. No timeout will occur even if the hardware introduces a long delay between the first and the second packet (which just happens when the finger is resting after the second contact). Index: dev/pckbc/pms.c =================================================================== RCS file: /cvs/src/sys/dev/pckbc/pms.c,v retrieving revision 1.64 diff -u -p -r1.64 pms.c --- dev/pckbc/pms.c 20 Jul 2015 00:55:06 -0000 1.64 +++ dev/pckbc/pms.c 14 Aug 2015 18:27:57 -0000 @@ -120,7 +120,8 @@ struct alps_softc { int min_x, min_y; int max_x, max_y; - int old_fin; + + u_int gesture; u_int sec_buttons; /* trackpoint */ @@ -1521,8 +1522,7 @@ pms_proc_alps(struct pms_softc *sc) { struct alps_softc *alps = sc->alps; int x, y, z, w, dx, dy; - u_int buttons; - int fin, ges; + u_int buttons, gesture; if ((alps->model & ALPS_DUALPOINT) && alps_sec_proc(sc)) return; @@ -1557,28 +1557,44 @@ pms_proc_alps(struct pms_softc *sc) y = ALPS_YMAX_BEZEL - y + ALPS_YMIN_BEZEL; if (alps->wsmode == WSMOUSE_NATIVE) { - ges = sc->packet[2] & 0x01; - fin = sc->packet[2] & 0x02; + if (alps->gesture == ALPS_TAP) { + /* Report a touch with the tap coordinates. */ + wsmouse_input(sc->sc_wsmousedev, buttons, + alps->old_x, alps->old_y, ALPS_PRESSURE, 4, + WSMOUSE_INPUT_ABSOLUTE_X + | WSMOUSE_INPUT_ABSOLUTE_Y + | WSMOUSE_INPUT_ABSOLUTE_Z + | WSMOUSE_INPUT_ABSOLUTE_W); + if (z > 0) { + /* + * The hardware doesn't send a null pressure + * event when dragging starts. + */ + wsmouse_input(sc->sc_wsmousedev, buttons, + alps->old_x, alps->old_y, 0, 0, + WSMOUSE_INPUT_ABSOLUTE_X + | WSMOUSE_INPUT_ABSOLUTE_Y + | WSMOUSE_INPUT_ABSOLUTE_Z + | WSMOUSE_INPUT_ABSOLUTE_W); + } + } - /* Simulate click (tap) */ - if (ges && !fin) - z = 35; - - /* Generate a null pressure event (needed for tap & drag) */ - if (ges && fin && !alps->old_fin) - z = 0; - - /* Generate a width value corresponding to one finger */ - if (z > 0) - w = 4; - else - w = 0; + gesture = sc->packet[2] & 0x03; + if (gesture != ALPS_TAP) { + w = z ? 4 : 0; + wsmouse_input(sc->sc_wsmousedev, buttons, x, y, z, w, + WSMOUSE_INPUT_ABSOLUTE_X + | WSMOUSE_INPUT_ABSOLUTE_Y + | WSMOUSE_INPUT_ABSOLUTE_Z + | WSMOUSE_INPUT_ABSOLUTE_W); + } - wsmouse_input(sc->sc_wsmousedev, buttons, x, y, z, w, - WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y | - WSMOUSE_INPUT_ABSOLUTE_Z | WSMOUSE_INPUT_ABSOLUTE_W); + if (alps->gesture != ALPS_DRAG || gesture != ALPS_TAP) + alps->gesture = gesture; + + alps->old_x = x; + alps->old_y = y; - alps->old_fin = fin; } else { dx = dy = 0; if (z > ALPS_PRESSURE) { Index: dev/pckbc/pmsreg.h =================================================================== RCS file: /cvs/src/sys/dev/pckbc/pmsreg.h,v retrieving revision 1.11 diff -u -p -r1.11 pmsreg.h --- dev/pckbc/pmsreg.h 26 Mar 2015 01:30:22 -0000 1.11 +++ dev/pckbc/pmsreg.h 14 Aug 2015 18:27:57 -0000 @@ -164,6 +164,10 @@ #define ALPS_Z_MAGIC 127 +/* ALPS "gesture" and "finger" bits */ +#define ALPS_TAP 0x01 +#define ALPS_DRAG 0x03 + /* Elantech queries */ #define ELANTECH_QUE_FW_ID 0 #define ELANTECH_QUE_FW_VER 1