git: a79397d13228 - main - wsp: Handle horizontal scrolling and create tunable for swipe/scroll.
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 07 Mar 2025 17:55:22 UTC
The branch main has been updated by wulf:
URL: https://cgit.FreeBSD.org/src/commit/?id=a79397d13228b1e2cc00e4f18158966b3d8cac83
commit a79397d13228b1e2cc00e4f18158966b3d8cac83
Author: Joshua Rogers <Joshua@Joshua.Hu>
AuthorDate: 2025-03-07 17:53:35 +0000
Commit: Vladimir Kondratyev <wulf@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 <Joshua@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;