The branch main has been updated by wulf: URL: https://cgit.FreeBSD.org/src/commit/?id=a79397d13228b1e2cc00e4f18158966b3d8cac83
commit a79397d13228b1e2cc00e4f18158966b3d8cac83 Author: Joshua Rogers <jos...@joshua.hu> AuthorDate: 2025-03-07 17:53:35 +0000 Commit: Vladimir Kondratyev <w...@freebsd.org> CommitDate: 2025-03-07 17:53:35 +0000 wsp: Handle horizontal scrolling and create tunable for swipe/scroll. Previously, a two-finger horizontal scroll would result in a forwards/backwards keyboard event being performed. This patch changes that functionality to be specified via two new sysctls: horizontal_swipe_finger_count and scroll_finger_count. The former specifies how many fingers are used to perform the aforementioned forwards/backwards keyboard event, while the latter specifies how many fingers are used to perform horizontal scrolling. 0 disables each of them. The threshold for scrolling has been coupled into a single tunable: scr_threshold. This tunable is used for both scrolling and the horizontal swipe. t_factor and t_invert tunables have been created in the same manner as their z-axis counterparts. Horizontal scrolling is disabled by default, as it requires the sysctl hw.usb.wsp.t_factor to 3 (wsp mode). Horizontal swiping is enabled by default with a three-finger tap. Also rewrite much of, and improve, documentation. Signed-off-by: Joshua Rogers <jos...@joshua.hu> --- share/man/man4/wsp.4 | 158 ++++++++++++++++++++++++++++++++++++------------ sys/dev/usb/input/wsp.c | 113 ++++++++++++++++++++++++---------- 2 files changed, 200 insertions(+), 71 deletions(-) diff --git a/share/man/man4/wsp.4 b/share/man/man4/wsp.4 index b77d5ac99a7b..de2c121784d4 100644 --- a/share/man/man4/wsp.4 +++ b/share/man/man4/wsp.4 @@ -49,53 +49,131 @@ The driver provides support for the Apple Internal Trackpad device found in many Apple laptops. .Pp -The driver simulates a three-button mouse using multi-finger tap +The driver simulates a three-button mouse using multi-finger press/tap detection. A single-finger press generates a left button click. -A two-finger tap maps to the right button; whereas a three-finger tap -gets treated as a middle button click. +A two-finger press maps to the right button; whereas a three-finger +press gets treated as a middle button click. .Pp +The trackpad functions with presses and taps. A press is a full-forced +press which causes a physical lowering of the trackpad. A tap is a +touch of the trackpad which does not depress the physical trackpad. +.Pp +The .Nm -supports dynamic reconfiguration using +driver supports receiving evdev input device data if enabled. This data +is used for extended usage of the touchpad like multi-finger support, +pressure detection, tap support, and gestures. At least the second bit +of the .Xr sysctl 8 -through nodes under -.Nm hw.usb.wsp . -Pointer sensitivity can be controlled using the sysctl tunable -.Nm hw.usb.wsp.scale_factor . -Tap to left-click can be controlled using the sysctl tunable -.Nm hw.usb.wsp.enable_single_tap_clicks -with 0 disabling single tap clicks and 1 enabling them (default). -Movement on the trackpad following a partially-released click can be -controlled using the sysctl tunable -.Nm hw.usb.wsp.enable_single_tap_movement , -with 0 to disable the movement on the trackpad until a full release -or 1 to allow the continued movement (default). -.Nm hw.usb.wsp.max_finger_area -defines the maximum area on the trackpad which is registered as a -finger (lower for greater palm detection). -.Nm max_scroll_finger_distance -defines the maximum distance between two fingers where z-axis -movements are registered. -.Nm hw.usb.wsp.max_double_tap_distance -defines the maximum distance between two finger clicks or taps which may -register as a double-click. -.Nm hw.usb.wsp.scr_hor_threshold -defines the minimum required horizontal movement to register as a forward -/back button click. -Z-Axis sensitivity can be controlled using the sysctl tunable -.Nm hw.usb.wsp.z_factor . -Z-Axis inversion can be controlled using the sysctl tunable -.Nm hw.usb.wsp.z_invert , -set to 0 to disable (default) or 1 to enable inversion. +tunable +.Nm kern.evdev.rcpt_mask +must be set. This can be enabled with +.Nm kern.evdev.rcpt_mask=3 . .Pp -.Nm -may use evdev data (if enabled during kernel compilation) for gesture support -using the +Vertical scrolling (z-axis) is enabled by default with a two-finger +tap and the movement of a finger up and down. +Horizontal scrolling (t-axis) is not natively supported by the sysmouse +protocol, therefore must be enabled with evdev data. This can be enabled +with the +.Xr sysctl 8 +tunable +.Nm kern.evdev.sysmouse_t_axis=3. +Horizontal scrolling can be used with a two-finger tap and the movement +of a finger from side to side. The .Xr sysctl 8 -value -.Nm kern.evdev.rcpt_mask . -On most MacBooks, setting this value to 3 enables gestures, while 12 -disables them. +tunable +.Nm hw.usb.wsp.t_factor +must be greater than 0 for horizontal scrolling to be enabled, too. +.Pp +Horizontal swiping with a three-finger tap is registered as mouse buttons +8 and 9, depending on the direction. These buttons default to backwards +and forwards keyboard events. +.Sh SYSCTL VARIABLES +The following variables are available as +.Xr sysctl 8 +tunables: +.Bl -tag -width indent +.It Va hw.usb.wsp.scale_factor +Controls the pointer sensitivity. Default is 12. +.El +.Bl -tag -width indent +.It Va hw.usb.wsp.enable_single_tap_clicks +Enables single-tap to register as a left-click. Default is 1 (enabled). +.El +.Bl -tag -width indent +.It Va hw.usb.wsp.enable_single_tap_movement +Enables movement on the trackpad follow a partially-released left-click. +Default is 1 (enabled). +.El +.Bl -tag -width indent +.It Va hw.usb.wsp.max_finger_area +Specifies the maximum area on the trackpad which is registered as a +finger (a lower value is used for palm detection). Default is 1900. +.El +.Bl -tag -width indent +.It Va max_scroll_finger_distance +Specifies the maximum distance between two fingers where z-axis +and t-axis movements are registered. Z-axis and T-axis movements +are vertical and horizontal movements with more than one finger +tapped (not clicked), respectively. Default is 8192. +.El +.Bl -tag -width indent +.It Va hw.usb.wsp.max_double_tap_distance +Specifies the maximum distance between two fingers that a two-finger +click will be registered as a right-click. Default is 2500. +.El +.Bl -tag -width indent +.It Va hw.usb.wsp.scr_threshold +Specifies the minimum horizontal or vertical distance required to +register as a scrolling gesture. Default is 20. +.El +.Bl -tag -width indent +.It Va hw.usb.wsp.z_factor +Z-axis sensitivity. Default is 5. +.El +.Bl -tag -width indent +.It Va hw.usb.wsp.z_invert +Z-axis inversion. Default is 0 (disabled). +.El +.Bl -tag -width indent +.It Va hw.usb.wsp.t_factor +T-axis sensitivity. Default is 0 (disabled). +.El +.Bl -tag -width indent +.It Va hw.usb.wsp.t_invert +T-axis inversion. Default is 0 (disabled). +.El +.Bl -tag -width indent +.It Va hw.usb.wsp.scroll_finger_count +Specifies the number of tapped fingers which registers as a scrolling +movement. Default is 2. +.El +.Bl -tag -width indent +.It Va hw.usb.wsp.horizontal_swipe_finger_count +Speifies the number of tapped fingers which registers as a swipe +gesture. Default is 3. +.El +.Bl -tag -width indent +.It Va hw.usb.wsp.pressure_touch_threshold +Specifies the threshold for a finger to be registered as a click. +Default is 50. +.El +.Bl -tag -width indent +.It Va hw.usb.wsp.pressure_untouch_threshold +Specifies the threshold for a finger to be registered as an unclick. +Default is 10. +.El +.Bl -tag -width indent +.It Va hw.usb.wsp.pressure_tap_threshold +Specifies the threadhold for a finger to be registered as a tap. +Default is 120. +.El +.Bl -tag -width indent +.It Va hw.usb.wsp.debug +Specifies the +.Nm +driver debugging level (0-3). Default is 1. .Sh FILES .Nm creates a blocking pseudo-device file, diff --git a/sys/dev/usb/input/wsp.c b/sys/dev/usb/input/wsp.c index 55b9aadfce86..55289aa40b17 100644 --- a/sys/dev/usb/input/wsp.c +++ b/sys/dev/usb/input/wsp.c @@ -86,17 +86,21 @@ enum wsp_log_level { static int wsp_debug = WSP_LLEVEL_ERROR;/* the default is to only log errors */ SYSCTL_INT(_hw_usb_wsp, OID_AUTO, debug, CTLFLAG_RWTUN, - &wsp_debug, WSP_LLEVEL_ERROR, "WSP debug level"); + &wsp_debug, WSP_LLEVEL_ERROR, "WSP debug level (0-3)"); #endif /* USB_DEBUG */ static struct wsp_tuning { int scale_factor; + int scroll_finger_count; + int horizontal_swipe_finger_count; int z_factor; int z_invert; + int t_factor; + int t_invert; int pressure_touch_threshold; int pressure_untouch_threshold; int pressure_tap_threshold; - int scr_hor_threshold; + int scr_threshold; int max_finger_area; int max_scroll_finger_distance; int max_double_tap_distance; @@ -106,12 +110,16 @@ static struct wsp_tuning { wsp_tuning = { .scale_factor = 12, + .scroll_finger_count = 2, + .horizontal_swipe_finger_count = 3, .z_factor = 5, .z_invert = 0, + .t_factor = 0, + .t_invert = 0, .pressure_touch_threshold = 50, .pressure_untouch_threshold = 10, .pressure_tap_threshold = 120, - .scr_hor_threshold = 50, + .scr_threshold = 20, .max_finger_area = 1900, .max_scroll_finger_distance = MAX_FINGER_ORIENTATION/2, .max_double_tap_distance = 2500, @@ -123,25 +131,37 @@ static void wsp_running_rangecheck(struct wsp_tuning *ptun) { WSP_CLAMP(ptun->scale_factor, 1, 63); - WSP_CLAMP(ptun->z_factor, 1, 63); + WSP_CLAMP(ptun->scroll_finger_count, 0, 3); + WSP_CLAMP(ptun->horizontal_swipe_finger_count, 0, 3); + WSP_CLAMP(ptun->z_factor, 0, 63); WSP_CLAMP(ptun->z_invert, 0, 1); + WSP_CLAMP(ptun->t_factor, 0, 63); + WSP_CLAMP(ptun->t_invert, 0, 1); WSP_CLAMP(ptun->pressure_touch_threshold, 1, 255); WSP_CLAMP(ptun->pressure_untouch_threshold, 1, 255); WSP_CLAMP(ptun->pressure_tap_threshold, 1, 255); WSP_CLAMP(ptun->max_finger_area, 1, 2400); WSP_CLAMP(ptun->max_scroll_finger_distance, 1, MAX_FINGER_ORIENTATION); WSP_CLAMP(ptun->max_double_tap_distance, 1, MAX_FINGER_ORIENTATION); - WSP_CLAMP(ptun->scr_hor_threshold, 1, 255); + WSP_CLAMP(ptun->scr_threshold, 1, 255); WSP_CLAMP(ptun->enable_single_tap_clicks, 0, 1); WSP_CLAMP(ptun->enable_single_tap_movement, 0, 1); } SYSCTL_INT(_hw_usb_wsp, OID_AUTO, scale_factor, CTLFLAG_RWTUN, &wsp_tuning.scale_factor, 0, "movement scale factor"); +SYSCTL_INT(_hw_usb_wsp, OID_AUTO, scroll_finger_count, CTLFLAG_RWTUN, + &wsp_tuning.scroll_finger_count, 0, "amount of fingers to use scrolling gesture"); +SYSCTL_INT(_hw_usb_wsp, OID_AUTO, horizontal_swipe_finger_count, CTLFLAG_RWTUN, + &wsp_tuning.horizontal_swipe_finger_count, 0, "amount of fingers to use horizontal swipe gesture"); SYSCTL_INT(_hw_usb_wsp, OID_AUTO, z_factor, CTLFLAG_RWTUN, - &wsp_tuning.z_factor, 0, "Z-axis scale factor"); + &wsp_tuning.z_factor, 0, "Z-axis (vertical) scale factor"); SYSCTL_INT(_hw_usb_wsp, OID_AUTO, z_invert, CTLFLAG_RWTUN, - &wsp_tuning.z_invert, 0, "enable Z-axis inversion"); + &wsp_tuning.z_invert, 0, "enable (vertical) Z-axis inversion"); +SYSCTL_INT(_hw_usb_wsp, OID_AUTO, t_factor, CTLFLAG_RWTUN, + &wsp_tuning.t_factor, 0, "T-axis (horizontal) scale factor"); +SYSCTL_INT(_hw_usb_wsp, OID_AUTO, t_invert, CTLFLAG_RWTUN, + &wsp_tuning.t_invert, 0, "enable T-axis (horizontal) inversion"); SYSCTL_INT(_hw_usb_wsp, OID_AUTO, pressure_touch_threshold, CTLFLAG_RWTUN, &wsp_tuning.pressure_touch_threshold, 0, "touch pressure threshold"); SYSCTL_INT(_hw_usb_wsp, OID_AUTO, pressure_untouch_threshold, CTLFLAG_RWTUN, @@ -154,8 +174,8 @@ SYSCTL_INT(_hw_usb_wsp, OID_AUTO, max_scroll_finger_distance, CTLFLAG_RWTUN, &wsp_tuning.max_scroll_finger_distance, 0, "maximum scroll finger distance"); SYSCTL_INT(_hw_usb_wsp, OID_AUTO, max_double_tap_distance, CTLFLAG_RWTUN, &wsp_tuning.max_double_tap_distance, 0, "maximum double-finger click distance"); -SYSCTL_INT(_hw_usb_wsp, OID_AUTO, scr_hor_threshold, CTLFLAG_RWTUN, - &wsp_tuning.scr_hor_threshold, 0, "horizontal scrolling threshold"); +SYSCTL_INT(_hw_usb_wsp, OID_AUTO, scr_threshold, CTLFLAG_RWTUN, + &wsp_tuning.scr_threshold, 0, "scrolling threshold"); SYSCTL_INT(_hw_usb_wsp, OID_AUTO, enable_single_tap_clicks, CTLFLAG_RWTUN, &wsp_tuning.enable_single_tap_clicks, 0, "enable single tap clicks"); SYSCTL_INT(_hw_usb_wsp, OID_AUTO, enable_single_tap_movement, CTLFLAG_RWTUN, @@ -1144,11 +1164,12 @@ wsp_intr_callback(struct usb_xfer *xfer, usb_error_t error) } wsp_add_to_queue(sc, 0, 0, 0, 0); /* button release */ } - if ((sc->dt_sum / tun.scr_hor_threshold) != 0 && - sc->ntaps == 2 && sc->scr_mode == WSP_SCR_HOR) { + + if (sc->scr_mode == WSP_SCR_HOR && sc->ntaps == tun.horizontal_swipe_finger_count + && tun.horizontal_swipe_finger_count > 0 && (sc->dt_sum / tun.scr_threshold) != 0) { /* - * translate T-axis into button presses - * until further + * translate T-axis swipe into button + * presses 3 and 4 (forward/back) */ if (sc->dt_sum > 0) wsp_add_to_queue(sc, 0, 0, 0, 1UL << 3); @@ -1234,11 +1255,18 @@ wsp_intr_callback(struct usb_xfer *xfer, usb_error_t error) dx, dy, sc->finger); } if (sc->dz_count--) { - rdz = (dy + sc->rdz) % tun.scale_factor; - sc->dz_sum -= (dy + sc->rdz) / tun.scale_factor; + if (sc->scr_mode == WSP_SCR_HOR) { + rdz = (dx + sc->rdz) % tun.scale_factor; + sc->dz_sum -= (dx + sc->rdz) / tun.scale_factor; + } else if (sc->scr_mode == WSP_SCR_VER) { + rdz = (dy + sc->rdz) % tun.scale_factor; + sc->dz_sum -= (dy + sc->rdz) / tun.scale_factor; + } sc->rdz = rdz; } - if ((sc->dz_sum / tun.z_factor) != 0) + if (sc->scr_mode == WSP_SCR_VER && (tun.z_factor == 0 || (sc->dz_sum / tun.z_factor) != 0)) + sc->dz_count = 0; + else if (sc->scr_mode == WSP_SCR_HOR && (tun.t_factor == 0 || (sc->dz_sum / tun.t_factor) != 0)) sc->dz_count = 0; } rdx = (dx + sc->rdx) % tun.scale_factor; @@ -1252,26 +1280,49 @@ wsp_intr_callback(struct usb_xfer *xfer, usb_error_t error) sc->dx_sum += dx; sc->dy_sum += dy; - if (ntouch == 2 && sc->sc_status.button == 0) { - if (sc->scr_mode == WSP_SCR_NONE && - abs(sc->dx_sum) + abs(sc->dy_sum) > tun.scr_hor_threshold) - sc->scr_mode = abs(sc->dx_sum) > - abs(sc->dy_sum) * 2 ? WSP_SCR_HOR : WSP_SCR_VER; - DPRINTFN(WSP_LLEVEL_INFO, "scr_mode=%5d, count=%d, dx_sum=%d, dy_sum=%d\n", - sc->scr_mode, sc->intr_count, sc->dx_sum, sc->dy_sum); - if (sc->scr_mode == WSP_SCR_HOR) - sc->dt_sum += dx; - else - sc->dt_sum = 0; + if (sc->sc_status.button == 0 && ntouch > 0) { + if (ntouch == tun.scroll_finger_count || ntouch == tun.horizontal_swipe_finger_count) { + if (sc->scr_mode == WSP_SCR_NONE && abs(sc->dx_sum) + abs(sc->dy_sum) > tun.scr_threshold) + sc->scr_mode = abs(sc->dx_sum) > abs(sc->dy_sum) * 2 ? WSP_SCR_HOR : WSP_SCR_VER; - dx = dy = 0; - if (sc->dz_count == 0) - dz = (sc->dz_sum / tun.z_factor) * (tun.z_invert ? -1 : 1); - if (sc->scr_mode == WSP_SCR_HOR || sc->distance > tun.max_scroll_finger_distance) + DPRINTFN(WSP_LLEVEL_INFO, "scr_mode=%5d, count=%d, dx_sum=%d, dy_sum=%d\n", sc->scr_mode, sc->intr_count, sc->dx_sum, sc->dy_sum); + } + + if (ntouch == tun.scroll_finger_count) { /* preference scrolling over swipe if tun.scroll_finger_count == tun.horizontal_swipe_finger_count */ + if (sc->scr_mode == WSP_SCR_HOR) { + sc->sc_status.button = 1 << 5; + } + dx = dy = dz = 0; dz = 0; + sc->dt_sum = 0; + if (sc->distance <= tun.max_scroll_finger_distance && sc->dz_count == 0) { + if (sc->scr_mode == WSP_SCR_VER) { + if (tun.z_factor > 0) + dz = (sc->dz_sum / tun.z_factor) * (tun.z_invert ? -1 : 1); + } else if (sc->scr_mode == WSP_SCR_HOR) { + if (tun.t_factor > 0) + dz = (sc->dz_sum / tun.t_factor) * (tun.t_invert ? -1 : 1); + } + } + } else if (ntouch == tun.horizontal_swipe_finger_count) { + if (sc->scr_mode == WSP_SCR_HOR) { + sc->dt_sum += dx * (tun.t_invert ? -1 : 1); + } else { + sc->dt_sum = 0; + } + dx = dy = dz = 0; + } } + if (ntouch == 3) dx = dy = dz = 0; + + if (ntouch != tun.horizontal_swipe_finger_count) + sc->dt_sum = 0; + + if (ntouch == 0) + sc->scr_mode = WSP_SCR_NONE; + if (sc->intr_count < WSP_TAP_MAX_COUNT && abs(dx) < 3 && abs(dy) < 3 && abs(dz) < 3) dx = dy = dz = 0;