wscons: precision scrolling

classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

wscons: precision scrolling

Ulf Brosziewski
The standard method of scrolling in X is tailored to mouse wheels and
proceeds in coarse steps.  Wheel events are mapped to button events, and on
receiving such an event, an application moves the view of its data by some
fixed distance - usually the height of a line of text, or of a couple of
lines.

Version 2.1 of the X Input Protocol has introduced a more precise
alternative.  It defines additional types of motion events.  In essence,
their values represent fractions of a complete scroll unit, and newer
applications may move their views by distances that are proportional to the
event values.  For applications that don't support this, X generates the
standard button events whenever the values add up to the complete unit.

synaptics(4) supports the newer method since long.

The diffs below add the feature to ws and wstpad.  The kernel part defines
two new event types in wsconsio.h, and it adapts the scrolling functions of
the touchpad input driver.  The xenocara part adds the new "axes" and event
handlers to ws.

There is a little twist to the implementation.  While synaptics(4)
initializes the scroll axes with the scroll distance in device units, the
constant 4096 is used in the new ws code, and event values represent the
fraction (motion_delta / scroll_unit) in [*.12] fixed-point format.  That
way, no queries for the device- and configuration-dependent scroll unit
are necessary.

The X Input Protocol calls the method "smooth scrolling", but it seems
that nowadays, this term is used exclusively for the rendering technique
that displays a little animation when the document position changes, so
"precision scrolling" might be a better choice.

Tests, comments, and OKs would be welcome.


Index: dev/wscons/wsconsio.h
===================================================================
RCS file: /cvs/src/sys/dev/wscons/wsconsio.h,v
retrieving revision 1.90
diff -u -p -r1.90 wsconsio.h
--- dev/wscons/wsconsio.h 10 Nov 2018 14:27:51 -0000 1.90
+++ dev/wscons/wsconsio.h 12 Mar 2019 21:55:11 -0000
@@ -112,6 +112,12 @@ struct wscons_event {
 #define WSCONS_EVENT_TOUCH_RESET 25 /* (no value) */

 /*
+ * Precision Scrolling
+ */
+#define WSCONS_EVENT_HSCROLL 26 /* dx * 4096 / scroll_unit */
+#define WSCONS_EVENT_VSCROLL 27 /* dy * 4096 / scroll_unit */
+
+/*
  * Keyboard ioctls (0 - 31)
  */

Index: dev/wscons/wsmouse.c
===================================================================
RCS file: /cvs/src/sys/dev/wscons/wsmouse.c,v
retrieving revision 1.51
diff -u -p -r1.51 wsmouse.c
--- dev/wscons/wsmouse.c 19 Feb 2019 07:01:02 -0000 1.51
+++ dev/wscons/wsmouse.c 12 Mar 2019 21:55:11 -0000
@@ -1034,10 +1034,18 @@ wsmouse_motion_sync(struct wsmouseinput
  wsmouse_evq_put(evq, DELTA_X_EV(input), dx);
  if (dy)
  wsmouse_evq_put(evq, DELTA_Y_EV(input), dy);
- if (motion->dz)
- wsmouse_evq_put(evq, DELTA_Z_EV, motion->dz);
- if (motion->dw)
- wsmouse_evq_put(evq, DELTA_W_EV, motion->dw);
+ if (motion->dz) {
+ if (IS_TOUCHPAD(input))
+ wsmouse_evq_put(evq, VSCROLL_EV, motion->dz);
+ else
+ wsmouse_evq_put(evq, DELTA_Z_EV, motion->dz);
+ }
+ if (motion->dw) {
+ if (IS_TOUCHPAD(input))
+ wsmouse_evq_put(evq, HSCROLL_EV, motion->dw);
+ else
+ wsmouse_evq_put(evq, DELTA_W_EV, motion->dw);
+ }
  }
  if (motion->sync & SYNC_POSITION) {
  if (motion->sync & SYNC_X) {
Index: dev/wscons/wsmouseinput.h
===================================================================
RCS file: /cvs/src/sys/dev/wscons/wsmouseinput.h,v
retrieving revision 1.12
diff -u -p -r1.12 wsmouseinput.h
--- dev/wscons/wsmouseinput.h 10 Nov 2018 14:27:51 -0000 1.12
+++ dev/wscons/wsmouseinput.h 12 Mar 2019 21:55:12 -0000
@@ -210,6 +210,8 @@ int wstpad_set_param(struct wsmouseinput
     WSCONS_EVENT_MOUSE_ABSOLUTE_X : WSCONS_EVENT_MOUSE_ABSOLUTE_Y)
 #define DELTA_Z_EV WSCONS_EVENT_MOUSE_DELTA_Z
 #define DELTA_W_EV WSCONS_EVENT_MOUSE_DELTA_W
+#define VSCROLL_EV WSCONS_EVENT_VSCROLL
+#define HSCROLL_EV WSCONS_EVENT_HSCROLL
 #define ABS_Z_EV WSCONS_EVENT_TOUCH_PRESSURE
 #define ABS_W_EV WSCONS_EVENT_TOUCH_CONTACTS
 #define BTN_DOWN_EV WSCONS_EVENT_MOUSE_DOWN
Index: dev/wscons/wstpad.c
===================================================================
RCS file: /cvs/src/sys/dev/wscons/wstpad.c,v
retrieving revision 1.22
diff -u -p -r1.22 wstpad.c
--- dev/wscons/wstpad.c 29 Dec 2018 21:03:58 -0000 1.22
+++ dev/wscons/wstpad.c 12 Mar 2019 21:55:12 -0000
@@ -167,8 +167,6 @@ struct wstpad {
  u_int mtcycle;
  u_int ignore;

- int dx;
- int dy;
  int contacts;
  int prev_contacts;
  u_int btns;
@@ -223,12 +221,11 @@ struct wstpad {
  } tap;

  struct {
- int acc_dx;
- int acc_dy;
  int dz;
  int dw;
  int hdist;
  int vdist;
+ int mag;
  } scroll;
 };

@@ -435,8 +432,8 @@ set_freeze_ts(struct wstpad *tp, int sec


 /* Return TRUE if two-finger- or edge-scrolling would be valid. */
-static inline int
-chk_scroll_state(struct wsmouseinput *input)
+int
+wstpad_scroll_coords(struct wsmouseinput *input, int *dx, int *dy)
 {
  struct wstpad *tp = input->tp;

@@ -451,40 +448,43 @@ chk_scroll_state(struct wsmouseinput *in
  * a short delay, is only applied initially, a touch that stops and
  * resumes scrolling is not affected.
  */
- if (tp->scroll.dz || tp->scroll.dw || wstpad_is_stable(input, tp->t))
- return (tp->dx || tp->dy);
+ if (tp->scroll.dz || tp->scroll.dw || wstpad_is_stable(input, tp->t)) {
+ *dx = normalize_rel(&input->filter.h, input->motion.pos.dx);
+ *dy = normalize_rel(&input->filter.v, input->motion.pos.dy);
+ return (*dx || *dy);
+ }

  return (0);
 }

 void
-wstpad_scroll(struct wstpad *tp, int dx, int dy, u_int *cmds)
+wstpad_scroll(struct wstpad *tp, int dx, int dy, int mag, u_int *cmds)
 {
- int sign;
+ int dz, dw, n = 1;

- /* Scrolling is either horizontal or vertical, but not both. */
-
- sign = (dy > 0) - (dy < 0);
- if (sign) {
- if (tp->scroll.dz != -sign) {
- tp->scroll.dz = -sign;
- tp->scroll.acc_dy = -tp->scroll.vdist;
- }
- tp->scroll.acc_dy += abs(dy);
- if (tp->scroll.acc_dy >= 0) {
- tp->scroll.acc_dy -= tp->scroll.vdist;
- *cmds |= 1 << VSCROLL;
- }
- } else if ((sign = (dx > 0) - (dx < 0))) {
- if (tp->scroll.dw != sign) {
- tp->scroll.dw = sign;
- tp->scroll.acc_dx = -tp->scroll.hdist;
- }
- tp->scroll.acc_dx += abs(dx);
- if (tp->scroll.acc_dx >= 0) {
- tp->scroll.acc_dx -= tp->scroll.hdist;
- *cmds |= 1 << HSCROLL;
- }
+ /*
+ * The function applies strong deceleration, but only to input with
+ * very low speeds.  A higher threshold might make applications
+ * without support for precision scrolling appear unresponsive.
+ */
+ mag = tp->scroll.mag = imin(MAG_MEDIUM,
+    (mag + 3 * tp->scroll.mag) / 4);
+ if (mag < MAG_LOW)
+ n = (MAG_LOW - mag) / 4096 + 1;
+
+ if (dy && tp->scroll.vdist) {
+ dz = -dy * 4096 / (tp->scroll.vdist * n);
+ if (tp->scroll.dz && (dy < 0 == tp->scroll.dz > 0))
+ dz = (dz + 3 * tp->scroll.dz) / 4;
+ tp->scroll.dz = dz;
+ *cmds |= 1 << VSCROLL;
+
+ } else if (dx && tp->scroll.hdist) {
+ dw = dx * 4096 / (tp->scroll.hdist * n);
+ if (tp->scroll.dw && (dx > 0 == tp->scroll.dw > 0))
+ dw = (dw + 3 * tp->scroll.dw) / 4;
+ tp->scroll.dw = dw;
+ *cmds |= 1 << HSCROLL;
  }
 }

@@ -502,12 +502,14 @@ wstpad_f2scroll(struct wsmouseinput *inp
  return;
  }

- if (!chk_scroll_state(input))
+ if (!wstpad_scroll_coords(input, &dx, &dy))
  return;

  dir = tp->t->dir;
- dy = NORTH(dir) || SOUTH(dir) ? tp->dy : 0;
- dx = EAST(dir) || WEST(dir) ? tp->dx : 0;
+ if (!(NORTH(dir) || SOUTH(dir)))
+ dy = 0;
+ if (!(EAST(dir) || WEST(dir)))
+ dx = 0;

  if (dx || dy) {
  centered = CENTERED(tp->t);
@@ -526,7 +528,8 @@ wstpad_f2scroll(struct wsmouseinput *inp
  centered |= CENTERED(t2);
  }
  if (centered) {
- wstpad_scroll(tp, dx, dy, cmds);
+ wstpad_scroll(tp, dx, dy,
+    magnitude(input, dx, dy), cmds);
  set_freeze_ts(tp, 0, FREEZE_MS);
  }
  }
@@ -540,17 +543,19 @@ wstpad_edgescroll(struct wsmouseinput *i
  u_int v_edge, b_edge;
  int dx, dy;

- if (tp->contacts != 1 || !chk_scroll_state(input))
+ if (!wstpad_scroll_coords(input, &dx, &dy) || tp->contacts != 1)
  return;

  v_edge = (tp->features & WSTPAD_SWAPSIDES) ? L_EDGE : R_EDGE;
  b_edge = (tp->features & WSTPAD_HORIZSCROLL) ? B_EDGE : 0;

- dy = (t->flags & v_edge) ? tp->dy : 0;
- dx = (t->flags & b_edge) ? tp->dx : 0;
+ if ((t->flags & v_edge) == 0)
+ dy = 0;
+ if ((t->flags & b_edge) == 0)
+ dx = 0;

  if (dx || dy)
- wstpad_scroll(tp, dx, dy, cmds);
+ wstpad_scroll(tp, dx, dy, magnitude(input, dx, dy), cmds);
 }

 static inline u_int
@@ -1121,20 +1126,7 @@ wstpad_touch_inputs(struct wsmouseinput
 {
  struct wstpad *tp = input->tp;
  struct tpad_touch *t;
- int slot;
-
- /*
- * Use the normalized, hysteresis-filtered, but otherwise untransformed
- * relative coordinates of the pointer-controlling touch for filtering
- * and scrolling.
- */
- if ((input->motion.sync & SYNC_POSITION)
-    && !wsmouse_hysteresis(input, &input->motion.pos)) {
- tp->dx = normalize_rel(&input->filter.h, input->motion.pos.dx);
- tp->dy = normalize_rel(&input->filter.v, input->motion.pos.dy);
- } else {
- tp->dx = tp->dy = 0;
- }
+ int slot, x, y, dx, dy;

  tp->btns = input->btn.buttons;
  tp->btns_sync = input->btn.sync;
@@ -1158,8 +1150,6 @@ wstpad_touch_inputs(struct wsmouseinput
  wstpad_mt_masks(input);
  } else {
  t = tp->t;
- t->x = normalize_abs(&input->filter.h, t->pos->x);
- t->y = normalize_abs(&input->filter.v, t->pos->y);
  if (tp->contacts)
  t->state = (tp->prev_contacts ?
     TOUCH_UPDATE : TOUCH_BEGIN);
@@ -1167,17 +1157,25 @@ wstpad_touch_inputs(struct wsmouseinput
  t->state = (tp->prev_contacts ?
     TOUCH_END : TOUCH_NONE);

+ dx = dy = 0;
+ x = normalize_abs(&input->filter.h, t->pos->x);
+ y = normalize_abs(&input->filter.v, t->pos->y);
  if (t->state == TOUCH_BEGIN) {
- t->orig.x = t->x;
- t->orig.y = t->y;
+ t->x = t->orig.x = x;
+ t->y = t->orig.y = y;
  memcpy(&t->orig.time, &tp->time,
     sizeof(struct timespec));
- t->flags = edge_flags(tp, t->x, t->y);
- } else {
- t->flags &= (~EDGES | edge_flags(tp, t->x, t->y));
+ t->flags = edge_flags(tp, x, y);
+ } else if (input->motion.sync & SYNC_POSITION) {
+ if (!wsmouse_hysteresis(input, t->pos)) {
+ dx = x - t->x;
+ dy = y - t->y;
+ }
+ t->x = x;
+ t->y = y;
+ t->flags &= (~EDGES | edge_flags(tp, x, y));
  }
-
- wstpad_set_direction(tp, t, tp->dx, tp->dy);
+ wstpad_set_direction(tp, t, dx, dy);
  }
 }


Index: driver/xf86-input-ws/src/ws.c
===================================================================
RCS file: /cvs/xenocara/driver/xf86-input-ws/src/ws.c,v
retrieving revision 1.63
diff -u -p -r1.63 ws.c
--- driver/xf86-input-ws/src/ws.c 31 Dec 2017 23:31:41 -0000 1.63
+++ driver/xf86-input-ws/src/ws.c 11 Mar 2019 21:09:28 -0000
@@ -363,6 +363,10 @@ wsDeviceInit(DeviceIntPtr pWS)
  axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X);
  axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y);
  }
+ axes_labels[HSCROLL_AXIS] =
+    XIGetKnownProperty(AXIS_LABEL_PROP_REL_HSCROLL);
+ axes_labels[VSCROLL_AXIS] =
+    XIGetKnownProperty(AXIS_LABEL_PROP_REL_VSCROLL);
  if (!InitValuatorClassDeviceStruct(pWS,
     NAXES, axes_labels, GetMotionHistorySize(),
     priv->type == WSMOUSE_TYPE_TPANEL ? Absolute : Relative))
@@ -382,6 +386,25 @@ wsDeviceInit(DeviceIntPtr pWS)
     priv->type == WSMOUSE_TYPE_TPANEL ? Absolute : Relative);
  xf86InitValuatorDefaults(pWS, 1);

+ xf86InitValuatorAxisStruct(pWS, HSCROLL_AXIS,
+    axes_labels[HSCROLL_AXIS], 0, -1, 0, 0, 0, Relative);
+ xf86InitValuatorAxisStruct(pWS, VSCROLL_AXIS,
+    axes_labels[VSCROLL_AXIS], 0, -1, 0, 0, 0, Relative);
+ priv->scroll_mask = valuator_mask_new(MAX_VALUATORS);
+ if (!priv->scroll_mask) {
+ free(axes_labels);
+ return !Success;
+ }
+
+ /*
+ * The value of an HSCROLL or VSCROLL event is the fraction
+ *         motion_delta / scroll_distance
+ * in [*.12] fixed-point format.  The 'increment' attribute of the
+ * scroll axes is constant:
+ */
+ SetScrollValuator(pWS, HSCROLL_AXIS, SCROLL_TYPE_HORIZONTAL, 4096, 0);
+ SetScrollValuator(pWS, VSCROLL_AXIS, SCROLL_TYPE_VERTICAL, 4096, 0);
+
  pWS->public.on = FALSE;
  if (wsOpen(pInfo) != Success) {
  return !Success;
@@ -579,6 +602,14 @@ wsReadHwState(InputInfoPtr pInfo, wsHwSt
  case WSCONS_EVENT_SYNC:
  DBG(4, ErrorF("Sync\n"));
  return TRUE;
+ case WSCONS_EVENT_HSCROLL:
+ hw->hscroll = event->value;
+ DBG(4, ErrorF("Horiz. Scrolling %d\n", event->value));
+ return TRUE;
+ case WSCONS_EVENT_VSCROLL:
+ hw->vscroll = event->value;
+ DBG(4, ErrorF("Vert. Scrolling %d\n", event->value));
+ return TRUE;
  default:
  xf86IDrvMsg(pInfo, X_WARNING,
     "bad wsmouse event type=%d\n", event->type);
@@ -623,6 +654,14 @@ wsReadInput(InputInfoPtr pInfo)
  wbutton = (hw.dw < 0) ? priv->W.negative : priv->W.positive;
  DBG(4, ErrorF("W -> button %d (%d)\n", wbutton, abs(hw.dw)));
  wsButtonClicks(pInfo, wbutton, abs(hw.dw));
+ }
+ if (hw.hscroll || hw.vscroll) {
+ valuator_mask_zero(priv->scroll_mask);
+ valuator_mask_set_double(priv->scroll_mask,
+    HSCROLL_AXIS, (double) hw.hscroll);
+ valuator_mask_set_double(priv->scroll_mask,
+    VSCROLL_AXIS, (double) hw.vscroll);
+ xf86PostMotionEventM(pInfo->dev, FALSE, priv->scroll_mask);
  }
  if (priv->lastButtons != hw.buttons) {
  /* button event */
Index: driver/xf86-input-ws/src/ws.h
===================================================================
RCS file: /cvs/xenocara/driver/xf86-input-ws/src/ws.h,v
retrieving revision 1.15
diff -u -p -r1.15 ws.h
--- driver/xf86-input-ws/src/ws.h 31 Dec 2017 23:31:41 -0000 1.15
+++ driver/xf86-input-ws/src/ws.h 11 Mar 2019 21:09:28 -0000
@@ -26,7 +26,10 @@ extern int ws_debug_level;
 # define DBG(lvl, f)
 #endif

-#define NAXES 2 /* X and Y axes only */
+#define NAXES 4 /* X, Y, horizontal and vertical scrolling */
+#define HSCROLL_AXIS 2
+#define VSCROLL_AXIS 3
+
 #define NBUTTONS 32 /* max theoretical buttons */
 #define DFLTBUTTONS 3 /* default number of buttons */

@@ -45,6 +48,7 @@ typedef struct {
  unsigned int buttons;
  int dx, dy, dz, dw;
  int ax, ay;
+ int hscroll, vscroll;
 } wsHwState;

 typedef struct WSDevice {
@@ -86,6 +90,8 @@ typedef struct WSDevice {
  Time expires; /* time of expiry */
  Time timeout;
  } emulateWheel;
+
+ ValuatorMask *scroll_mask;

  OsTimerPtr remove_timer; /* Callback for removal on EIO */

Reply | Threaded
Open this post in threaded view
|

Re: wscons: precision scrolling

Martin Pieuchot
On 13/03/19(Wed) 00:41, Ulf Brosziewski wrote:

> The standard method of scrolling in X is tailored to mouse wheels and
> proceeds in coarse steps.  Wheel events are mapped to button events, and on
> receiving such an event, an application moves the view of its data by some
> fixed distance - usually the height of a line of text, or of a couple of
> lines.
>
> Version 2.1 of the X Input Protocol has introduced a more precise
> alternative.  It defines additional types of motion events.  In essence,
> their values represent fractions of a complete scroll unit, and newer
> applications may move their views by distances that are proportional to the
> event values.  For applications that don't support this, X generates the
> standard button events whenever the values add up to the complete unit.
>
> synaptics(4) supports the newer method since long.
>
> The diffs below add the feature to ws and wstpad.  The kernel part defines
> two new event types in wsconsio.h, and it adapts the scrolling functions of
> the touchpad input driver.  The xenocara part adds the new "axes" and event
> handlers to ws.
>
> There is a little twist to the implementation.  While synaptics(4)
> initializes the scroll axes with the scroll distance in device units, the
> constant 4096 is used in the new ws code, and event values represent the
> fraction (motion_delta / scroll_unit) in [*.12] fixed-point format.  That
> way, no queries for the device- and configuration-dependent scroll unit
> are necessary.
>
> The X Input Protocol calls the method "smooth scrolling", but it seems
> that nowadays, this term is used exclusively for the rendering technique
> that displays a little animation when the document position changes, so
> "precision scrolling" might be a better choice.
>
> Tests, comments, and OKs would be welcome.

I like it.  Implementation is nice.  I find the *_EV defines confusing.
Why not use the WSCONS_* defines directly, it would make easier for the
reader to find which code generates which event in a single grep.  But
that's not new ;)

Do you know if it would make sense to get rid of the standard scrolling
method?  Could we generate such events for all input devices?  Does
other X drivers do that already or plan to do it?

> Index: dev/wscons/wsconsio.h
> ===================================================================
> RCS file: /cvs/src/sys/dev/wscons/wsconsio.h,v
> retrieving revision 1.90
> diff -u -p -r1.90 wsconsio.h
> --- dev/wscons/wsconsio.h 10 Nov 2018 14:27:51 -0000 1.90
> +++ dev/wscons/wsconsio.h 12 Mar 2019 21:55:11 -0000
> @@ -112,6 +112,12 @@ struct wscons_event {
>  #define WSCONS_EVENT_TOUCH_RESET 25 /* (no value) */
>
>  /*
> + * Precision Scrolling
> + */
> +#define WSCONS_EVENT_HSCROLL 26 /* dx * 4096 / scroll_unit */
> +#define WSCONS_EVENT_VSCROLL 27 /* dy * 4096 / scroll_unit */
> +
> +/*
>   * Keyboard ioctls (0 - 31)
>   */
>
> Index: dev/wscons/wsmouse.c
> ===================================================================
> RCS file: /cvs/src/sys/dev/wscons/wsmouse.c,v
> retrieving revision 1.51
> diff -u -p -r1.51 wsmouse.c
> --- dev/wscons/wsmouse.c 19 Feb 2019 07:01:02 -0000 1.51
> +++ dev/wscons/wsmouse.c 12 Mar 2019 21:55:11 -0000
> @@ -1034,10 +1034,18 @@ wsmouse_motion_sync(struct wsmouseinput
>   wsmouse_evq_put(evq, DELTA_X_EV(input), dx);
>   if (dy)
>   wsmouse_evq_put(evq, DELTA_Y_EV(input), dy);
> - if (motion->dz)
> - wsmouse_evq_put(evq, DELTA_Z_EV, motion->dz);
> - if (motion->dw)
> - wsmouse_evq_put(evq, DELTA_W_EV, motion->dw);
> + if (motion->dz) {
> + if (IS_TOUCHPAD(input))
> + wsmouse_evq_put(evq, VSCROLL_EV, motion->dz);
> + else
> + wsmouse_evq_put(evq, DELTA_Z_EV, motion->dz);
> + }
> + if (motion->dw) {
> + if (IS_TOUCHPAD(input))
> + wsmouse_evq_put(evq, HSCROLL_EV, motion->dw);
> + else
> + wsmouse_evq_put(evq, DELTA_W_EV, motion->dw);
> + }
>   }
>   if (motion->sync & SYNC_POSITION) {
>   if (motion->sync & SYNC_X) {
> Index: dev/wscons/wsmouseinput.h
> ===================================================================
> RCS file: /cvs/src/sys/dev/wscons/wsmouseinput.h,v
> retrieving revision 1.12
> diff -u -p -r1.12 wsmouseinput.h
> --- dev/wscons/wsmouseinput.h 10 Nov 2018 14:27:51 -0000 1.12
> +++ dev/wscons/wsmouseinput.h 12 Mar 2019 21:55:12 -0000
> @@ -210,6 +210,8 @@ int wstpad_set_param(struct wsmouseinput
>      WSCONS_EVENT_MOUSE_ABSOLUTE_X : WSCONS_EVENT_MOUSE_ABSOLUTE_Y)
>  #define DELTA_Z_EV WSCONS_EVENT_MOUSE_DELTA_Z
>  #define DELTA_W_EV WSCONS_EVENT_MOUSE_DELTA_W
> +#define VSCROLL_EV WSCONS_EVENT_VSCROLL
> +#define HSCROLL_EV WSCONS_EVENT_HSCROLL
>  #define ABS_Z_EV WSCONS_EVENT_TOUCH_PRESSURE
>  #define ABS_W_EV WSCONS_EVENT_TOUCH_CONTACTS
>  #define BTN_DOWN_EV WSCONS_EVENT_MOUSE_DOWN
> Index: dev/wscons/wstpad.c
> ===================================================================
> RCS file: /cvs/src/sys/dev/wscons/wstpad.c,v
> retrieving revision 1.22
> diff -u -p -r1.22 wstpad.c
> --- dev/wscons/wstpad.c 29 Dec 2018 21:03:58 -0000 1.22
> +++ dev/wscons/wstpad.c 12 Mar 2019 21:55:12 -0000
> @@ -167,8 +167,6 @@ struct wstpad {
>   u_int mtcycle;
>   u_int ignore;
>
> - int dx;
> - int dy;
>   int contacts;
>   int prev_contacts;
>   u_int btns;
> @@ -223,12 +221,11 @@ struct wstpad {
>   } tap;
>
>   struct {
> - int acc_dx;
> - int acc_dy;
>   int dz;
>   int dw;
>   int hdist;
>   int vdist;
> + int mag;
>   } scroll;
>  };
>
> @@ -435,8 +432,8 @@ set_freeze_ts(struct wstpad *tp, int sec
>
>
>  /* Return TRUE if two-finger- or edge-scrolling would be valid. */
> -static inline int
> -chk_scroll_state(struct wsmouseinput *input)
> +int
> +wstpad_scroll_coords(struct wsmouseinput *input, int *dx, int *dy)
>  {
>   struct wstpad *tp = input->tp;
>
> @@ -451,40 +448,43 @@ chk_scroll_state(struct wsmouseinput *in
>   * a short delay, is only applied initially, a touch that stops and
>   * resumes scrolling is not affected.
>   */
> - if (tp->scroll.dz || tp->scroll.dw || wstpad_is_stable(input, tp->t))
> - return (tp->dx || tp->dy);
> + if (tp->scroll.dz || tp->scroll.dw || wstpad_is_stable(input, tp->t)) {
> + *dx = normalize_rel(&input->filter.h, input->motion.pos.dx);
> + *dy = normalize_rel(&input->filter.v, input->motion.pos.dy);
> + return (*dx || *dy);
> + }
>
>   return (0);
>  }
>
>  void
> -wstpad_scroll(struct wstpad *tp, int dx, int dy, u_int *cmds)
> +wstpad_scroll(struct wstpad *tp, int dx, int dy, int mag, u_int *cmds)
>  {
> - int sign;
> + int dz, dw, n = 1;
>
> - /* Scrolling is either horizontal or vertical, but not both. */
> -
> - sign = (dy > 0) - (dy < 0);
> - if (sign) {
> - if (tp->scroll.dz != -sign) {
> - tp->scroll.dz = -sign;
> - tp->scroll.acc_dy = -tp->scroll.vdist;
> - }
> - tp->scroll.acc_dy += abs(dy);
> - if (tp->scroll.acc_dy >= 0) {
> - tp->scroll.acc_dy -= tp->scroll.vdist;
> - *cmds |= 1 << VSCROLL;
> - }
> - } else if ((sign = (dx > 0) - (dx < 0))) {
> - if (tp->scroll.dw != sign) {
> - tp->scroll.dw = sign;
> - tp->scroll.acc_dx = -tp->scroll.hdist;
> - }
> - tp->scroll.acc_dx += abs(dx);
> - if (tp->scroll.acc_dx >= 0) {
> - tp->scroll.acc_dx -= tp->scroll.hdist;
> - *cmds |= 1 << HSCROLL;
> - }
> + /*
> + * The function applies strong deceleration, but only to input with
> + * very low speeds.  A higher threshold might make applications
> + * without support for precision scrolling appear unresponsive.
> + */
> + mag = tp->scroll.mag = imin(MAG_MEDIUM,
> +    (mag + 3 * tp->scroll.mag) / 4);
> + if (mag < MAG_LOW)
> + n = (MAG_LOW - mag) / 4096 + 1;
> +
> + if (dy && tp->scroll.vdist) {
> + dz = -dy * 4096 / (tp->scroll.vdist * n);
> + if (tp->scroll.dz && (dy < 0 == tp->scroll.dz > 0))
> + dz = (dz + 3 * tp->scroll.dz) / 4;
> + tp->scroll.dz = dz;
> + *cmds |= 1 << VSCROLL;
> +
> + } else if (dx && tp->scroll.hdist) {
> + dw = dx * 4096 / (tp->scroll.hdist * n);
> + if (tp->scroll.dw && (dx > 0 == tp->scroll.dw > 0))
> + dw = (dw + 3 * tp->scroll.dw) / 4;
> + tp->scroll.dw = dw;
> + *cmds |= 1 << HSCROLL;
>   }
>  }
>
> @@ -502,12 +502,14 @@ wstpad_f2scroll(struct wsmouseinput *inp
>   return;
>   }
>
> - if (!chk_scroll_state(input))
> + if (!wstpad_scroll_coords(input, &dx, &dy))
>   return;
>
>   dir = tp->t->dir;
> - dy = NORTH(dir) || SOUTH(dir) ? tp->dy : 0;
> - dx = EAST(dir) || WEST(dir) ? tp->dx : 0;
> + if (!(NORTH(dir) || SOUTH(dir)))
> + dy = 0;
> + if (!(EAST(dir) || WEST(dir)))
> + dx = 0;
>
>   if (dx || dy) {
>   centered = CENTERED(tp->t);
> @@ -526,7 +528,8 @@ wstpad_f2scroll(struct wsmouseinput *inp
>   centered |= CENTERED(t2);
>   }
>   if (centered) {
> - wstpad_scroll(tp, dx, dy, cmds);
> + wstpad_scroll(tp, dx, dy,
> +    magnitude(input, dx, dy), cmds);
>   set_freeze_ts(tp, 0, FREEZE_MS);
>   }
>   }
> @@ -540,17 +543,19 @@ wstpad_edgescroll(struct wsmouseinput *i
>   u_int v_edge, b_edge;
>   int dx, dy;
>
> - if (tp->contacts != 1 || !chk_scroll_state(input))
> + if (!wstpad_scroll_coords(input, &dx, &dy) || tp->contacts != 1)
>   return;
>
>   v_edge = (tp->features & WSTPAD_SWAPSIDES) ? L_EDGE : R_EDGE;
>   b_edge = (tp->features & WSTPAD_HORIZSCROLL) ? B_EDGE : 0;
>
> - dy = (t->flags & v_edge) ? tp->dy : 0;
> - dx = (t->flags & b_edge) ? tp->dx : 0;
> + if ((t->flags & v_edge) == 0)
> + dy = 0;
> + if ((t->flags & b_edge) == 0)
> + dx = 0;
>
>   if (dx || dy)
> - wstpad_scroll(tp, dx, dy, cmds);
> + wstpad_scroll(tp, dx, dy, magnitude(input, dx, dy), cmds);
>  }
>
>  static inline u_int
> @@ -1121,20 +1126,7 @@ wstpad_touch_inputs(struct wsmouseinput
>  {
>   struct wstpad *tp = input->tp;
>   struct tpad_touch *t;
> - int slot;
> -
> - /*
> - * Use the normalized, hysteresis-filtered, but otherwise untransformed
> - * relative coordinates of the pointer-controlling touch for filtering
> - * and scrolling.
> - */
> - if ((input->motion.sync & SYNC_POSITION)
> -    && !wsmouse_hysteresis(input, &input->motion.pos)) {
> - tp->dx = normalize_rel(&input->filter.h, input->motion.pos.dx);
> - tp->dy = normalize_rel(&input->filter.v, input->motion.pos.dy);
> - } else {
> - tp->dx = tp->dy = 0;
> - }
> + int slot, x, y, dx, dy;
>
>   tp->btns = input->btn.buttons;
>   tp->btns_sync = input->btn.sync;
> @@ -1158,8 +1150,6 @@ wstpad_touch_inputs(struct wsmouseinput
>   wstpad_mt_masks(input);
>   } else {
>   t = tp->t;
> - t->x = normalize_abs(&input->filter.h, t->pos->x);
> - t->y = normalize_abs(&input->filter.v, t->pos->y);
>   if (tp->contacts)
>   t->state = (tp->prev_contacts ?
>      TOUCH_UPDATE : TOUCH_BEGIN);
> @@ -1167,17 +1157,25 @@ wstpad_touch_inputs(struct wsmouseinput
>   t->state = (tp->prev_contacts ?
>      TOUCH_END : TOUCH_NONE);
>
> + dx = dy = 0;
> + x = normalize_abs(&input->filter.h, t->pos->x);
> + y = normalize_abs(&input->filter.v, t->pos->y);
>   if (t->state == TOUCH_BEGIN) {
> - t->orig.x = t->x;
> - t->orig.y = t->y;
> + t->x = t->orig.x = x;
> + t->y = t->orig.y = y;
>   memcpy(&t->orig.time, &tp->time,
>      sizeof(struct timespec));
> - t->flags = edge_flags(tp, t->x, t->y);
> - } else {
> - t->flags &= (~EDGES | edge_flags(tp, t->x, t->y));
> + t->flags = edge_flags(tp, x, y);
> + } else if (input->motion.sync & SYNC_POSITION) {
> + if (!wsmouse_hysteresis(input, t->pos)) {
> + dx = x - t->x;
> + dy = y - t->y;
> + }
> + t->x = x;
> + t->y = y;
> + t->flags &= (~EDGES | edge_flags(tp, x, y));
>   }
> -
> - wstpad_set_direction(tp, t, tp->dx, tp->dy);
> + wstpad_set_direction(tp, t, dx, dy);
>   }
>  }
>
>
> Index: driver/xf86-input-ws/src/ws.c
> ===================================================================
> RCS file: /cvs/xenocara/driver/xf86-input-ws/src/ws.c,v
> retrieving revision 1.63
> diff -u -p -r1.63 ws.c
> --- driver/xf86-input-ws/src/ws.c 31 Dec 2017 23:31:41 -0000 1.63
> +++ driver/xf86-input-ws/src/ws.c 11 Mar 2019 21:09:28 -0000
> @@ -363,6 +363,10 @@ wsDeviceInit(DeviceIntPtr pWS)
>   axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X);
>   axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y);
>   }
> + axes_labels[HSCROLL_AXIS] =
> +    XIGetKnownProperty(AXIS_LABEL_PROP_REL_HSCROLL);
> + axes_labels[VSCROLL_AXIS] =
> +    XIGetKnownProperty(AXIS_LABEL_PROP_REL_VSCROLL);
>   if (!InitValuatorClassDeviceStruct(pWS,
>      NAXES, axes_labels, GetMotionHistorySize(),
>      priv->type == WSMOUSE_TYPE_TPANEL ? Absolute : Relative))
> @@ -382,6 +386,25 @@ wsDeviceInit(DeviceIntPtr pWS)
>      priv->type == WSMOUSE_TYPE_TPANEL ? Absolute : Relative);
>   xf86InitValuatorDefaults(pWS, 1);
>
> + xf86InitValuatorAxisStruct(pWS, HSCROLL_AXIS,
> +    axes_labels[HSCROLL_AXIS], 0, -1, 0, 0, 0, Relative);
> + xf86InitValuatorAxisStruct(pWS, VSCROLL_AXIS,
> +    axes_labels[VSCROLL_AXIS], 0, -1, 0, 0, 0, Relative);
> + priv->scroll_mask = valuator_mask_new(MAX_VALUATORS);
> + if (!priv->scroll_mask) {
> + free(axes_labels);
> + return !Success;
> + }
> +
> + /*
> + * The value of an HSCROLL or VSCROLL event is the fraction
> + *         motion_delta / scroll_distance
> + * in [*.12] fixed-point format.  The 'increment' attribute of the
> + * scroll axes is constant:
> + */
> + SetScrollValuator(pWS, HSCROLL_AXIS, SCROLL_TYPE_HORIZONTAL, 4096, 0);
> + SetScrollValuator(pWS, VSCROLL_AXIS, SCROLL_TYPE_VERTICAL, 4096, 0);
> +
>   pWS->public.on = FALSE;
>   if (wsOpen(pInfo) != Success) {
>   return !Success;
> @@ -579,6 +602,14 @@ wsReadHwState(InputInfoPtr pInfo, wsHwSt
>   case WSCONS_EVENT_SYNC:
>   DBG(4, ErrorF("Sync\n"));
>   return TRUE;
> + case WSCONS_EVENT_HSCROLL:
> + hw->hscroll = event->value;
> + DBG(4, ErrorF("Horiz. Scrolling %d\n", event->value));
> + return TRUE;
> + case WSCONS_EVENT_VSCROLL:
> + hw->vscroll = event->value;
> + DBG(4, ErrorF("Vert. Scrolling %d\n", event->value));
> + return TRUE;
>   default:
>   xf86IDrvMsg(pInfo, X_WARNING,
>      "bad wsmouse event type=%d\n", event->type);
> @@ -623,6 +654,14 @@ wsReadInput(InputInfoPtr pInfo)
>   wbutton = (hw.dw < 0) ? priv->W.negative : priv->W.positive;
>   DBG(4, ErrorF("W -> button %d (%d)\n", wbutton, abs(hw.dw)));
>   wsButtonClicks(pInfo, wbutton, abs(hw.dw));
> + }
> + if (hw.hscroll || hw.vscroll) {
> + valuator_mask_zero(priv->scroll_mask);
> + valuator_mask_set_double(priv->scroll_mask,
> +    HSCROLL_AXIS, (double) hw.hscroll);
> + valuator_mask_set_double(priv->scroll_mask,
> +    VSCROLL_AXIS, (double) hw.vscroll);
> + xf86PostMotionEventM(pInfo->dev, FALSE, priv->scroll_mask);
>   }
>   if (priv->lastButtons != hw.buttons) {
>   /* button event */
> Index: driver/xf86-input-ws/src/ws.h
> ===================================================================
> RCS file: /cvs/xenocara/driver/xf86-input-ws/src/ws.h,v
> retrieving revision 1.15
> diff -u -p -r1.15 ws.h
> --- driver/xf86-input-ws/src/ws.h 31 Dec 2017 23:31:41 -0000 1.15
> +++ driver/xf86-input-ws/src/ws.h 11 Mar 2019 21:09:28 -0000
> @@ -26,7 +26,10 @@ extern int ws_debug_level;
>  # define DBG(lvl, f)
>  #endif
>
> -#define NAXES 2 /* X and Y axes only */
> +#define NAXES 4 /* X, Y, horizontal and vertical scrolling */
> +#define HSCROLL_AXIS 2
> +#define VSCROLL_AXIS 3
> +
>  #define NBUTTONS 32 /* max theoretical buttons */
>  #define DFLTBUTTONS 3 /* default number of buttons */
>
> @@ -45,6 +48,7 @@ typedef struct {
>   unsigned int buttons;
>   int dx, dy, dz, dw;
>   int ax, ay;
> + int hscroll, vscroll;
>  } wsHwState;
>
>  typedef struct WSDevice {
> @@ -86,6 +90,8 @@ typedef struct WSDevice {
>   Time expires; /* time of expiry */
>   Time timeout;
>   } emulateWheel;
> +
> + ValuatorMask *scroll_mask;
>
>   OsTimerPtr remove_timer; /* Callback for removal on EIO */
>

Reply | Threaded
Open this post in threaded view
|

Re: wscons: precision scrolling

joshua stein-3
In reply to this post by Ulf Brosziewski
On Wed, 13 Mar 2019 at 00:41:12 +0100, Ulf Brosziewski wrote:

> The standard method of scrolling in X is tailored to mouse wheels and
> proceeds in coarse steps.  Wheel events are mapped to button events, and on
> receiving such an event, an application moves the view of its data by some
> fixed distance - usually the height of a line of text, or of a couple of
> lines.
>
> Version 2.1 of the X Input Protocol has introduced a more precise
> alternative.  It defines additional types of motion events.  In essence,
> their values represent fractions of a complete scroll unit, and newer
> applications may move their views by distances that are proportional to the
> event values.  For applications that don't support this, X generates the
> standard button events whenever the values add up to the complete unit.
>
> synaptics(4) supports the newer method since long.
>
> The diffs below add the feature to ws and wstpad.  The kernel part defines
> two new event types in wsconsio.h, and it adapts the scrolling functions of
> the touchpad input driver.  The xenocara part adds the new "axes" and event
> handlers to ws.
>
> There is a little twist to the implementation.  While synaptics(4)
> initializes the scroll axes with the scroll distance in device units, the
> constant 4096 is used in the new ws code, and event values represent the
> fraction (motion_delta / scroll_unit) in [*.12] fixed-point format.  That
> way, no queries for the device- and configuration-dependent scroll unit
> are necessary.
>
> The X Input Protocol calls the method "smooth scrolling", but it seems
> that nowadays, this term is used exclusively for the rendering technique
> that displays a little animation when the document position changes, so
> "precision scrolling" might be a better choice.
>
> Tests, comments, and OKs would be welcome.

Well done!  It works on my touchpad and retains the old "chunky"
style scrolling from the mouse wheel on my external mouse.

My only quibble is that this new style scrolling seems much too fast
by default with the default X and wscons mouse acceleration
settings.

Reply | Threaded
Open this post in threaded view
|

Re: wscons: precision scrolling

Ulf Brosziewski
On 3/13/19 5:27 PM, joshua stein wrote:

> On Wed, 13 Mar 2019 at 00:41:12 +0100, Ulf Brosziewski wrote:
>> The standard method of scrolling in X is tailored to mouse wheels and
>> proceeds in coarse steps.  Wheel events are mapped to button events, and on
>> receiving such an event, an application moves the view of its data by some
>> fixed distance - usually the height of a line of text, or of a couple of
>> lines.
>>
>> Version 2.1 of the X Input Protocol has introduced a more precise
>> alternative.  It defines additional types of motion events.  In essence,
>> their values represent fractions of a complete scroll unit, and newer
>> applications may move their views by distances that are proportional to the
>> event values.  For applications that don't support this, X generates the
>> standard button events whenever the values add up to the complete unit.
>>
>> synaptics(4) supports the newer method since long.
>>
>> The diffs below add the feature to ws and wstpad.  The kernel part defines
>> two new event types in wsconsio.h, and it adapts the scrolling functions of
>> the touchpad input driver.  The xenocara part adds the new "axes" and event
>> handlers to ws.
>>
>> There is a little twist to the implementation.  While synaptics(4)
>> initializes the scroll axes with the scroll distance in device units, the
>> constant 4096 is used in the new ws code, and event values represent the
>> fraction (motion_delta / scroll_unit) in [*.12] fixed-point format.  That
>> way, no queries for the device- and configuration-dependent scroll unit
>> are necessary.
>>
>> The X Input Protocol calls the method "smooth scrolling", but it seems
>> that nowadays, this term is used exclusively for the rendering technique
>> that displays a little animation when the document position changes, so
>> "precision scrolling" might be a better choice.
>>
>> Tests, comments, and OKs would be welcome.
>
> Well done!  It works on my touchpad and retains the old "chunky"
> style scrolling from the mouse wheel on my external mouse.
>
> My only quibble is that this new style scrolling seems much too fast
> by default with the default X and wscons mouse acceleration
> settings.
>
>
Much too fast?  I'm a bit surprised.  In my tests, the new method was
generally somewhat slower than the old one (and I haven't changed the
"scroll units").  How did you test it?  Which hardware and which applications
did you use?

Reply | Threaded
Open this post in threaded view
|

Re: wscons: precision scrolling

Ulf Brosziewski
In reply to this post by Martin Pieuchot
On 3/13/19 4:49 PM, Martin Pieuchot wrote:

> On 13/03/19(Wed) 00:41, Ulf Brosziewski wrote:
>> The standard method of scrolling in X is tailored to mouse wheels and
>> proceeds in coarse steps.  Wheel events are mapped to button events, and on
>> receiving such an event, an application moves the view of its data by some
>> fixed distance - usually the height of a line of text, or of a couple of
>> lines.
>>
>> Version 2.1 of the X Input Protocol has introduced a more precise
>> alternative.  It defines additional types of motion events.  In essence,
>> their values represent fractions of a complete scroll unit, and newer
>> applications may move their views by distances that are proportional to the
>> event values.  For applications that don't support this, X generates the
>> standard button events whenever the values add up to the complete unit.
>>
>> synaptics(4) supports the newer method since long.
>>
>> The diffs below add the feature to ws and wstpad.  The kernel part defines
>> two new event types in wsconsio.h, and it adapts the scrolling functions of
>> the touchpad input driver.  The xenocara part adds the new "axes" and event
>> handlers to ws.
>>
>> There is a little twist to the implementation.  While synaptics(4)
>> initializes the scroll axes with the scroll distance in device units, the
>> constant 4096 is used in the new ws code, and event values represent the
>> fraction (motion_delta / scroll_unit) in [*.12] fixed-point format.  That
>> way, no queries for the device- and configuration-dependent scroll unit
>> are necessary.
>>
>> The X Input Protocol calls the method "smooth scrolling", but it seems
>> that nowadays, this term is used exclusively for the rendering technique
>> that displays a little animation when the document position changes, so
>> "precision scrolling" might be a better choice.
>>
>> Tests, comments, and OKs would be welcome.
>
> I like it.  Implementation is nice.  I find the *_EV defines confusing.
> Why not use the WSCONS_* defines directly, it would make easier for the
> reader to find which code generates which event in a single grep.  But
> that's not new ;)

Some of the WSCONS_EVENT_* names are very long, and too many capital
letters in a C function can make me nervous ;-)  Initially, I thought
that more *_EV definitions would become macros.

>
> Do you know if it would make sense to get rid of the standard scrolling
> method?  Could we generate such events for all input devices?  Does
> other X drivers do that already or plan to do it?
>

I wouldn't know of any obstacle, at least, but I haven't checked that.
Whether the kernel sends a DELTA_Z event or a VSCROLL event with a
multiple of the base unit shouldn't make a difference in the outcome.
It might even be possible to apply an acceleration scheme to wheel
input (I believe Mac OS does that), but I have no idea whether that
would be useful.  Anyway, first we should make sure that the mechanism
is sound; I'm a bit puzzled by Joshua's report and hope there will be
more tests.

>> Index: dev/wscons/wsconsio.h
>> ===================================================================
>> RCS file: /cvs/src/sys/dev/wscons/wsconsio.h,v
>> retrieving revision 1.90
>> diff -u -p -r1.90 wsconsio.h
>> --- dev/wscons/wsconsio.h 10 Nov 2018 14:27:51 -0000 1.90
>> +++ dev/wscons/wsconsio.h 12 Mar 2019 21:55:11 -0000
>> @@ -112,6 +112,12 @@ struct wscons_event {
>>  #define WSCONS_EVENT_TOUCH_RESET 25 /* (no value) */
>>
>>  /*
>> + * Precision Scrolling
>> + */
>> +#define WSCONS_EVENT_HSCROLL 26 /* dx * 4096 / scroll_unit */
>> +#define WSCONS_EVENT_VSCROLL 27 /* dy * 4096 / scroll_unit */
>> +
>> +/*
>>   * Keyboard ioctls (0 - 31)
>>   */
>>
>> Index: dev/wscons/wsmouse.c
>> ===================================================================
>> RCS file: /cvs/src/sys/dev/wscons/wsmouse.c,v
>> retrieving revision 1.51
>> diff -u -p -r1.51 wsmouse.c
>> --- dev/wscons/wsmouse.c 19 Feb 2019 07:01:02 -0000 1.51
>> +++ dev/wscons/wsmouse.c 12 Mar 2019 21:55:11 -0000
>> @@ -1034,10 +1034,18 @@ wsmouse_motion_sync(struct wsmouseinput
>>   wsmouse_evq_put(evq, DELTA_X_EV(input), dx);
>>   if (dy)
>>   wsmouse_evq_put(evq, DELTA_Y_EV(input), dy);
>> - if (motion->dz)
>> - wsmouse_evq_put(evq, DELTA_Z_EV, motion->dz);
>> - if (motion->dw)
>> - wsmouse_evq_put(evq, DELTA_W_EV, motion->dw);
>> + if (motion->dz) {
>> + if (IS_TOUCHPAD(input))
>> + wsmouse_evq_put(evq, VSCROLL_EV, motion->dz);
>> + else
>> + wsmouse_evq_put(evq, DELTA_Z_EV, motion->dz);
>> + }
>> + if (motion->dw) {
>> + if (IS_TOUCHPAD(input))
>> + wsmouse_evq_put(evq, HSCROLL_EV, motion->dw);
>> + else
>> + wsmouse_evq_put(evq, DELTA_W_EV, motion->dw);
>> + }
>>   }
>>   if (motion->sync & SYNC_POSITION) {
>>   if (motion->sync & SYNC_X) {
>> Index: dev/wscons/wsmouseinput.h
>> ===================================================================
>> RCS file: /cvs/src/sys/dev/wscons/wsmouseinput.h,v
>> retrieving revision 1.12
>> diff -u -p -r1.12 wsmouseinput.h
>> --- dev/wscons/wsmouseinput.h 10 Nov 2018 14:27:51 -0000 1.12
>> +++ dev/wscons/wsmouseinput.h 12 Mar 2019 21:55:12 -0000
>> @@ -210,6 +210,8 @@ int wstpad_set_param(struct wsmouseinput
>>      WSCONS_EVENT_MOUSE_ABSOLUTE_X : WSCONS_EVENT_MOUSE_ABSOLUTE_Y)
>>  #define DELTA_Z_EV WSCONS_EVENT_MOUSE_DELTA_Z
>>  #define DELTA_W_EV WSCONS_EVENT_MOUSE_DELTA_W
>> +#define VSCROLL_EV WSCONS_EVENT_VSCROLL
>> +#define HSCROLL_EV WSCONS_EVENT_HSCROLL
>>  #define ABS_Z_EV WSCONS_EVENT_TOUCH_PRESSURE
>>  #define ABS_W_EV WSCONS_EVENT_TOUCH_CONTACTS
>>  #define BTN_DOWN_EV WSCONS_EVENT_MOUSE_DOWN
>> Index: dev/wscons/wstpad.c
>> ===================================================================
>> RCS file: /cvs/src/sys/dev/wscons/wstpad.c,v
>> retrieving revision 1.22
>> diff -u -p -r1.22 wstpad.c
>> --- dev/wscons/wstpad.c 29 Dec 2018 21:03:58 -0000 1.22
>> +++ dev/wscons/wstpad.c 12 Mar 2019 21:55:12 -0000
>> @@ -167,8 +167,6 @@ struct wstpad {
>>   u_int mtcycle;
>>   u_int ignore;
>>
>> - int dx;
>> - int dy;
>>   int contacts;
>>   int prev_contacts;
>>   u_int btns;
>> @@ -223,12 +221,11 @@ struct wstpad {
>>   } tap;
>>
>>   struct {
>> - int acc_dx;
>> - int acc_dy;
>>   int dz;
>>   int dw;
>>   int hdist;
>>   int vdist;
>> + int mag;
>>   } scroll;
>>  };
>>
>> @@ -435,8 +432,8 @@ set_freeze_ts(struct wstpad *tp, int sec
>>
>>
>>  /* Return TRUE if two-finger- or edge-scrolling would be valid. */
>> -static inline int
>> -chk_scroll_state(struct wsmouseinput *input)
>> +int
>> +wstpad_scroll_coords(struct wsmouseinput *input, int *dx, int *dy)
>>  {
>>   struct wstpad *tp = input->tp;
>>
>> @@ -451,40 +448,43 @@ chk_scroll_state(struct wsmouseinput *in
>>   * a short delay, is only applied initially, a touch that stops and
>>   * resumes scrolling is not affected.
>>   */
>> - if (tp->scroll.dz || tp->scroll.dw || wstpad_is_stable(input, tp->t))
>> - return (tp->dx || tp->dy);
>> + if (tp->scroll.dz || tp->scroll.dw || wstpad_is_stable(input, tp->t)) {
>> + *dx = normalize_rel(&input->filter.h, input->motion.pos.dx);
>> + *dy = normalize_rel(&input->filter.v, input->motion.pos.dy);
>> + return (*dx || *dy);
>> + }
>>
>>   return (0);
>>  }
>>
>>  void
>> -wstpad_scroll(struct wstpad *tp, int dx, int dy, u_int *cmds)
>> +wstpad_scroll(struct wstpad *tp, int dx, int dy, int mag, u_int *cmds)
>>  {
>> - int sign;
>> + int dz, dw, n = 1;
>>
>> - /* Scrolling is either horizontal or vertical, but not both. */
>> -
>> - sign = (dy > 0) - (dy < 0);
>> - if (sign) {
>> - if (tp->scroll.dz != -sign) {
>> - tp->scroll.dz = -sign;
>> - tp->scroll.acc_dy = -tp->scroll.vdist;
>> - }
>> - tp->scroll.acc_dy += abs(dy);
>> - if (tp->scroll.acc_dy >= 0) {
>> - tp->scroll.acc_dy -= tp->scroll.vdist;
>> - *cmds |= 1 << VSCROLL;
>> - }
>> - } else if ((sign = (dx > 0) - (dx < 0))) {
>> - if (tp->scroll.dw != sign) {
>> - tp->scroll.dw = sign;
>> - tp->scroll.acc_dx = -tp->scroll.hdist;
>> - }
>> - tp->scroll.acc_dx += abs(dx);
>> - if (tp->scroll.acc_dx >= 0) {
>> - tp->scroll.acc_dx -= tp->scroll.hdist;
>> - *cmds |= 1 << HSCROLL;
>> - }
>> + /*
>> + * The function applies strong deceleration, but only to input with
>> + * very low speeds.  A higher threshold might make applications
>> + * without support for precision scrolling appear unresponsive.
>> + */
>> + mag = tp->scroll.mag = imin(MAG_MEDIUM,
>> +    (mag + 3 * tp->scroll.mag) / 4);
>> + if (mag < MAG_LOW)
>> + n = (MAG_LOW - mag) / 4096 + 1;
>> +
>> + if (dy && tp->scroll.vdist) {
>> + dz = -dy * 4096 / (tp->scroll.vdist * n);
>> + if (tp->scroll.dz && (dy < 0 == tp->scroll.dz > 0))
>> + dz = (dz + 3 * tp->scroll.dz) / 4;
>> + tp->scroll.dz = dz;
>> + *cmds |= 1 << VSCROLL;
>> +
>> + } else if (dx && tp->scroll.hdist) {
>> + dw = dx * 4096 / (tp->scroll.hdist * n);
>> + if (tp->scroll.dw && (dx > 0 == tp->scroll.dw > 0))
>> + dw = (dw + 3 * tp->scroll.dw) / 4;
>> + tp->scroll.dw = dw;
>> + *cmds |= 1 << HSCROLL;
>>   }
>>  }
>>
>> @@ -502,12 +502,14 @@ wstpad_f2scroll(struct wsmouseinput *inp
>>   return;
>>   }
>>
>> - if (!chk_scroll_state(input))
>> + if (!wstpad_scroll_coords(input, &dx, &dy))
>>   return;
>>
>>   dir = tp->t->dir;
>> - dy = NORTH(dir) || SOUTH(dir) ? tp->dy : 0;
>> - dx = EAST(dir) || WEST(dir) ? tp->dx : 0;
>> + if (!(NORTH(dir) || SOUTH(dir)))
>> + dy = 0;
>> + if (!(EAST(dir) || WEST(dir)))
>> + dx = 0;
>>
>>   if (dx || dy) {
>>   centered = CENTERED(tp->t);
>> @@ -526,7 +528,8 @@ wstpad_f2scroll(struct wsmouseinput *inp
>>   centered |= CENTERED(t2);
>>   }
>>   if (centered) {
>> - wstpad_scroll(tp, dx, dy, cmds);
>> + wstpad_scroll(tp, dx, dy,
>> +    magnitude(input, dx, dy), cmds);
>>   set_freeze_ts(tp, 0, FREEZE_MS);
>>   }
>>   }
>> @@ -540,17 +543,19 @@ wstpad_edgescroll(struct wsmouseinput *i
>>   u_int v_edge, b_edge;
>>   int dx, dy;
>>
>> - if (tp->contacts != 1 || !chk_scroll_state(input))
>> + if (!wstpad_scroll_coords(input, &dx, &dy) || tp->contacts != 1)
>>   return;
>>
>>   v_edge = (tp->features & WSTPAD_SWAPSIDES) ? L_EDGE : R_EDGE;
>>   b_edge = (tp->features & WSTPAD_HORIZSCROLL) ? B_EDGE : 0;
>>
>> - dy = (t->flags & v_edge) ? tp->dy : 0;
>> - dx = (t->flags & b_edge) ? tp->dx : 0;
>> + if ((t->flags & v_edge) == 0)
>> + dy = 0;
>> + if ((t->flags & b_edge) == 0)
>> + dx = 0;
>>
>>   if (dx || dy)
>> - wstpad_scroll(tp, dx, dy, cmds);
>> + wstpad_scroll(tp, dx, dy, magnitude(input, dx, dy), cmds);
>>  }
>>
>>  static inline u_int
>> @@ -1121,20 +1126,7 @@ wstpad_touch_inputs(struct wsmouseinput
>>  {
>>   struct wstpad *tp = input->tp;
>>   struct tpad_touch *t;
>> - int slot;
>> -
>> - /*
>> - * Use the normalized, hysteresis-filtered, but otherwise untransformed
>> - * relative coordinates of the pointer-controlling touch for filtering
>> - * and scrolling.
>> - */
>> - if ((input->motion.sync & SYNC_POSITION)
>> -    && !wsmouse_hysteresis(input, &input->motion.pos)) {
>> - tp->dx = normalize_rel(&input->filter.h, input->motion.pos.dx);
>> - tp->dy = normalize_rel(&input->filter.v, input->motion.pos.dy);
>> - } else {
>> - tp->dx = tp->dy = 0;
>> - }
>> + int slot, x, y, dx, dy;
>>
>>   tp->btns = input->btn.buttons;
>>   tp->btns_sync = input->btn.sync;
>> @@ -1158,8 +1150,6 @@ wstpad_touch_inputs(struct wsmouseinput
>>   wstpad_mt_masks(input);
>>   } else {
>>   t = tp->t;
>> - t->x = normalize_abs(&input->filter.h, t->pos->x);
>> - t->y = normalize_abs(&input->filter.v, t->pos->y);
>>   if (tp->contacts)
>>   t->state = (tp->prev_contacts ?
>>      TOUCH_UPDATE : TOUCH_BEGIN);
>> @@ -1167,17 +1157,25 @@ wstpad_touch_inputs(struct wsmouseinput
>>   t->state = (tp->prev_contacts ?
>>      TOUCH_END : TOUCH_NONE);
>>
>> + dx = dy = 0;
>> + x = normalize_abs(&input->filter.h, t->pos->x);
>> + y = normalize_abs(&input->filter.v, t->pos->y);
>>   if (t->state == TOUCH_BEGIN) {
>> - t->orig.x = t->x;
>> - t->orig.y = t->y;
>> + t->x = t->orig.x = x;
>> + t->y = t->orig.y = y;
>>   memcpy(&t->orig.time, &tp->time,
>>      sizeof(struct timespec));
>> - t->flags = edge_flags(tp, t->x, t->y);
>> - } else {
>> - t->flags &= (~EDGES | edge_flags(tp, t->x, t->y));
>> + t->flags = edge_flags(tp, x, y);
>> + } else if (input->motion.sync & SYNC_POSITION) {
>> + if (!wsmouse_hysteresis(input, t->pos)) {
>> + dx = x - t->x;
>> + dy = y - t->y;
>> + }
>> + t->x = x;
>> + t->y = y;
>> + t->flags &= (~EDGES | edge_flags(tp, x, y));
>>   }
>> -
>> - wstpad_set_direction(tp, t, tp->dx, tp->dy);
>> + wstpad_set_direction(tp, t, dx, dy);
>>   }
>>  }
>>
>>
>> Index: driver/xf86-input-ws/src/ws.c
>> ===================================================================
>> RCS file: /cvs/xenocara/driver/xf86-input-ws/src/ws.c,v
>> retrieving revision 1.63
>> diff -u -p -r1.63 ws.c
>> --- driver/xf86-input-ws/src/ws.c 31 Dec 2017 23:31:41 -0000 1.63
>> +++ driver/xf86-input-ws/src/ws.c 11 Mar 2019 21:09:28 -0000
>> @@ -363,6 +363,10 @@ wsDeviceInit(DeviceIntPtr pWS)
>>   axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X);
>>   axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y);
>>   }
>> + axes_labels[HSCROLL_AXIS] =
>> +    XIGetKnownProperty(AXIS_LABEL_PROP_REL_HSCROLL);
>> + axes_labels[VSCROLL_AXIS] =
>> +    XIGetKnownProperty(AXIS_LABEL_PROP_REL_VSCROLL);
>>   if (!InitValuatorClassDeviceStruct(pWS,
>>      NAXES, axes_labels, GetMotionHistorySize(),
>>      priv->type == WSMOUSE_TYPE_TPANEL ? Absolute : Relative))
>> @@ -382,6 +386,25 @@ wsDeviceInit(DeviceIntPtr pWS)
>>      priv->type == WSMOUSE_TYPE_TPANEL ? Absolute : Relative);
>>   xf86InitValuatorDefaults(pWS, 1);
>>
>> + xf86InitValuatorAxisStruct(pWS, HSCROLL_AXIS,
>> +    axes_labels[HSCROLL_AXIS], 0, -1, 0, 0, 0, Relative);
>> + xf86InitValuatorAxisStruct(pWS, VSCROLL_AXIS,
>> +    axes_labels[VSCROLL_AXIS], 0, -1, 0, 0, 0, Relative);
>> + priv->scroll_mask = valuator_mask_new(MAX_VALUATORS);
>> + if (!priv->scroll_mask) {
>> + free(axes_labels);
>> + return !Success;
>> + }
>> +
>> + /*
>> + * The value of an HSCROLL or VSCROLL event is the fraction
>> + *         motion_delta / scroll_distance
>> + * in [*.12] fixed-point format.  The 'increment' attribute of the
>> + * scroll axes is constant:
>> + */
>> + SetScrollValuator(pWS, HSCROLL_AXIS, SCROLL_TYPE_HORIZONTAL, 4096, 0);
>> + SetScrollValuator(pWS, VSCROLL_AXIS, SCROLL_TYPE_VERTICAL, 4096, 0);
>> +
>>   pWS->public.on = FALSE;
>>   if (wsOpen(pInfo) != Success) {
>>   return !Success;
>> @@ -579,6 +602,14 @@ wsReadHwState(InputInfoPtr pInfo, wsHwSt
>>   case WSCONS_EVENT_SYNC:
>>   DBG(4, ErrorF("Sync\n"));
>>   return TRUE;
>> + case WSCONS_EVENT_HSCROLL:
>> + hw->hscroll = event->value;
>> + DBG(4, ErrorF("Horiz. Scrolling %d\n", event->value));
>> + return TRUE;
>> + case WSCONS_EVENT_VSCROLL:
>> + hw->vscroll = event->value;
>> + DBG(4, ErrorF("Vert. Scrolling %d\n", event->value));
>> + return TRUE;
>>   default:
>>   xf86IDrvMsg(pInfo, X_WARNING,
>>      "bad wsmouse event type=%d\n", event->type);
>> @@ -623,6 +654,14 @@ wsReadInput(InputInfoPtr pInfo)
>>   wbutton = (hw.dw < 0) ? priv->W.negative : priv->W.positive;
>>   DBG(4, ErrorF("W -> button %d (%d)\n", wbutton, abs(hw.dw)));
>>   wsButtonClicks(pInfo, wbutton, abs(hw.dw));
>> + }
>> + if (hw.hscroll || hw.vscroll) {
>> + valuator_mask_zero(priv->scroll_mask);
>> + valuator_mask_set_double(priv->scroll_mask,
>> +    HSCROLL_AXIS, (double) hw.hscroll);
>> + valuator_mask_set_double(priv->scroll_mask,
>> +    VSCROLL_AXIS, (double) hw.vscroll);
>> + xf86PostMotionEventM(pInfo->dev, FALSE, priv->scroll_mask);
>>   }
>>   if (priv->lastButtons != hw.buttons) {
>>   /* button event */
>> Index: driver/xf86-input-ws/src/ws.h
>> ===================================================================
>> RCS file: /cvs/xenocara/driver/xf86-input-ws/src/ws.h,v
>> retrieving revision 1.15
>> diff -u -p -r1.15 ws.h
>> --- driver/xf86-input-ws/src/ws.h 31 Dec 2017 23:31:41 -0000 1.15
>> +++ driver/xf86-input-ws/src/ws.h 11 Mar 2019 21:09:28 -0000
>> @@ -26,7 +26,10 @@ extern int ws_debug_level;
>>  # define DBG(lvl, f)
>>  #endif
>>
>> -#define NAXES 2 /* X and Y axes only */
>> +#define NAXES 4 /* X, Y, horizontal and vertical scrolling */
>> +#define HSCROLL_AXIS 2
>> +#define VSCROLL_AXIS 3
>> +
>>  #define NBUTTONS 32 /* max theoretical buttons */
>>  #define DFLTBUTTONS 3 /* default number of buttons */
>>
>> @@ -45,6 +48,7 @@ typedef struct {
>>   unsigned int buttons;
>>   int dx, dy, dz, dw;
>>   int ax, ay;
>> + int hscroll, vscroll;
>>  } wsHwState;
>>
>>  typedef struct WSDevice {
>> @@ -86,6 +90,8 @@ typedef struct WSDevice {
>>   Time expires; /* time of expiry */
>>   Time timeout;
>>   } emulateWheel;
>> +
>> + ValuatorMask *scroll_mask;
>>
>>   OsTimerPtr remove_timer; /* Callback for removal on EIO */
>>
>
>

Reply | Threaded
Open this post in threaded view
|

Re: wscons: precision scrolling

Stefan Sperling-5
On Thu, Mar 14, 2019 at 01:40:55AM +0100, Ulf Brosziewski wrote:
> Anyway, first we should make sure that the mechanism
> is sound; I'm a bit puzzled by Joshua's report and hope there will be
> more tests.

Your change works well on my x250 and x201.

Compared to my x220, which currently runs the Gnome desktop on 6.4-stable,
I don't notice any difference when scrolling in firefox or in gnome-terminal.

However, on the x250, which also runs Gnome, the difference in scrolling is
rather obvious in Nautilus (Gnome's file manager). The new behaviour feels
a lot nicer. Scrolling of icons in Nautilus is now smooth, and feels rather
choppy in 6.4 by comparison.

On my x201, which runs XFCE, scrolling in XFCE's file manager is still
choppy even with your change. I suppose this means XFCE is not yet using
the new X protocol scrollng methods.

I don't notice any obvious differences in scrolling speed.

Reply | Threaded
Open this post in threaded view
|

Re: wscons: precision scrolling

joshua stein-3
In reply to this post by Ulf Brosziewski
On Thu, 14 Mar 2019 at 00:48:33 +0100, Ulf Brosziewski wrote:
> Much too fast?  I'm a bit surprised.  In my tests, the new method was
> generally somewhat slower than the old one (and I haven't changed the
> "scroll units").  How did you test it?  Which hardware and which applications
> did you use?

This is with an imt touchpad:

       ihidev0 at iic1 addr 0x15 irq 109 (polling), vendor 0x4f3 product 0x3056, ELAN2201
       ihidev0: 93 report ids
       imt0 at ihidev0: clickpad, 5 contacts
       wsmouse0 at imt0 mux 0

I tested with two-finger scrolling in Firefox and Chrome with a new
user and fresh browser profiles.  I loaded the same webpages with
the old wstpad code and the new, and the two-finger scrolling with
the new setup scrolls much too fast for even small finger movements
(~0.5").

A movement with the previous code that would trigger the
mousewheel-style scrolling of just a handful of lines causes the new
code to scroll nearly an entire screen-height of the page.

Reply | Threaded
Open this post in threaded view
|

Re: wscons: precision scrolling

Ulf Brosziewski
Hi Joshua,

could you make a test with the updated diff below and check whether
the scroll speed is normal? (There are no changes in ws, it's just
the kernel part).

On 3/16/19 4:16 PM, joshua stein wrote:

> On Thu, 14 Mar 2019 at 00:48:33 +0100, Ulf Brosziewski wrote:
>> Much too fast?  I'm a bit surprised.  In my tests, the new method was
>> generally somewhat slower than the old one (and I haven't changed the
>> "scroll units").  How did you test it?  Which hardware and which applications
>> did you use?
>
> This is with an imt touchpad:
>
>        ihidev0 at iic1 addr 0x15 irq 109 (polling), vendor 0x4f3 product 0x3056, ELAN2201
>        ihidev0: 93 report ids
>        imt0 at ihidev0: clickpad, 5 contacts
>        wsmouse0 at imt0 mux 0
>
> I tested with two-finger scrolling in Firefox and Chrome with a new
> user and fresh browser profiles.  I loaded the same webpages with
> the old wstpad code and the new, and the two-finger scrolling with
> the new setup scrolls much too fast for even small finger movements
> (~0.5").
>
> A movement with the previous code that would trigger the
> mousewheel-style scrolling of just a handful of lines causes the new
> code to scroll nearly an entire screen-height of the page.
>
>

Index: dev/wscons/wsconsio.h
===================================================================
RCS file: /cvs/src/sys/dev/wscons/wsconsio.h,v
retrieving revision 1.90
diff -u -p -r1.90 wsconsio.h
--- dev/wscons/wsconsio.h 10 Nov 2018 14:27:51 -0000 1.90
+++ dev/wscons/wsconsio.h 17 Mar 2019 18:23:14 -0000
@@ -112,6 +112,12 @@ struct wscons_event {
 #define WSCONS_EVENT_TOUCH_RESET 25 /* (no value) */

 /*
+ * Precision Scrolling
+ */
+#define WSCONS_EVENT_HSCROLL 26 /* dx * 4096 / scroll_unit */
+#define WSCONS_EVENT_VSCROLL 27 /* dy * 4096 / scroll_unit */
+
+/*
  * Keyboard ioctls (0 - 31)
  */

Index: dev/wscons/wsmouse.c
===================================================================
RCS file: /cvs/src/sys/dev/wscons/wsmouse.c,v
retrieving revision 1.51
diff -u -p -r1.51 wsmouse.c
--- dev/wscons/wsmouse.c 19 Feb 2019 07:01:02 -0000 1.51
+++ dev/wscons/wsmouse.c 17 Mar 2019 18:23:14 -0000
@@ -1034,10 +1034,18 @@ wsmouse_motion_sync(struct wsmouseinput
  wsmouse_evq_put(evq, DELTA_X_EV(input), dx);
  if (dy)
  wsmouse_evq_put(evq, DELTA_Y_EV(input), dy);
- if (motion->dz)
- wsmouse_evq_put(evq, DELTA_Z_EV, motion->dz);
- if (motion->dw)
- wsmouse_evq_put(evq, DELTA_W_EV, motion->dw);
+ if (motion->dz) {
+ if (IS_TOUCHPAD(input))
+ wsmouse_evq_put(evq, VSCROLL_EV, motion->dz);
+ else
+ wsmouse_evq_put(evq, DELTA_Z_EV, motion->dz);
+ }
+ if (motion->dw) {
+ if (IS_TOUCHPAD(input))
+ wsmouse_evq_put(evq, HSCROLL_EV, motion->dw);
+ else
+ wsmouse_evq_put(evq, DELTA_W_EV, motion->dw);
+ }
  }
  if (motion->sync & SYNC_POSITION) {
  if (motion->sync & SYNC_X) {
Index: dev/wscons/wsmouseinput.h
===================================================================
RCS file: /cvs/src/sys/dev/wscons/wsmouseinput.h,v
retrieving revision 1.12
diff -u -p -r1.12 wsmouseinput.h
--- dev/wscons/wsmouseinput.h 10 Nov 2018 14:27:51 -0000 1.12
+++ dev/wscons/wsmouseinput.h 17 Mar 2019 18:23:14 -0000
@@ -210,6 +210,8 @@ int wstpad_set_param(struct wsmouseinput
     WSCONS_EVENT_MOUSE_ABSOLUTE_X : WSCONS_EVENT_MOUSE_ABSOLUTE_Y)
 #define DELTA_Z_EV WSCONS_EVENT_MOUSE_DELTA_Z
 #define DELTA_W_EV WSCONS_EVENT_MOUSE_DELTA_W
+#define VSCROLL_EV WSCONS_EVENT_VSCROLL
+#define HSCROLL_EV WSCONS_EVENT_HSCROLL
 #define ABS_Z_EV WSCONS_EVENT_TOUCH_PRESSURE
 #define ABS_W_EV WSCONS_EVENT_TOUCH_CONTACTS
 #define BTN_DOWN_EV WSCONS_EVENT_MOUSE_DOWN
Index: dev/wscons/wstpad.c
===================================================================
RCS file: /cvs/src/sys/dev/wscons/wstpad.c,v
retrieving revision 1.22
diff -u -p -r1.22 wstpad.c
--- dev/wscons/wstpad.c 29 Dec 2018 21:03:58 -0000 1.22
+++ dev/wscons/wstpad.c 17 Mar 2019 18:23:14 -0000
@@ -167,8 +167,6 @@ struct wstpad {
  u_int mtcycle;
  u_int ignore;

- int dx;
- int dy;
  int contacts;
  int prev_contacts;
  u_int btns;
@@ -223,12 +221,11 @@ struct wstpad {
  } tap;

  struct {
- int acc_dx;
- int acc_dy;
  int dz;
  int dw;
  int hdist;
  int vdist;
+ int mag;
  } scroll;
 };

@@ -435,8 +432,8 @@ set_freeze_ts(struct wstpad *tp, int sec


 /* Return TRUE if two-finger- or edge-scrolling would be valid. */
-static inline int
-chk_scroll_state(struct wsmouseinput *input)
+int
+wstpad_scroll_coords(struct wsmouseinput *input, int *dx, int *dy)
 {
  struct wstpad *tp = input->tp;

@@ -445,46 +442,51 @@ chk_scroll_state(struct wsmouseinput *in
  tp->scroll.dw = 0;
  return (0);
  }
+ if ((input->motion.sync & SYNC_POSITION) == 0)
+ return (0);
  /*
  * Try to exclude accidental scroll events by checking whether the
  * pointer-controlling touch is stable.  The check, which may cause
  * a short delay, is only applied initially, a touch that stops and
  * resumes scrolling is not affected.
  */
- if (tp->scroll.dz || tp->scroll.dw || wstpad_is_stable(input, tp->t))
- return (tp->dx || tp->dy);
+ if (tp->scroll.dz || tp->scroll.dw || wstpad_is_stable(input, tp->t)) {
+ *dx = normalize_rel(&input->filter.h, input->motion.pos.dx);
+ *dy = normalize_rel(&input->filter.v, input->motion.pos.dy);
+ return (*dx || *dy);
+ }

  return (0);
 }

 void
-wstpad_scroll(struct wstpad *tp, int dx, int dy, u_int *cmds)
+wstpad_scroll(struct wstpad *tp, int dx, int dy, int mag, u_int *cmds)
 {
- int sign;
-
- /* Scrolling is either horizontal or vertical, but not both. */
+ int dz, dw, n = 1;

- sign = (dy > 0) - (dy < 0);
- if (sign) {
- if (tp->scroll.dz != -sign) {
- tp->scroll.dz = -sign;
- tp->scroll.acc_dy = -tp->scroll.vdist;
- }
- tp->scroll.acc_dy += abs(dy);
- if (tp->scroll.acc_dy >= 0) {
- tp->scroll.acc_dy -= tp->scroll.vdist;
- *cmds |= 1 << VSCROLL;
- }
- } else if ((sign = (dx > 0) - (dx < 0))) {
- if (tp->scroll.dw != sign) {
- tp->scroll.dw = sign;
- tp->scroll.acc_dx = -tp->scroll.hdist;
- }
- tp->scroll.acc_dx += abs(dx);
- if (tp->scroll.acc_dx >= 0) {
- tp->scroll.acc_dx -= tp->scroll.hdist;
- *cmds |= 1 << HSCROLL;
- }
+ /*
+ * The function applies strong deceleration, but only to input with
+ * very low speeds.  A higher threshold might make applications
+ * without support for precision scrolling appear unresponsive.
+ */
+ mag = tp->scroll.mag = imin(MAG_MEDIUM,
+    (mag + 3 * tp->scroll.mag) / 4);
+ if (mag < MAG_LOW)
+ n = (MAG_LOW - mag) / 4096 + 1;
+
+ if (dy && tp->scroll.vdist) {
+ dz = -dy * 4096 / (tp->scroll.vdist * n);
+ if (tp->scroll.dz && (dy < 0 == tp->scroll.dz > 0))
+ dz = (dz + 3 * tp->scroll.dz) / 4;
+ tp->scroll.dz = dz;
+ *cmds |= 1 << VSCROLL;
+
+ } else if (dx && tp->scroll.hdist) {
+ dw = dx * 4096 / (tp->scroll.hdist * n);
+ if (tp->scroll.dw && (dx > 0 == tp->scroll.dw > 0))
+ dw = (dw + 3 * tp->scroll.dw) / 4;
+ tp->scroll.dw = dw;
+ *cmds |= 1 << HSCROLL;
  }
 }

@@ -502,12 +504,14 @@ wstpad_f2scroll(struct wsmouseinput *inp
  return;
  }

- if (!chk_scroll_state(input))
+ if (!wstpad_scroll_coords(input, &dx, &dy))
  return;

  dir = tp->t->dir;
- dy = NORTH(dir) || SOUTH(dir) ? tp->dy : 0;
- dx = EAST(dir) || WEST(dir) ? tp->dx : 0;
+ if (!(NORTH(dir) || SOUTH(dir)))
+ dy = 0;
+ if (!(EAST(dir) || WEST(dir)))
+ dx = 0;

  if (dx || dy) {
  centered = CENTERED(tp->t);
@@ -526,7 +530,8 @@ wstpad_f2scroll(struct wsmouseinput *inp
  centered |= CENTERED(t2);
  }
  if (centered) {
- wstpad_scroll(tp, dx, dy, cmds);
+ wstpad_scroll(tp, dx, dy,
+    magnitude(input, dx, dy), cmds);
  set_freeze_ts(tp, 0, FREEZE_MS);
  }
  }
@@ -540,17 +545,19 @@ wstpad_edgescroll(struct wsmouseinput *i
  u_int v_edge, b_edge;
  int dx, dy;

- if (tp->contacts != 1 || !chk_scroll_state(input))
+ if (!wstpad_scroll_coords(input, &dx, &dy) || tp->contacts != 1)
  return;

  v_edge = (tp->features & WSTPAD_SWAPSIDES) ? L_EDGE : R_EDGE;
  b_edge = (tp->features & WSTPAD_HORIZSCROLL) ? B_EDGE : 0;

- dy = (t->flags & v_edge) ? tp->dy : 0;
- dx = (t->flags & b_edge) ? tp->dx : 0;
+ if ((t->flags & v_edge) == 0)
+ dy = 0;
+ if ((t->flags & b_edge) == 0)
+ dx = 0;

  if (dx || dy)
- wstpad_scroll(tp, dx, dy, cmds);
+ wstpad_scroll(tp, dx, dy, magnitude(input, dx, dy), cmds);
 }

 static inline u_int
@@ -1121,20 +1128,7 @@ wstpad_touch_inputs(struct wsmouseinput
 {
  struct wstpad *tp = input->tp;
  struct tpad_touch *t;
- int slot;
-
- /*
- * Use the normalized, hysteresis-filtered, but otherwise untransformed
- * relative coordinates of the pointer-controlling touch for filtering
- * and scrolling.
- */
- if ((input->motion.sync & SYNC_POSITION)
-    && !wsmouse_hysteresis(input, &input->motion.pos)) {
- tp->dx = normalize_rel(&input->filter.h, input->motion.pos.dx);
- tp->dy = normalize_rel(&input->filter.v, input->motion.pos.dy);
- } else {
- tp->dx = tp->dy = 0;
- }
+ int slot, x, y, dx, dy;

  tp->btns = input->btn.buttons;
  tp->btns_sync = input->btn.sync;
@@ -1158,8 +1152,6 @@ wstpad_touch_inputs(struct wsmouseinput
  wstpad_mt_masks(input);
  } else {
  t = tp->t;
- t->x = normalize_abs(&input->filter.h, t->pos->x);
- t->y = normalize_abs(&input->filter.v, t->pos->y);
  if (tp->contacts)
  t->state = (tp->prev_contacts ?
     TOUCH_UPDATE : TOUCH_BEGIN);
@@ -1167,17 +1159,25 @@ wstpad_touch_inputs(struct wsmouseinput
  t->state = (tp->prev_contacts ?
     TOUCH_END : TOUCH_NONE);

+ dx = dy = 0;
+ x = normalize_abs(&input->filter.h, t->pos->x);
+ y = normalize_abs(&input->filter.v, t->pos->y);
  if (t->state == TOUCH_BEGIN) {
- t->orig.x = t->x;
- t->orig.y = t->y;
+ t->x = t->orig.x = x;
+ t->y = t->orig.y = y;
  memcpy(&t->orig.time, &tp->time,
     sizeof(struct timespec));
- t->flags = edge_flags(tp, t->x, t->y);
- } else {
- t->flags &= (~EDGES | edge_flags(tp, t->x, t->y));
+ t->flags = edge_flags(tp, x, y);
+ } else if (input->motion.sync & SYNC_POSITION) {
+ if (!wsmouse_hysteresis(input, t->pos)) {
+ dx = x - t->x;
+ dy = y - t->y;
+ }
+ t->x = x;
+ t->y = y;
+ t->flags &= (~EDGES | edge_flags(tp, x, y));
  }
-
- wstpad_set_direction(tp, t, tp->dx, tp->dy);
+ wstpad_set_direction(tp, t, dx, dy);
  }
 }

Reply | Threaded
Open this post in threaded view
|

Re: wscons: precision scrolling

joshua stein-3
On Sun, 17 Mar 2019 at 19:35:17 +0100, Ulf Brosziewski wrote:
> Hi Joshua,
>
> could you make a test with the updated diff below and check whether
> the scroll speed is normal? (There are no changes in ws, it's just
> the kernel part).

Hi, this version scrolls much better.