1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-01-07 04:10:27 -08:00

Explain confusing aspects of XInput 2 scroll wheel reporting

* src/xterm.c (x_init_master_valuators): Explain how XInput 2
reports scroll wheel movement.

(handle_one_xevent): Explain why XI2 scroll valuators
are reset after each enter events.
This commit is contained in:
Po Lu 2021-11-26 19:59:54 +08:00
parent 824d31e3bf
commit 673eadaeb5

View file

@ -372,6 +372,29 @@ x_free_xi_devices (struct x_display_info *dpyinfo)
unblock_input ();
}
/* The code below handles the tracking of scroll valuators on XInput
2, in order to support scroll wheels that report information more
granular than a screen line.
On X, when the XInput 2 extension is being utilized, the states of
the mouse wheels in each axis are stored as absolute values inside
"valuators" attached to each mouse device. To obtain the delta of
the scroll wheel from a motion event (which is used to report that
some valuator has changed), it is necessary to iterate over every
valuator that changed, and compare its previous value to the
current value of the valuator.
Each individual valuator also has an "interval", which is the
amount you must divide that delta by in order to obtain a delta in
the terms of scroll units.
This delta however is still intermediate, to make driver
implementations easier. The XInput developers recommend (and most
programs use) the following algorithm to convert from scroll unit
deltas to pixel deltas:
pixels_scrolled = pow (window_height, 2.0 / 3.0) * delta; */
/* Setup valuator tracking for XI2 master devices on
DPYINFO->display. */
@ -9874,6 +9897,19 @@ handle_one_xevent (struct x_display_info *dpyinfo,
x_display_set_last_user_time (dpyinfo, xi_event->time);
x_detect_focus_change (dpyinfo, any, event, &inev.ie);
/* One problem behind the design of XInput 2 scrolling is
that valuators are not unique to each window, but only
the window that has grabbed the valuator's device or
the window that the device's pointer is on top of can
receive motion events. There is also no way to
retrieve the value of a valuator outside of each motion
event.
As such, to prevent wildly inaccurate results when the
valuators have changed outside Emacs, we reset our
records of each valuator's value whenever the pointer
re-enters a frame after its valuators have potentially
been changed elsewhere. */
if (enter->detail != XINotifyInferior
&& enter->mode != XINotifyPassiveUngrab
&& enter->mode != XINotifyUngrab && any)
@ -9947,6 +9983,10 @@ handle_one_xevent (struct x_display_info *dpyinfo,
struct xi_scroll_valuator_t *val;
double delta, scroll_unit;
/* See the comment on top of
x_init_master_valuators for more details on how
scroll wheel movement is reported on XInput 2. */
delta = x_get_scroll_valuator_delta (dpyinfo, xev->deviceid,
i, *values, &val);
@ -9972,7 +10012,6 @@ handle_one_xevent (struct x_display_info *dpyinfo,
goto XI_OTHER;
}
scroll_unit = pow (FRAME_PIXEL_HEIGHT (f), 2.0 / 3.0);
found_valuator = true;
if (signbit (delta) != signbit (val->emacs_value))
@ -9999,6 +10038,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
|= x_x_to_emacs_modifiers (dpyinfo,
xev->mods.effective);
scroll_unit = pow (FRAME_PIXEL_HEIGHT (f), 2.0 / 3.0);
if (val->horizontal)
{
inev.ie.arg