From 9310c18a55559b441078265fb70b4c66cc9193bc Mon Sep 17 00:00:00 2001 From: bru Date: Sun, 2 Jul 2023 21:44:04 +0000 Subject: [PATCH] Add button mappings for two- and three-finger clicks on clickpads. Based on a proposal of tobhe@. ok tobhe@ --- sbin/wsconsctl/mouse.c | 13 +++++- sbin/wsconsctl/mousecfg.c | 41 +++++++----------- sbin/wsconsctl/mousecfg.h | 3 +- share/man/man4/wsmouse.4 | 8 +++- sys/arch/arm64/dev/aplhidev.c | 9 +++- sys/dev/usb/ubcmtp.c | 9 +++- sys/dev/wscons/wsconsio.h | 25 ++++++++++- sys/dev/wscons/wstpad.c | 80 ++++++++++++++++++++++++++++++++--- 8 files changed, 147 insertions(+), 41 deletions(-) diff --git a/sbin/wsconsctl/mouse.c b/sbin/wsconsctl/mouse.c index e04642dacbc..c880c92b57b 100644 --- a/sbin/wsconsctl/mouse.c +++ b/sbin/wsconsctl/mouse.c @@ -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) { diff --git a/sbin/wsconsctl/mousecfg.c b/sbin/wsconsctl/mousecfg.c index 76a9984bd86..7fd7bff3d21 100644 --- a/sbin/wsconsctl/mousecfg.c +++ b/sbin/wsconsctl/mousecfg.c @@ -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 @@ -35,30 +35,15 @@ #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, ¶meters)) cfg_touchpad = 0; } diff --git a/sbin/wsconsctl/mousecfg.h b/sbin/wsconsctl/mousecfg.h index 8e99139d280..161ed05e476 100644 --- a/sbin/wsconsctl/mousecfg.h +++ b/sbin/wsconsctl/mousecfg.h @@ -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; diff --git a/share/man/man4/wsmouse.4 b/share/man/man4/wsmouse.4 index 9dae08eb1c4..549d52e51a2 100644 --- a/share/man/man4/wsmouse.4 +++ b/share/man/man4/wsmouse.4 @@ -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 @@ -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. diff --git a/sys/arch/arm64/dev/aplhidev.c b/sys/arch/arm64/dev/aplhidev.c index 5b0c8185f2b..db6feb6bcca 100644 --- a/sys/arch/arm64/dev/aplhidev.c +++ b/sys/arch/arm64/dev/aplhidev.c @@ -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 * Copyright (c) 2013-2014 joshua stein @@ -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 diff --git a/sys/dev/usb/ubcmtp.c b/sys/dev/usb/ubcmtp.c index d86883bd6c2..fd53f52281b 100644 --- a/sys/dev/usb/ubcmtp.c +++ b/sys/dev/usb/ubcmtp.c @@ -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 @@ -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 diff --git a/sys/dev/wscons/wsconsio.h b/sys/dev/wscons/wsconsio.h index 9755ee60f18..574c593cf1e 100644 --- a/sys/dev/wscons/wsconsio.h +++ b/sys/dev/wscons/wsconsio.h @@ -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; diff --git a/sys/dev/wscons/wstpad.c b/sys/dev/wscons/wstpad.c index be074b89fb8..c3735cf2416 100644 --- a/sys/dev/wscons/wstpad.c +++ b/sys/dev/wscons/wstpad.c @@ -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); } -- 2.20.1