Expose pixel-wise wheel events to Lisp

* doc/lispref/commands.texi (Misc Events): Document changes to
wheel events.

* src/keyboard.c (make_lispy_event): Handle wheel events with
pixel delta data.
* src/termhooks.h (WHEEL_EVENT): Document changes to
WHEEL_EVENT args.
* src/xfns.c (syms_of_xfns): Declare new symbols.
* src/xterm.c (handle_one_xevent): Give wheel events pixel delta
data.
(x_coalesce_scroll_events): New user option.
This commit is contained in:
Po Lu 2021-11-16 19:39:50 +08:00
parent 487ec3cf2a
commit 0c51c1b5ed
5 changed files with 52 additions and 14 deletions

View file

@ -1994,7 +1994,18 @@ frame has already been made visible, Emacs has no work to do.
These kinds of event are generated by moving a mouse wheel. The
@var{position} element is a mouse position list (@pxref{Click
Events}), specifying the position of the mouse cursor when the event
occurred.
occurred. The event may have additional arguments after
@var{position}. The third argument after @var{position}, if present,
is a pair of the form @w{@code{(@var{x} . @var{y})}}, where @var{x}
and @var{y} are the number of pixels to scroll by in each axis.
@cindex pixel-resolution wheel events
You can use @var{x} and @var{y} to determine how much the mouse wheel
has actually moved at pixel resolution.
For example, the pixelwise deltas could be used to scroll the display
at pixel resolution, exactly according to the user's turning the mouse
wheel.
@vindex mouse-wheel-up-event
@vindex mouse-wheel-down-event

View file

@ -5980,7 +5980,11 @@ make_lispy_event (struct input_event *event)
ASIZE (wheel_syms));
}
if (NUMBERP (event->arg))
if (CONSP (event->arg))
return list5 (head, position, make_fixnum (double_click_count),
XCAR (event->arg), Fcons (XCAR (XCDR (event->arg)),
XCAR (XCDR (XCDR (event->arg)))));
else if (NUMBERP (event->arg))
return list4 (head, position, make_fixnum (double_click_count),
event->arg);
else if (event->modifiers & (double_modifier | triple_modifier))

View file

@ -119,7 +119,10 @@ enum event_kind
.timestamp gives a timestamp (in
milliseconds) for the event.
.arg may contain the number of
lines to scroll. */
lines to scroll, or a list of
the form (NUMBER-OF-LINES . (X Y)) where
X and Y are the number of pixels
on each axis to scroll by. */
HORIZ_WHEEL_EVENT, /* A wheel event generated by a second
horizontal wheel that is present on some
mice. See WHEEL_EVENT. */

View file

@ -8085,6 +8085,7 @@ eliminated in future versions of Emacs. */);
#ifdef HAVE_XINPUT2
DEFSYM (Qxinput2, "xinput2");
Fprovide (Qxinput2, Qnil);
#endif

View file

@ -556,6 +556,7 @@ xi_reset_scroll_valuators_for_device_id (struct x_display_info *dpyinfo, int id)
{
valuator = &device->valuators[i];
valuator->invalid_p = true;
valuator->emacs_value = 0.0;
}
return;
@ -9921,8 +9922,6 @@ handle_one_xevent (struct x_display_info *dpyinfo,
#endif
goto XI_OTHER;
case XI_Motion:
/* First test if there is some kind of scroll event
here! */
states = &xev->valuators;
values = states->values;
@ -9932,10 +9931,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
{
if (XIMaskIsSet (states->mask, i))
{
block_input ();
struct xi_scroll_valuator_t *val;
double delta;
double delta, scroll_unit;
delta = x_get_scroll_valuator_delta (dpyinfo, xev->deviceid,
i, *values, &val);
@ -9943,6 +9940,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
if (delta != DBL_MAX)
{
f = mouse_or_wdesc_frame (dpyinfo, xev->event);
scroll_unit = pow (FRAME_PIXEL_HEIGHT (f), 2.0 / 3.0);
found_valuator = true;
if (signbit (delta) != signbit (val->emacs_value))
@ -9950,15 +9948,16 @@ handle_one_xevent (struct x_display_info *dpyinfo,
val->emacs_value += delta;
if (x_coalesce_scroll_events
&& (fabs (val->emacs_value) < 1))
continue;
if (!f)
{
f = x_any_window_to_frame (dpyinfo, xev->event);
if (!f)
{
unblock_input ();
goto XI_OTHER;
}
goto XI_OTHER;
}
bool s = signbit (val->emacs_value);
@ -9975,13 +9974,26 @@ handle_one_xevent (struct x_display_info *dpyinfo,
inev.ie.modifiers
|= x_x_to_emacs_modifiers (dpyinfo,
xev->mods.effective);
inev.ie.arg = Qnil;
if (val->horizontal)
{
inev.ie.arg
= list3 (Qnil,
make_float (val->emacs_value
* scroll_unit),
make_float (0));
}
else
{
inev.ie.arg = list3 (Qnil, make_float (0),
make_float (val->emacs_value
* scroll_unit));
}
kbd_buffer_store_event_hold (&inev.ie, hold_quit);
val->emacs_value = 0;
}
unblock_input ();
values++;
}
@ -15048,4 +15060,11 @@ gtk_window_move to set or store frame positions and disables some time
consuming frame position adjustments. In newer versions of GTK, Emacs
always uses gtk_window_move and ignores the value of this variable. */);
x_gtk_use_window_move = true;
DEFVAR_BOOL ("x-coalesce-scroll-events", x_coalesce_scroll_events,
doc: /* Non-nil means send a wheel event only for scrolling at least one screen line.
Otherwise, a wheel event will be sent every time the mouse wheel is
moved. This option is only effective when Emacs is built with XInput
2. */);
x_coalesce_scroll_events = true;
}