Support precision mouse scrolling on MS-Windows
* src/w32fns.c (w32_wnd_proc): Pass the WM_SETTINGCHANGE message to the Lisp thread. * src/w32term.c (w32_construct_mouse_wheel): Support mice with precision scrolling wheel. (w32_get_mouse_wheel_vertical_delta): New function. (w32_read_socket): When the WM_SETTINGCHANGE is received, call 'w32_get_mouse_wheel_vertical_delta'. (w32_initialize): Call 'w32_get_mouse_wheel_vertical_delta' at startup. * src/nsterm.m (syms_of_nsterm): * src/haikuterm.c (syms_of_haikuterm): * src/xterm.c (syms_of_xterm): Remove window-system specific variables for coalescing mwheel events. * src/keyboard.c (syms_of_keyboard) <mwheel-coalesce-scroll-events>: New variable, to replace the above platform-specific ones. * doc/lispref/commands.texi (Misc Events): Improve wording of the description of mouse-wheel events.
This commit is contained in:
parent
c13b49a110
commit
bab2969404
7 changed files with 124 additions and 37 deletions
|
@ -2001,19 +2001,19 @@ These kinds of event are generated by moving a mouse wheel. The
|
|||
Events}), specifying the position of the mouse cursor when the event
|
||||
occurred.
|
||||
|
||||
@var{clicks}, if present, is the number of times in quick succession
|
||||
the wheel has been moved. @xref{Repeat Events}. @var{lines}, if
|
||||
@var{clicks}, if present, is the number of times that the wheel was
|
||||
moved in quick succession. @xref{Repeat Events}. @var{lines}, if
|
||||
present and not @code{nil}, is the number of screen lines that should
|
||||
be scrolled. @var{pixel-delta}, 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.
|
||||
be scrolled. @var{pixel-delta}, if present, is a cons cell of the
|
||||
form @w{@code{(@var{x} . @var{y})}}, where @var{x} and @var{y} are the
|
||||
numbers of pixels by which to scroll in each axis, a.k.a.@:
|
||||
@dfn{pixelwise deltas}.
|
||||
|
||||
@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
|
||||
You can use these @var{x} and @var{y} pixelwise deltas 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
|
||||
|
|
|
@ -3024,7 +3024,7 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
|
|||
|
||||
if (fabsf (py) >= FRAME_LINE_HEIGHT (f)
|
||||
|| fabsf (px) >= FRAME_COLUMN_WIDTH (f)
|
||||
|| !x_coalesce_scroll_events)
|
||||
|| !mwheel_coalesce_scroll_events)
|
||||
{
|
||||
inev.kind = (fabsf (px) > fabsf (py)
|
||||
? HORIZ_WHEEL_EVENT
|
||||
|
@ -3565,10 +3565,6 @@ syms_of_haikuterm (void)
|
|||
doc: /* SKIP: real doc in xterm.c. */);
|
||||
Vx_toolkit_scroll_bars = Qt;
|
||||
|
||||
DEFVAR_BOOL ("x-coalesce-scroll-events", x_coalesce_scroll_events,
|
||||
doc: /* SKIP: real doc in xterm.c. */);
|
||||
x_coalesce_scroll_events = true;
|
||||
|
||||
DEFVAR_BOOL ("haiku-debug-on-fatal-error", haiku_debug_on_fatal_error,
|
||||
doc: /* If non-nil, Emacs will launch the system debugger upon a fatal error. */);
|
||||
haiku_debug_on_fatal_error = 1;
|
||||
|
|
|
@ -12571,6 +12571,12 @@ other similar functions ignore input events in `while-no-input-ignore-events'.
|
|||
This flag may eventually be removed once this behavior is deemed safe. */);
|
||||
input_pending_p_filter_events = true;
|
||||
|
||||
DEFVAR_BOOL ("mwheel-coalesce-scroll-events", mwheel_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. */);
|
||||
mwheel_coalesce_scroll_events = true;
|
||||
|
||||
pdumper_do_now_and_after_load (syms_of_keyboard_for_pdumper);
|
||||
}
|
||||
|
||||
|
|
14
src/nsterm.m
14
src/nsterm.m
|
@ -6606,7 +6606,7 @@ - (void)mouseDown: (NSEvent *)theEvent
|
|||
* reset the total delta for the direction we're NOT
|
||||
* scrolling so that small movements don't add up. */
|
||||
if (abs (totalDeltaX) > abs (totalDeltaY)
|
||||
&& (!x_coalesce_scroll_events
|
||||
&& (!mwheel_coalesce_scroll_events
|
||||
|| abs (totalDeltaX) > lineHeight))
|
||||
{
|
||||
horizontal = YES;
|
||||
|
@ -6614,14 +6614,14 @@ - (void)mouseDown: (NSEvent *)theEvent
|
|||
|
||||
lines = abs (totalDeltaX / lineHeight);
|
||||
x = totalDeltaX;
|
||||
if (!x_coalesce_scroll_events)
|
||||
if (!mwheel_coalesce_scroll_events)
|
||||
totalDeltaX = 0;
|
||||
else
|
||||
totalDeltaX = totalDeltaX % lineHeight;
|
||||
totalDeltaY = 0;
|
||||
}
|
||||
else if (abs (totalDeltaY) >= abs (totalDeltaX)
|
||||
&& (!x_coalesce_scroll_events
|
||||
&& (!mwheel_coalesce_scroll_events
|
||||
|| abs (totalDeltaY) > lineHeight))
|
||||
{
|
||||
horizontal = NO;
|
||||
|
@ -6629,7 +6629,7 @@ - (void)mouseDown: (NSEvent *)theEvent
|
|||
|
||||
lines = abs (totalDeltaY / lineHeight);
|
||||
y = totalDeltaY;
|
||||
if (!x_coalesce_scroll_events)
|
||||
if (!mwheel_coalesce_scroll_events)
|
||||
totalDeltaY = 0;
|
||||
else
|
||||
totalDeltaY = totalDeltaY % lineHeight;
|
||||
|
@ -6662,7 +6662,7 @@ - (void)mouseDown: (NSEvent *)theEvent
|
|||
y = [theEvent scrollingDeltaY];
|
||||
}
|
||||
|
||||
if (lines == 0 && x_coalesce_scroll_events)
|
||||
if (lines == 0 && mwheel_coalesce_scroll_events)
|
||||
return;
|
||||
|
||||
if (NUMBERP (Vns_scroll_event_delta_factor))
|
||||
|
@ -10037,10 +10037,6 @@ Nil means use fullscreen the old (< 10.7) way. The old way works better with
|
|||
doc: /* SKIP: real doc in xterm.c. */);
|
||||
x_underline_at_descent_line = 0;
|
||||
|
||||
DEFVAR_BOOL ("x-coalesce-scroll-events", x_coalesce_scroll_events,
|
||||
doc: /* SKIP: real doc in xterm.c. */);
|
||||
x_coalesce_scroll_events = true;
|
||||
|
||||
DEFSYM (Qx_underline_at_descent_line, "x-underline-at-descent-line");
|
||||
|
||||
DEFVAR_LISP ("ns-scroll-event-delta-factor", Vns_scroll_event_delta_factor,
|
||||
|
|
|
@ -5173,6 +5173,13 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
|
||||
goto dflt;
|
||||
|
||||
case WM_SETTINGCHANGE:
|
||||
/* Inform the Lisp thread that some system-wide setting has
|
||||
changed, so if Emacs is interested in some of them, it could
|
||||
update its internal values. */
|
||||
my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
|
||||
goto dflt;
|
||||
|
||||
case WM_SETFOCUS:
|
||||
dpyinfo->faked_key = 0;
|
||||
reset_modifiers ();
|
||||
|
|
|
@ -164,6 +164,10 @@ int last_scroll_bar_drag_pos;
|
|||
/* Keyboard code page - may be changed by language-change events. */
|
||||
int w32_keyboard_codepage;
|
||||
|
||||
/* The number of screen lines to scroll for the default mouse-wheel
|
||||
scroll amount, given by WHEEL_DELTA. */
|
||||
static UINT w32_wheel_scroll_lines;
|
||||
|
||||
#ifdef CYGWIN
|
||||
int w32_message_fd = -1;
|
||||
#endif /* CYGWIN */
|
||||
|
@ -271,6 +275,19 @@ XGetGCValues (void *ignore, XGCValues *gc,
|
|||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
w32_get_mouse_wheel_vertical_delta (void)
|
||||
{
|
||||
if (os_subtype != OS_SUBTYPE_NT)
|
||||
return;
|
||||
|
||||
UINT scroll_lines;
|
||||
BOOL ret = SystemParametersInfo (SPI_GETWHEELSCROLLLINES, 0,
|
||||
&scroll_lines, 0);
|
||||
if (ret)
|
||||
w32_wheel_scroll_lines = scroll_lines;
|
||||
}
|
||||
|
||||
static void
|
||||
w32_set_clip_rectangle (HDC hdc, RECT *rect)
|
||||
{
|
||||
|
@ -3203,32 +3220,94 @@ w32_construct_mouse_wheel (struct input_event *result, W32Msg *msg,
|
|||
{
|
||||
POINT p;
|
||||
int delta;
|
||||
static int sum_delta_y = 0;
|
||||
|
||||
result->kind = msg->msg.message == WM_MOUSEHWHEEL ? HORIZ_WHEEL_EVENT
|
||||
: WHEEL_EVENT;
|
||||
result->code = 0;
|
||||
result->timestamp = msg->msg.time;
|
||||
result->arg = Qnil;
|
||||
|
||||
/* A WHEEL_DELTA positive value indicates that the wheel was rotated
|
||||
forward, away from the user (up); a negative value indicates that
|
||||
the wheel was rotated backward, toward the user (down). */
|
||||
delta = GET_WHEEL_DELTA_WPARAM (msg->msg.wParam);
|
||||
if (delta == 0)
|
||||
{
|
||||
result->kind = NO_EVENT;
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
/* With multiple monitors, we can legitimately get negative
|
||||
coordinates, so cast to short to interpret them correctly. */
|
||||
p.x = (short) LOWORD (msg->msg.lParam);
|
||||
p.y = (short) HIWORD (msg->msg.lParam);
|
||||
|
||||
if (eabs (delta) < WHEEL_DELTA)
|
||||
{
|
||||
/* This is high-precision mouse wheel, which sends
|
||||
fine-resolution wheel events. Produce a wheel event only if
|
||||
the conditions for sending such an event are fulfilled. */
|
||||
int scroll_unit = max (w32_wheel_scroll_lines, 1), nlines;
|
||||
double value_to_report;
|
||||
|
||||
/* w32_wheel_scroll_lines == INT_MAX means the user asked for
|
||||
"entire page" to be the scroll unit. We interpret that as
|
||||
the height of the window under the mouse pointer. */
|
||||
if (w32_wheel_scroll_lines == INT_MAX)
|
||||
{
|
||||
Lisp_Object window = window_from_coordinates (f, p.x, p.y, NULL,
|
||||
false, false);
|
||||
if (!WINDOWP (window))
|
||||
{
|
||||
result->kind = NO_EVENT;
|
||||
return Qnil;
|
||||
}
|
||||
scroll_unit = XWINDOW (window)->pixel_height;
|
||||
if (scroll_unit < 1) /* paranoia */
|
||||
scroll_unit = 1;
|
||||
}
|
||||
|
||||
/* If mwheel-coalesce-scroll-events is non-nil, report a wheel event
|
||||
only when we have accumulated enough delta's for WHEEL_DELTA. */
|
||||
if (mwheel_coalesce_scroll_events)
|
||||
{
|
||||
/* If the user changed the direction, reset the accumulated
|
||||
deltas. */
|
||||
if ((delta > 0) != (sum_delta_y > 0))
|
||||
sum_delta_y = 0;
|
||||
sum_delta_y += delta;
|
||||
/* https://docs.microsoft.com/en-us/previous-versions/ms997498(v=msdn.10) */
|
||||
if (eabs (sum_delta_y) < WHEEL_DELTA)
|
||||
{
|
||||
result->kind = NO_EVENT;
|
||||
return Qnil;
|
||||
}
|
||||
value_to_report =
|
||||
((double)FRAME_LINE_HEIGHT (f) * scroll_unit)
|
||||
/ ((double)WHEEL_DELTA / sum_delta_y);
|
||||
sum_delta_y = 0;
|
||||
}
|
||||
else
|
||||
value_to_report =
|
||||
((double)FRAME_LINE_HEIGHT (f) * scroll_unit)
|
||||
/ ((double)WHEEL_DELTA / delta);
|
||||
nlines = value_to_report / FRAME_LINE_HEIGHT (f) + 0.5;
|
||||
result->arg = list3 (make_fixnum (nlines),
|
||||
make_float (0.0),
|
||||
make_float (value_to_report));
|
||||
}
|
||||
|
||||
/* The up and down modifiers indicate if the wheel was rotated up or
|
||||
down based on WHEEL_DELTA value. */
|
||||
result->modifiers = (msg->dwModifiers
|
||||
| ((delta < 0 ) ? down_modifier : up_modifier));
|
||||
|
||||
/* With multiple monitors, we can legitimately get negative
|
||||
coordinates, so cast to short to interpret them correctly. */
|
||||
p.x = (short) LOWORD (msg->msg.lParam);
|
||||
p.y = (short) HIWORD (msg->msg.lParam);
|
||||
/* For the case that F's w32 window is not msg->msg.hwnd. */
|
||||
ScreenToClient (FRAME_W32_WINDOW (f), &p);
|
||||
XSETINT (result->x, p.x);
|
||||
XSETINT (result->y, p.y);
|
||||
XSETFRAME (result->frame_or_window, f);
|
||||
result->arg = Qnil;
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
|
@ -4905,6 +4984,14 @@ w32_read_socket (struct terminal *terminal,
|
|||
}
|
||||
break;
|
||||
|
||||
case WM_SETTINGCHANGE:
|
||||
/* We are only interested in changes of the number of lines
|
||||
to scroll when the vertical mouse wheel is moved. This
|
||||
is only supported on NT. */
|
||||
if (msg.msg.wParam == SPI_SETWHEELSCROLLLINES)
|
||||
w32_get_mouse_wheel_vertical_delta ();
|
||||
break;
|
||||
|
||||
case WM_KEYDOWN:
|
||||
case WM_SYSKEYDOWN:
|
||||
f = w32_window_to_frame (dpyinfo, msg.msg.hwnd);
|
||||
|
@ -7522,6 +7609,8 @@ w32_initialize (void)
|
|||
horizontal_scroll_bar_left_border = horizontal_scroll_bar_right_border
|
||||
= GetSystemMetrics (SM_CYHSCROLL);
|
||||
}
|
||||
|
||||
w32_get_mouse_wheel_vertical_delta ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -10024,7 +10024,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
|
|||
|
||||
val->emacs_value += delta;
|
||||
|
||||
if (x_coalesce_scroll_events
|
||||
if (mwheel_coalesce_scroll_events
|
||||
&& (fabs (val->emacs_value) < 1))
|
||||
continue;
|
||||
|
||||
|
@ -15214,13 +15214,6 @@ 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, with Haiku windowing support, or with NS. */);
|
||||
x_coalesce_scroll_events = true;
|
||||
|
||||
DEFVAR_LISP ("x-scroll-event-delta-factor", Vx_scroll_event_delta_factor,
|
||||
doc: /* A scale to apply to pixel deltas reported in scroll events.
|
||||
This option is only effective when Emacs is built with XInput 2
|
||||
|
|
Loading…
Add table
Reference in a new issue