Add button mappings for two- and three-finger clicks on clickpads.
authorbru <bru@openbsd.org>
Sun, 2 Jul 2023 21:44:04 +0000 (21:44 +0000)
committerbru <bru@openbsd.org>
Sun, 2 Jul 2023 21:44:04 +0000 (21:44 +0000)
Based on a proposal of tobhe@.

ok tobhe@

sbin/wsconsctl/mouse.c
sbin/wsconsctl/mousecfg.c
sbin/wsconsctl/mousecfg.h
share/man/man4/wsmouse.4
sys/arch/arm64/dev/aplhidev.c
sys/dev/usb/ubcmtp.c
sys/dev/wscons/wsconsio.h
sys/dev/wscons/wstpad.c

index e04642d..c880c92 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: mouse.c,v 1.20 2019/08/19 21:42:33 bru Exp $  */
+/*     $OpenBSD: mouse.c,v 1.21 2023/07/02 21:44:04 bru Exp $  */
 /*     $NetBSD: mouse.c,v 1.3 1999/11/15 13:47:30 ad Exp $ */
 
 /*-
@@ -57,6 +57,7 @@ struct field mouse_field_tab[] = {
     { "reverse_scrolling",     &cfg_revscroll, FMT_CFG,        FLG_NORDBACK },
     /* touchpad-specific options: */
     { "tp.tapping",            &cfg_tapping,   FMT_CFG,        FLG_NORDBACK },
+    { "tp.mtbuttons",          &cfg_mtbuttons, FMT_CFG,        FLG_NORDBACK },
     { "tp.scaling",            &cfg_scaling,   FMT_CFG,        FLG_NORDBACK },
     { "tp.swapsides",          &cfg_swapsides, FMT_CFG,        FLG_NORDBACK },
     { "tp.disable",            &cfg_disable,   FMT_CFG,        FLG_NORDBACK },
@@ -69,6 +70,10 @@ struct field mouse_field_tab[] = {
 
 static int dev_index = -1;
 
+static struct wsmouse_parameters mtbtn_maxdist = {
+    (struct wsmouse_param[]) { { WSMOUSECFG_MTBTN_MAXDIST, 0 } }, 1
+};
+
 
 void
 mouse_init(int devfd, int devidx) {
@@ -91,6 +96,12 @@ mouse_init(int devfd, int devidx) {
                        if (f->format == FMT_CFG) {
                                f->flags &= ~FLG_DEAD;
                        }
+               /* Hide the 'mtbuttons' field if the feature is unavailable. */
+               if (mousecfg_get_field(&mtbtn_maxdist) ||
+                   mtbtn_maxdist.params[0].value < 0) {
+                       f = field_by_value(mouse_field_tab, &cfg_mtbuttons);
+                       f->flags |= FLG_DEAD;
+               }
        } else {
                for (f = mouse_field_tab; f->name != NULL; f++)
                        if (f->format == FMT_CFG) {
index 76a9984..7fd7bff 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: mousecfg.c,v 1.9 2021/03/03 19:44:37 bru Exp $ */
+/* $OpenBSD: mousecfg.c,v 1.10 2023/07/02 21:44:04 bru Exp $ */
 
 /*
  * Copyright (c) 2017 Ulf Brosziewski
 #define nitems(_a)       (sizeof((_a)) / sizeof((_a)[0]))
 #endif
 
-#define BASE_FIRST             WSMOUSECFG_DX_SCALE
-#define BASE_LAST              WSMOUSECFG_REVERSE_SCROLLING
-#define TP_FILTER_FIRST                WSMOUSECFG_DX_MAX
-#define TP_FILTER_LAST         WSMOUSECFG_SMOOTHING
-#define TP_FEATURES_FIRST      WSMOUSECFG_SOFTBUTTONS
-#define TP_FEATURES_LAST       WSMOUSECFG_DISABLE
-#define TP_SETUP_FIRST         WSMOUSECFG_LEFT_EDGE
-#define TP_SETUP_LAST          WSMOUSECFG_TAP_THREE_BTNMAP
-#define LOG_FIRST              WSMOUSECFG_LOG_INPUT
-#define LOG_LAST               WSMOUSECFG_LOG_EVENTS
-
-#define BASESIZE ((BASE_LAST - BASE_FIRST + 1) + (LOG_LAST - LOG_FIRST + 1))
-
-#define BUFSIZE (BASESIZE \
-    + (TP_FILTER_LAST - TP_FILTER_FIRST + 1) \
-    + (TP_FEATURES_LAST - TP_FEATURES_FIRST + 1) \
-    + (TP_SETUP_LAST - TP_SETUP_FIRST + 1))
+#define BASESIZE ((WSMOUSECFG__FILTERS - WSMOUSECFG_DX_SCALE) \
+    + (WSMOUSECFG__DEBUG - WSMOUSECFG_LOG_INPUT))
 
 static const int range[][2] = {
-       { BASE_FIRST, BASE_LAST },
-       { LOG_FIRST, LOG_LAST },
-       { TP_FILTER_FIRST, TP_FILTER_LAST },
-       { TP_FEATURES_FIRST, TP_FEATURES_LAST },
-       { TP_SETUP_FIRST, TP_SETUP_LAST },
+       { WSMOUSECFG_DX_SCALE, WSMOUSECFG__FILTERS - 1 },
+       { WSMOUSECFG_LOG_INPUT, WSMOUSECFG__DEBUG - 1 },
+       { WSMOUSECFG_DX_MAX, WSMOUSECFG__TPFILTERS - 1 },
+       { WSMOUSECFG_SOFTBUTTONS, WSMOUSECFG__TPFEATURES - 1 },
+       { WSMOUSECFG_LEFT_EDGE, WSMOUSECFG__TPSETUP - 1 },
 };
 
 static const int touchpad_types[] = {
@@ -77,6 +62,12 @@ struct wsmouse_parameters cfg_tapping = {
        3
 };
 
+struct wsmouse_parameters cfg_mtbuttons = {
+       (struct wsmouse_param[]) {
+           { WSMOUSECFG_MTBUTTONS, 0 }, },
+       1
+};
+
 struct wsmouse_parameters cfg_scaling = {
        (struct wsmouse_param[]) {
            { WSMOUSECFG_DX_SCALE, 0 },
@@ -124,7 +115,7 @@ int cfg_touchpad;
 
 static int cfg_horiz_res;
 static int cfg_vert_res;
-static struct wsmouse_param cfg_buffer[BUFSIZE];
+static struct wsmouse_param cfg_buffer[WSMOUSECFG_MAX];
 
 
 int
@@ -171,7 +162,7 @@ mousecfg_init(int dev_fd, const char **errstr)
        }
        if (cfg_touchpad) {
                parameters.params = cfg_buffer + BASESIZE;
-               parameters.nparams = BUFSIZE - BASESIZE;
+               parameters.nparams = WSMOUSECFG_MAX - BASESIZE;
                if (ioctl(dev_fd, WSMOUSEIO_GETPARAMS, &parameters))
                        cfg_touchpad = 0;
        }
index 8e99139..161ed05 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: mousecfg.h,v 1.4 2019/08/19 21:42:33 bru Exp $ */
+/* $OpenBSD: mousecfg.h,v 1.5 2023/07/02 21:44:04 bru Exp $ */
 
 /*
  * Copyright (c) 2017 Ulf Brosziewski
@@ -17,6 +17,7 @@
  */
 
 extern struct wsmouse_parameters cfg_tapping;
+extern struct wsmouse_parameters cfg_mtbuttons;
 extern struct wsmouse_parameters cfg_scaling;
 extern struct wsmouse_parameters cfg_edges;
 extern struct wsmouse_parameters cfg_swapsides;
index 9dae08e..549d52e 100644 (file)
@@ -1,4 +1,4 @@
-.\" $OpenBSD: wsmouse.4,v 1.22 2021/03/04 17:03:42 jmc Exp $
+.\" $OpenBSD: wsmouse.4,v 1.23 2023/07/02 21:44:04 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: March 4 2021 $
+.Dd $Mdocdate: July 2 2023 $
 .Dt WSMOUSE 4
 .Os
 .Sh NAME
@@ -106,6 +106,10 @@ 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.mtbuttons
+This feature is supported for some clickpads.
+If enabled, two-finger clicks - with the fingers side by side - generate
+left-button events, and three-finger clicks generate middle-button events.
 .It Cm mouse.tp.scaling
 The value is a scale coefficient that is applied to the relative
 coordinates.
index 5b0c818..db6feb6 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: aplhidev.c,v 1.11 2023/04/10 15:14:04 tobhe Exp $     */
+/*     $OpenBSD: aplhidev.c,v 1.12 2023/07/02 21:44:04 bru Exp $       */
 /*
  * Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org>
  * Copyright (c) 2013-2014 joshua stein <jcs@openbsd.org>
@@ -683,6 +683,10 @@ struct ubcmtp_finger {
 /* Use a constant, synaptics-compatible pressure value for now. */
 #define DEFAULT_PRESSURE       40
 
+static struct wsmouse_param aplms_wsmousecfg[] = {
+       { WSMOUSECFG_MTBTN_MAXDIST, 0 }, /* 0: Compute a default value. */
+};
+
 struct aplms_softc {
        struct device   sc_dev;
        struct device   *sc_wsmousedev;
@@ -762,7 +766,8 @@ aplms_configure(struct aplms_softc *sc)
        hw->mt_slots = UBCMTP_MAX_FINGERS;
        hw->flags = WSMOUSEHW_MT_TRACKING;
 
-       return wsmouse_configure(sc->sc_wsmousedev, NULL, 0);
+       return wsmouse_configure(sc->sc_wsmousedev,
+           aplms_wsmousecfg, nitems(aplms_wsmousecfg));
 }
 
 void
index d86883b..fd53f52 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ubcmtp.c,v 1.24 2022/10/26 16:07:28 kn Exp $ */
+/*     $OpenBSD: ubcmtp.c,v 1.25 2023/07/02 21:44:04 bru Exp $ */
 
 /*
  * Copyright (c) 2013-2014, joshua stein <jcs@openbsd.org>
@@ -309,6 +309,10 @@ static const struct ubcmtp_dev ubcmtp_devices[] = {
        },
 };
 
+static struct wsmouse_param ubcmtp_wsmousecfg[] = {
+       { WSMOUSECFG_MTBTN_MAXDIST, 0 }, /* 0: Compute a default value. */
+};
+
 struct ubcmtp_softc {
        struct device           sc_dev;         /* base device */
 
@@ -529,7 +533,8 @@ ubcmtp_configure(struct ubcmtp_softc *sc)
        hw->mt_slots = UBCMTP_MAX_FINGERS;
        hw->flags = WSMOUSEHW_MT_TRACKING;
 
-       return wsmouse_configure(sc->sc_wsmousedev, NULL, 0);
+       return wsmouse_configure(sc->sc_wsmousedev,
+           ubcmtp_wsmousecfg, nitems(ubcmtp_wsmousecfg));
 }
 
 int
index 9755ee6..574c593 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: wsconsio.h,v 1.99 2023/04/20 19:28:31 jcs Exp $ */
+/* $OpenBSD: wsconsio.h,v 1.100 2023/07/02 21:44:04 bru Exp $ */
 /* $NetBSD: wsconsio.h,v 1.74 2005/04/28 07:15:44 martin Exp $ */
 
 /*
@@ -279,6 +279,9 @@ struct wsmouse_calibcoords {
  * WSMOUSEIO_SETPARAMS calls. Arbitrary subsets can be passed, provided
  * that all keys are valid and that the number of key/value pairs doesn't
  * exceed WSMOUSECFG_MAX.
+ *
+ * The keys are divided into various groups, which end with marker entries
+ * of the form WSMOUSECFG__*.
  */
 enum wsmousecfg {
        /*
@@ -295,6 +298,8 @@ enum wsmousecfg {
        WSMOUSECFG_REVERSE_SCROLLING,
                                /* reverse scroll directions */
 
+        WSMOUSECFG__FILTERS,
+
        /*
         * Coordinate handling, applying only in WSMOUSE_COMPAT  mode.
         */
@@ -307,6 +312,8 @@ enum wsmousecfg {
                                           ture is not supported anymore. */
        WSMOUSECFG_SMOOTHING,   /* smoothing factor (0-7) */
 
+       WSMOUSECFG__TPFILTERS,
+
        /*
         * Touchpad features
         */
@@ -319,6 +326,9 @@ enum wsmousecfg {
        WSMOUSECFG_SWAPSIDES,           /* invert soft-button/scroll areas */
        WSMOUSECFG_DISABLE,             /* disable all output except for
                                           clicks in the top-button area */
+       WSMOUSECFG_MTBUTTONS,           /* multi-touch buttons */
+
+       WSMOUSECFG__TPFEATURES,
 
        /*
         * Touchpad options
@@ -340,14 +350,25 @@ enum wsmousecfg {
        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 */
+       WSMOUSECFG_MTBTN_MAXDIST,       /* MTBUTTONS: distance limit for
+                                          two-finger clicks */
+
+       WSMOUSECFG__TPSETUP,
 
        /*
         * Enable/Disable debug output.
         */
        WSMOUSECFG_LOG_INPUT = 256,
        WSMOUSECFG_LOG_EVENTS,
+
+       WSMOUSECFG__DEBUG,
 };
-#define WSMOUSECFG_MAX 41      /* max size of param array per ioctl */
+
+#define WSMOUSECFG_MAX ((WSMOUSECFG__FILTERS - WSMOUSECFG_DX_SCALE)    \
+    + (WSMOUSECFG__TPFILTERS - WSMOUSECFG_DX_MAX)                      \
+    + (WSMOUSECFG__TPFEATURES - WSMOUSECFG_SOFTBUTTONS)                        \
+    + (WSMOUSECFG__TPSETUP - WSMOUSECFG_LEFT_EDGE)                     \
+    + (WSMOUSECFG__DEBUG - WSMOUSECFG_LOG_INPUT))
 
 struct wsmouse_param {
        enum wsmousecfg key;
index be074b8..c3735cf 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: wstpad.c,v 1.31 2022/06/09 22:17:18 bru Exp $ */
+/* $OpenBSD: wstpad.c,v 1.32 2023/07/02 21:44:04 bru Exp $ */
 
 /*
  * Copyright (c) 2015, 2016 Ulf Brosziewski
@@ -149,6 +149,7 @@ struct tpad_touch {
 #define WSTPAD_HORIZSCROLL     (1 << 5)
 #define WSTPAD_SWAPSIDES       (1 << 6)
 #define WSTPAD_DISABLE         (1 << 7)
+#define WSTPAD_MTBUTTONS       (1 << 8)
 
 #define WSTPAD_MT              (1 << 31)
 
@@ -201,6 +202,8 @@ struct wstpad {
                /* two-finger contacts */
                int f2pressure;
                int f2width;
+               /* MTBUTTONS: distance limit for two-finger clicks */
+               int mtbtn_maxdist;
        } params;
 
        /* handler state and configuration: */
@@ -634,6 +637,37 @@ wstpad_get_sbtn(struct wsmouseinput *input, int top)
        return (btn != PRIMARYBTN ? btn : 0);
 }
 
+int
+wstpad_mtbtn_contacts(struct wsmouseinput *input)
+{
+       struct wstpad *tp = input->tp;
+       struct tpad_touch *t;
+       int dx, dy, dist, limit;
+
+       if (tp->ignore != 0)
+               return (tp->contacts - 1);
+
+       if (tp->contacts == 2 && (t = get_2nd_touch(input)) != NULL) {
+               dx = abs(t->x - tp->t->x) << 12;
+               dy = abs(t->y - tp->t->y) * tp->ratio;
+               dist = (dx >= dy ? dx + 3 * dy / 8 : dy + 3 * dx / 8);
+               limit = tp->params.mtbtn_maxdist << 12;
+               if (input->mt.ptr_mask != 0)
+                       limit = limit * 2 / 3;
+               if (dist > limit)
+                       return (1);
+       }
+       return (tp->contacts);
+}
+
+u_int
+wstpad_get_mtbtn(struct wsmouseinput *input)
+{
+       int contacts = wstpad_mtbtn_contacts(input);
+       return (contacts == 2 ? RIGHTBTN : (contacts == 3 ? MIDDLEBTN : 0));
+}
+
+
 void
 wstpad_softbuttons(struct wsmouseinput *input, u_int *cmds, int hdlr)
 {
@@ -646,7 +680,8 @@ wstpad_softbuttons(struct wsmouseinput *input, u_int *cmds, int hdlr)
        }
 
        if (tp->softbutton == 0 && PRIMARYBTN_CLICKED(tp)) {
-               tp->softbutton = wstpad_get_sbtn(input, top);
+               tp->softbutton = ((tp->features & WSTPAD_MTBUTTONS)
+                   ? wstpad_get_mtbtn(input) : wstpad_get_sbtn(input, top));
                if (tp->softbutton)
                        *cmds |= 1 << SOFTBUTTON_DOWN;
        }
@@ -1599,6 +1634,15 @@ wstpad_configure(struct wsmouseinput *input)
                tp->scroll.hdist = 4 * h_unit;
                tp->scroll.vdist = 4 * v_unit;
                tp->tap.maxdist = 4 * h_unit;
+
+               if (IS_MT(tp) && h_res > 1 && v_res > 1 &&
+                   input->hw.hw_type == WSMOUSEHW_CLICKPAD &&
+                   (width + h_res / 2) / h_res > 100 &&
+                   (height + v_res / 2) / v_res > 60) {
+                       tp->params.mtbtn_maxdist = h_res * 35;
+               } else {
+                       tp->params.mtbtn_maxdist = -1; /* not available */
+               }
        }
 
        /* A touch with a flag set in this mask does not move the pointer. */
@@ -1619,13 +1663,24 @@ wstpad_configure(struct wsmouseinput *input)
        tp->edge.center_left = tp->edge.center - offset;
        tp->edge.center_right = tp->edge.center + offset;
 
+       /*
+        * Make the MTBUTTONS configuration consistent.  A non-negative 'maxdist'
+        * value makes the feature visible in wsconsctl.  0-values are replaced
+        * by a default (one fourth of the length of the touchpad diagonal).
+        */
+       if (tp->params.mtbtn_maxdist < 0) {
+               tp->features &= ~WSTPAD_MTBUTTONS;
+       } else if (tp->params.mtbtn_maxdist == 0) {
+               diag = isqrt(width * width + height * height);
+               tp->params.mtbtn_maxdist = diag / 4;
+       }
+
        tp->handlers = 0;
 
-       if (tp->features & WSTPAD_SOFTBUTTONS)
+       if (tp->features & (WSTPAD_SOFTBUTTONS | WSTPAD_MTBUTTONS))
                tp->handlers |= 1 << SOFTBUTTON_HDLR;
        if (tp->features & WSTPAD_TOPBUTTONS)
                tp->handlers |= 1 << TOPBUTTON_HDLR;
-
        if (tp->features & WSTPAD_TWOFINGERSCROLL)
                tp->handlers |= 1 << F2SCROLL_HDLR;
        else if (tp->features & WSTPAD_EDGESCROLL)
@@ -1691,7 +1746,7 @@ wstpad_set_param(struct wsmouseinput *input, int key, int val)
                return (EINVAL);
 
        switch (key) {
-       case WSMOUSECFG_SOFTBUTTONS ... WSMOUSECFG_DISABLE:
+       case WSMOUSECFG_SOFTBUTTONS ... WSMOUSECFG_MTBUTTONS:
                switch (key) {
                case WSMOUSECFG_SOFTBUTTONS:
                        flag = WSTPAD_SOFTBUTTONS;
@@ -1717,6 +1772,9 @@ wstpad_set_param(struct wsmouseinput *input, int key, int val)
                case WSMOUSECFG_DISABLE:
                        flag = WSTPAD_DISABLE;
                        break;
+               case WSMOUSECFG_MTBUTTONS:
+                       flag = WSTPAD_MTBUTTONS;
+                       break;
                }
                if (val)
                        tp->features |= flag;
@@ -1768,6 +1826,10 @@ wstpad_set_param(struct wsmouseinput *input, int key, int val)
        case WSMOUSECFG_TAP_THREE_BTNMAP:
                tp->tap.btnmap[2] = BTNMASK(val);
                break;
+       case WSMOUSECFG_MTBTN_MAXDIST:
+               if (IS_MT(tp))
+                       tp->params.mtbtn_maxdist = val;
+               break;
        default:
                return (ENOTSUP);
        }
@@ -1785,7 +1847,7 @@ wstpad_get_param(struct wsmouseinput *input, int key, int *pval)
                return (EINVAL);
 
        switch (key) {
-       case WSMOUSECFG_SOFTBUTTONS ... WSMOUSECFG_DISABLE:
+       case WSMOUSECFG_SOFTBUTTONS ... WSMOUSECFG_MTBUTTONS:
                switch (key) {
                case WSMOUSECFG_SOFTBUTTONS:
                        flag = WSTPAD_SOFTBUTTONS;
@@ -1811,6 +1873,9 @@ wstpad_get_param(struct wsmouseinput *input, int key, int *pval)
                case WSMOUSECFG_DISABLE:
                        flag = WSTPAD_DISABLE;
                        break;
+               case WSMOUSECFG_MTBUTTONS:
+                       flag = WSTPAD_MTBUTTONS;
+                       break;
                }
                *pval = !!(tp->features & flag);
                break;
@@ -1859,6 +1924,9 @@ wstpad_get_param(struct wsmouseinput *input, int key, int *pval)
        case WSMOUSECFG_TAP_THREE_BTNMAP:
                *pval = ffs(tp->tap.btnmap[2]);
                break;
+       case WSMOUSECFG_MTBTN_MAXDIST:
+               *pval = tp->params.mtbtn_maxdist;
+               break;
        default:
                return (ENOTSUP);
        }