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;

Reply via email to