Add a configurable button mapping for tap gestures on touchpads.
authorbru <bru@openbsd.org>
Wed, 3 Mar 2021 19:44:37 +0000 (19:44 +0000)
committerbru <bru@openbsd.org>
Wed, 3 Mar 2021 19:44:37 +0000 (19:44 +0000)
Thanks to RJ Johnson for this work!

ok mpi@

sbin/wsconsctl/mousecfg.c
share/man/man4/wsmouse.4
sys/dev/wscons/wsconsio.h
sys/dev/wscons/wstpad.c

index afa98cf..76a9984 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: mousecfg.c,v 1.8 2021/03/02 22:35:19 bru Exp $ */
+/* $OpenBSD: mousecfg.c,v 1.9 2021/03/03 19:44:37 bru Exp $ */
 
 /*
  * Copyright (c) 2017 Ulf Brosziewski
@@ -40,9 +40,9 @@
 #define TP_FILTER_FIRST                WSMOUSECFG_DX_MAX
 #define TP_FILTER_LAST         WSMOUSECFG_SMOOTHING
 #define TP_FEATURES_FIRST      WSMOUSECFG_SOFTBUTTONS
-#define TP_FEATURES_LAST       WSMOUSECFG_TAPPING
+#define TP_FEATURES_LAST       WSMOUSECFG_DISABLE
 #define TP_SETUP_FIRST         WSMOUSECFG_LEFT_EDGE
-#define TP_SETUP_LAST          WSMOUSECFG_TAP_LOCKTIME
+#define TP_SETUP_LAST          WSMOUSECFG_TAP_THREE_BTNMAP
 #define LOG_FIRST              WSMOUSECFG_LOG_INPUT
 #define LOG_LAST               WSMOUSECFG_LOG_EVENTS
 
@@ -71,8 +71,10 @@ static const int touchpad_types[] = {
 
 struct wsmouse_parameters cfg_tapping = {
        (struct wsmouse_param[]) {
-           { WSMOUSECFG_TAPPING, 0 }, },
-       1
+           { WSMOUSECFG_TAP_ONE_BTNMAP, 0 },
+           { WSMOUSECFG_TAP_TWO_BTNMAP, 0 },
+           { WSMOUSECFG_TAP_THREE_BTNMAP, 0 }, },
+       3
 };
 
 struct wsmouse_parameters cfg_scaling = {
@@ -267,6 +269,30 @@ set_percent(struct wsmouse_parameters *field, enum wsmousecfg key, float f)
        set_value(field, key, (int) ((f * 4096 + 50) / 100));
 }
 
+static int
+set_tapping(struct wsmouse_parameters *field, char *tapping)
+{
+       int i1, i2, i3;
+
+       switch (sscanf(tapping, "%d,%d,%d", &i1, &i2, &i3)) {
+       case 1:
+               if (i1 == 0) /* Disable */
+                       i2 = i3 = i1;
+               else { /* Enable with defaults */
+                       i1 = 1; /* Left click */
+                       i2 = 3; /* Right click */
+                       i3 = 2; /* Middle click */
+               }
+               /* FALLTHROUGH */
+       case 3:
+               set_value(field, WSMOUSECFG_TAP_ONE_BTNMAP, i1);
+               set_value(field, WSMOUSECFG_TAP_TWO_BTNMAP, i2);
+               set_value(field, WSMOUSECFG_TAP_THREE_BTNMAP, i3);
+               return (0);
+       }
+       return (-1);
+}
+
 static int
 set_edges(struct wsmouse_parameters *field, char *edges)
 {
@@ -368,6 +394,12 @@ mousecfg_rd_field(struct wsmouse_parameters *field, char *val)
                return;
        }
 
+       if (field == &cfg_tapping) {
+               if (set_tapping(field, val))
+                       errx(1, "invalid input (tapping)");
+               return;
+       }
+
        if (field == &cfg_scaling) {
                if (sscanf(val, "%f", &f) == 1) {
                        n = (int) (f * 4096);
index b238b1b..7806ccf 100644 (file)
@@ -1,4 +1,4 @@
-.\" $OpenBSD: wsmouse.4,v 1.20 2018/02/04 20:29:59 bru Exp $
+.\" $OpenBSD: wsmouse.4,v 1.21 2021/03/03 19:44:37 bru Exp $
 .\" $NetBSD: wsmouse.4,v 1.3 1999/12/06 14:52:08 augustss Exp $
 .\"
 .\" Copyright (c) 2018 Ulf Brosziewski <bru@openbsd.org>
@@ -26,7 +26,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd $Mdocdate: February 4 2018 $
+.Dd $Mdocdate: March 3 2021 $
 .Dt WSMOUSE 4
 .Os
 .Sh NAME
@@ -87,13 +87,24 @@ is omitted, commands apply to
 .Pa /dev/wsmouse0 .
 .Bl -tag -width Ds
 .It Cm mouse.tp.tapping
-Setting this parameter to a non-zero value enables tap gestures.
-Contacts on the touchpad that are immediately released again
-trigger click events.
-One-finger, two-finger, and three-finger taps generate left-button,
-right-button, and middle-button clicks, respectively.
-If, within a short time interval, a second touch follows a one-finger
-tap, the button-up event is not issued until that touch ends
+Contacts on the touchpad that are immediately released again can
+be mapped to mouse button clicks. This list of three parameters
+configures these mappings, in the order:
+.Bd -literal -offset indent
+.Sm off
+.Ar one-finger , two-finger , three-finger
+.Sm on
+.Ed
+.Pp
+Setting a parameter to a positive value enables that tap gesture
+and maps it to the given mouse button. To disable all three tap
+gestures at once, provide the single value of 0. Conversely, a
+single non-zero value will enable one-finger, two-finger, and
+three-finger tap gestures with their default mappings of left
+button, right button, and middle button, respectively. If, within
+a short time interval, a second touch follows a tap gesture
+mapped to a left-button click, the button-up event is not issued
+until that touch ends
 .Pq Dq tap-and-drag .
 .It Cm mouse.tp.scaling
 The value is a scale coefficient that is applied to the relative
index 32ef411..7c3fc7a 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: wsconsio.h,v 1.95 2020/10/01 17:28:14 kettenis Exp $ */
+/* $OpenBSD: wsconsio.h,v 1.96 2021/03/03 19:44:37 bru Exp $ */
 /* $NetBSD: wsconsio.h,v 1.74 2005/04/28 07:15:44 martin Exp $ */
 
 /*
@@ -319,7 +319,6 @@ enum wsmousecfg {
        WSMOUSECFG_SWAPSIDES,           /* invert soft-button/scroll areas */
        WSMOUSECFG_DISABLE,             /* disable all output except for
                                           clicks in the top-button area */
-       WSMOUSECFG_TAPPING,             /* enable tapping */
 
        /*
         * Touchpad options
@@ -338,6 +337,9 @@ enum wsmousecfg {
                                           the button-up-event (ms) */
        WSMOUSECFG_TAP_LOCKTIME,        /* time between a tap-and-drag action
                                           and the button-up-event (ms) */
+       WSMOUSECFG_TAP_ONE_BTNMAP,      /* one-finger tap button mapping */
+       WSMOUSECFG_TAP_TWO_BTNMAP,      /* two-finger tap button mapping */
+       WSMOUSECFG_TAP_THREE_BTNMAP,    /* three-finger tap button mapping */
 
        /*
         * Enable/Disable debug output.
@@ -345,7 +347,7 @@ enum wsmousecfg {
        WSMOUSECFG_LOG_INPUT = 256,
        WSMOUSECFG_LOG_EVENTS,
 };
-#define WSMOUSECFG_MAX 39      /* max size of param array per ioctl */
+#define WSMOUSECFG_MAX 41      /* max size of param array per ioctl */
 
 struct wsmouse_param {
        enum wsmousecfg key;
index f916cbb..9e89bb0 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: wstpad.c,v 1.26 2020/09/13 10:05:46 fcambus Exp $ */
+/* $OpenBSD: wstpad.c,v 1.27 2021/03/03 19:44:37 bru Exp $ */
 
 /*
  * Copyright (c) 2015, 2016 Ulf Brosziewski
 #include <dev/wscons/wseventvar.h>
 #include <dev/wscons/wsmouseinput.h>
 
-#define LEFTBTN                        (1 << 0)
-#define MIDDLEBTN              (1 << 1)
-#define RIGHTBTN               (1 << 2)
+#define BTNMASK(n)             ((n) > 0 && (n) <= 32 ? 1 << ((n) - 1) : 0)
+
+#define LEFTBTN                        BTNMASK(1)
+#define MIDDLEBTN              BTNMASK(2)
+#define RIGHTBTN               BTNMASK(3)
 
 #define PRIMARYBTN LEFTBTN
 
@@ -57,6 +59,7 @@
 #define TAP_MAXTIME_DEFAULT    180
 #define TAP_CLICKTIME_DEFAULT  180
 #define TAP_LOCKTIME_DEFAULT   0
+#define TAP_BTNMAP_SIZE                3
 
 #define CLICKDELAY_MS          20
 #define FREEZE_MS              100
@@ -147,7 +150,6 @@ struct tpad_touch {
 #define WSTPAD_HORIZSCROLL     (1 << 5)
 #define WSTPAD_SWAPSIDES       (1 << 6)
 #define WSTPAD_DISABLE         (1 << 7)
-#define WSTPAD_TAPPING         (1 << 8)
 
 #define WSTPAD_MT              (1 << 31)
 
@@ -218,6 +220,7 @@ struct wstpad {
                struct timespec maxtime;
                int clicktime;
                int locktime;
+               u_int btnmap[TAP_BTNMAP_SIZE];
        } tap;
 
        struct {
@@ -722,7 +725,7 @@ tap_btn(struct wstpad *tp, int nmasked)
 {
        int n = tp->tap.contacts - nmasked;
 
-       return (n == 2 ? RIGHTBTN : (n == 3 ? MIDDLEBTN : LEFTBTN));
+       return (n <= TAP_BTNMAP_SIZE ? tp->tap.btnmap[n - 1] : 0);
 }
 
 /*
@@ -793,9 +796,13 @@ wstpad_tap(struct wsmouseinput *input, u_int *cmds)
                                tp->tap.centered = 0;
                        }
                        if (tp->tap.state == TAP_LIFTED) {
-                               *cmds |= 1 << TAPBUTTON_DOWN;
-                               err = !timeout_add_msec(&tp->tap.to,
-                                   tp->tap.clicktime);
+                               if (tp->tap.button != 0) {
+                                       *cmds |= 1 << TAPBUTTON_DOWN;
+                                       err = !timeout_add_msec(&tp->tap.to,
+                                           tp->tap.clicktime);
+                               } else {
+                                       tp->tap.state = TAP_DETECT;
+                               }
                        }
                }
                break;
@@ -1528,7 +1535,7 @@ int
 wstpad_configure(struct wsmouseinput *input)
 {
        struct wstpad *tp;
-       int width, height, diag, offset, h_res, v_res, h_unit, v_unit;
+       int width, height, diag, offset, h_res, v_res, h_unit, v_unit, i;
 
        width = abs(input->hw.x_max - input->hw.x_min);
        height = abs(input->hw.y_max - input->hw.y_min);
@@ -1626,12 +1633,16 @@ wstpad_configure(struct wsmouseinput *input)
        else if (tp->features & WSTPAD_EDGESCROLL)
                tp->handlers |= 1 << EDGESCROLL_HDLR;
 
-       if (tp->features & WSTPAD_TAPPING) {
+       for (i = 0; i < TAP_BTNMAP_SIZE; i++) {
+               if (tp->tap.btnmap[i] == 0)
+                       continue;
+
                tp->tap.clicktime = imin(imax(tp->tap.clicktime, 80), 350);
                if (tp->tap.locktime)
                        tp->tap.locktime =
                            imin(imax(tp->tap.locktime, 150), 5000);
                tp->handlers |= 1 << TAP_HDLR;
+               break;
        }
 
        if (input->hw.hw_type == WSMOUSEHW_CLICKPAD)
@@ -1669,7 +1680,7 @@ wstpad_set_param(struct wsmouseinput *input, int key, int val)
                return (EINVAL);
 
        switch (key) {
-       case WSMOUSECFG_SOFTBUTTONS ... WSMOUSECFG_TAPPING:
+       case WSMOUSECFG_SOFTBUTTONS ... WSMOUSECFG_DISABLE:
                switch (key) {
                case WSMOUSECFG_SOFTBUTTONS:
                        flag = WSTPAD_SOFTBUTTONS;
@@ -1695,9 +1706,6 @@ wstpad_set_param(struct wsmouseinput *input, int key, int val)
                case WSMOUSECFG_DISABLE:
                        flag = WSTPAD_DISABLE;
                        break;
-               case WSMOUSECFG_TAPPING:
-                       flag = WSTPAD_TAPPING;
-                       break;
                }
                if (val)
                        tp->features |= flag;
@@ -1740,6 +1748,15 @@ wstpad_set_param(struct wsmouseinput *input, int key, int val)
        case WSMOUSECFG_TAP_LOCKTIME:
                tp->tap.locktime = val;
                break;
+       case WSMOUSECFG_TAP_ONE_BTNMAP:
+               tp->tap.btnmap[0] = BTNMASK(val);
+               break;
+       case WSMOUSECFG_TAP_TWO_BTNMAP:
+               tp->tap.btnmap[1] = BTNMASK(val);
+               break;
+       case WSMOUSECFG_TAP_THREE_BTNMAP:
+               tp->tap.btnmap[2] = BTNMASK(val);
+               break;
        default:
                return (ENOTSUP);
        }
@@ -1757,7 +1774,7 @@ wstpad_get_param(struct wsmouseinput *input, int key, int *pval)
                return (EINVAL);
 
        switch (key) {
-       case WSMOUSECFG_SOFTBUTTONS ... WSMOUSECFG_TAPPING:
+       case WSMOUSECFG_SOFTBUTTONS ... WSMOUSECFG_DISABLE:
                switch (key) {
                case WSMOUSECFG_SOFTBUTTONS:
                        flag = WSTPAD_SOFTBUTTONS;
@@ -1783,9 +1800,6 @@ wstpad_get_param(struct wsmouseinput *input, int key, int *pval)
                case WSMOUSECFG_DISABLE:
                        flag = WSTPAD_DISABLE;
                        break;
-               case WSMOUSECFG_TAPPING:
-                       flag = WSTPAD_TAPPING;
-                       break;
                }
                *pval = !!(tp->features & flag);
                break;
@@ -1825,6 +1839,15 @@ wstpad_get_param(struct wsmouseinput *input, int key, int *pval)
        case WSMOUSECFG_TAP_LOCKTIME:
                *pval = tp->tap.locktime;
                break;
+       case WSMOUSECFG_TAP_ONE_BTNMAP:
+               *pval = ffs(tp->tap.btnmap[0]);
+               break;
+       case WSMOUSECFG_TAP_TWO_BTNMAP:
+               *pval = ffs(tp->tap.btnmap[1]);
+               break;
+       case WSMOUSECFG_TAP_THREE_BTNMAP:
+               *pval = ffs(tp->tap.btnmap[2]);
+               break;
        default:
                return (ENOTSUP);
        }