aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEli Zaretskii2021-12-01 15:36:55 +0200
committerEli Zaretskii2021-12-01 15:36:55 +0200
commitbab29694047d060bb58ff88e1a4d2cc7ef05df2a (patch)
tree25dffd70f392ccace1007b53b491707ad44dda1a
parentc13b49a110ffd23975e98c053746054492a3908a (diff)
downloademacs-bab29694047d060bb58ff88e1a4d2cc7ef05df2a.tar.gz
emacs-bab29694047d060bb58ff88e1a4d2cc7ef05df2a.zip
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.
-rw-r--r--doc/lispref/commands.texi20
-rw-r--r--src/haikuterm.c6
-rw-r--r--src/keyboard.c6
-rw-r--r--src/nsterm.m14
-rw-r--r--src/w32fns.c7
-rw-r--r--src/w32term.c99
-rw-r--r--src/xterm.c9
7 files changed, 124 insertions, 37 deletions
diff --git a/doc/lispref/commands.texi b/doc/lispref/commands.texi
index 920d380266f..073cdd8aa7b 100644
--- a/doc/lispref/commands.texi
+++ b/doc/lispref/commands.texi
@@ -2001,19 +2001,19 @@ These kinds of event are generated by moving a mouse wheel. The
2001Events}), specifying the position of the mouse cursor when the event 2001Events}), specifying the position of the mouse cursor when the event
2002occurred. 2002occurred.
2003 2003
2004@var{clicks}, if present, is the number of times in quick succession 2004@var{clicks}, if present, is the number of times that the wheel was
2005the wheel has been moved. @xref{Repeat Events}. @var{lines}, if 2005moved in quick succession. @xref{Repeat Events}. @var{lines}, if
2006present and not @code{nil}, is the number of screen lines that should 2006present and not @code{nil}, is the number of screen lines that should
2007be scrolled. @var{pixel-delta}, if present, is a pair of the form 2007be scrolled. @var{pixel-delta}, if present, is a cons cell of the
2008@w{@code{(@var{x} . @var{y})}}, where @var{x} and @var{y} are the 2008form @w{@code{(@var{x} . @var{y})}}, where @var{x} and @var{y} are the
2009number of pixels to scroll by in each axis. 2009numbers of pixels by which to scroll in each axis, a.k.a.@:
2010@dfn{pixelwise deltas}.
2010 2011
2011@cindex pixel-resolution wheel events 2012@cindex pixel-resolution wheel events
2012You can use @var{x} and @var{y} to determine how much the mouse wheel 2013You can use these @var{x} and @var{y} pixelwise deltas to determine
2013has actually moved at pixel resolution. 2014how much the mouse wheel has actually moved at pixel resolution. For
2014 2015example, the pixelwise deltas could be used to scroll the display at
2015For example, the pixelwise deltas could be used to scroll the display 2016pixel resolution, exactly according to the user's turning the mouse
2016at pixel resolution, exactly according to the user's turning the mouse
2017wheel. 2017wheel.
2018 2018
2019@vindex mouse-wheel-up-event 2019@vindex mouse-wheel-up-event
diff --git a/src/haikuterm.c b/src/haikuterm.c
index 6bf45894065..f3c37b0258e 100644
--- a/src/haikuterm.c
+++ b/src/haikuterm.c
@@ -3024,7 +3024,7 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3024 3024
3025 if (fabsf (py) >= FRAME_LINE_HEIGHT (f) 3025 if (fabsf (py) >= FRAME_LINE_HEIGHT (f)
3026 || fabsf (px) >= FRAME_COLUMN_WIDTH (f) 3026 || fabsf (px) >= FRAME_COLUMN_WIDTH (f)
3027 || !x_coalesce_scroll_events) 3027 || !mwheel_coalesce_scroll_events)
3028 { 3028 {
3029 inev.kind = (fabsf (px) > fabsf (py) 3029 inev.kind = (fabsf (px) > fabsf (py)
3030 ? HORIZ_WHEEL_EVENT 3030 ? HORIZ_WHEEL_EVENT
@@ -3565,10 +3565,6 @@ syms_of_haikuterm (void)
3565 doc: /* SKIP: real doc in xterm.c. */); 3565 doc: /* SKIP: real doc in xterm.c. */);
3566 Vx_toolkit_scroll_bars = Qt; 3566 Vx_toolkit_scroll_bars = Qt;
3567 3567
3568 DEFVAR_BOOL ("x-coalesce-scroll-events", x_coalesce_scroll_events,
3569 doc: /* SKIP: real doc in xterm.c. */);
3570 x_coalesce_scroll_events = true;
3571
3572 DEFVAR_BOOL ("haiku-debug-on-fatal-error", haiku_debug_on_fatal_error, 3568 DEFVAR_BOOL ("haiku-debug-on-fatal-error", haiku_debug_on_fatal_error,
3573 doc: /* If non-nil, Emacs will launch the system debugger upon a fatal error. */); 3569 doc: /* If non-nil, Emacs will launch the system debugger upon a fatal error. */);
3574 haiku_debug_on_fatal_error = 1; 3570 haiku_debug_on_fatal_error = 1;
diff --git a/src/keyboard.c b/src/keyboard.c
index c98175aea0d..b3e6e5029be 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -12571,6 +12571,12 @@ other similar functions ignore input events in `while-no-input-ignore-events'.
12571This flag may eventually be removed once this behavior is deemed safe. */); 12571This flag may eventually be removed once this behavior is deemed safe. */);
12572 input_pending_p_filter_events = true; 12572 input_pending_p_filter_events = true;
12573 12573
12574 DEFVAR_BOOL ("mwheel-coalesce-scroll-events", mwheel_coalesce_scroll_events,
12575 doc: /* Non-nil means send a wheel event only for scrolling at least one screen line.
12576Otherwise, a wheel event will be sent every time the mouse wheel is
12577moved. */);
12578 mwheel_coalesce_scroll_events = true;
12579
12574 pdumper_do_now_and_after_load (syms_of_keyboard_for_pdumper); 12580 pdumper_do_now_and_after_load (syms_of_keyboard_for_pdumper);
12575} 12581}
12576 12582
diff --git a/src/nsterm.m b/src/nsterm.m
index 807309eb2eb..5c19b0cab82 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -6606,7 +6606,7 @@ not_in_argv (NSString *arg)
6606 * reset the total delta for the direction we're NOT 6606 * reset the total delta for the direction we're NOT
6607 * scrolling so that small movements don't add up. */ 6607 * scrolling so that small movements don't add up. */
6608 if (abs (totalDeltaX) > abs (totalDeltaY) 6608 if (abs (totalDeltaX) > abs (totalDeltaY)
6609 && (!x_coalesce_scroll_events 6609 && (!mwheel_coalesce_scroll_events
6610 || abs (totalDeltaX) > lineHeight)) 6610 || abs (totalDeltaX) > lineHeight))
6611 { 6611 {
6612 horizontal = YES; 6612 horizontal = YES;
@@ -6614,14 +6614,14 @@ not_in_argv (NSString *arg)
6614 6614
6615 lines = abs (totalDeltaX / lineHeight); 6615 lines = abs (totalDeltaX / lineHeight);
6616 x = totalDeltaX; 6616 x = totalDeltaX;
6617 if (!x_coalesce_scroll_events) 6617 if (!mwheel_coalesce_scroll_events)
6618 totalDeltaX = 0; 6618 totalDeltaX = 0;
6619 else 6619 else
6620 totalDeltaX = totalDeltaX % lineHeight; 6620 totalDeltaX = totalDeltaX % lineHeight;
6621 totalDeltaY = 0; 6621 totalDeltaY = 0;
6622 } 6622 }
6623 else if (abs (totalDeltaY) >= abs (totalDeltaX) 6623 else if (abs (totalDeltaY) >= abs (totalDeltaX)
6624 && (!x_coalesce_scroll_events 6624 && (!mwheel_coalesce_scroll_events
6625 || abs (totalDeltaY) > lineHeight)) 6625 || abs (totalDeltaY) > lineHeight))
6626 { 6626 {
6627 horizontal = NO; 6627 horizontal = NO;
@@ -6629,7 +6629,7 @@ not_in_argv (NSString *arg)
6629 6629
6630 lines = abs (totalDeltaY / lineHeight); 6630 lines = abs (totalDeltaY / lineHeight);
6631 y = totalDeltaY; 6631 y = totalDeltaY;
6632 if (!x_coalesce_scroll_events) 6632 if (!mwheel_coalesce_scroll_events)
6633 totalDeltaY = 0; 6633 totalDeltaY = 0;
6634 else 6634 else
6635 totalDeltaY = totalDeltaY % lineHeight; 6635 totalDeltaY = totalDeltaY % lineHeight;
@@ -6662,7 +6662,7 @@ not_in_argv (NSString *arg)
6662 y = [theEvent scrollingDeltaY]; 6662 y = [theEvent scrollingDeltaY];
6663 } 6663 }
6664 6664
6665 if (lines == 0 && x_coalesce_scroll_events) 6665 if (lines == 0 && mwheel_coalesce_scroll_events)
6666 return; 6666 return;
6667 6667
6668 if (NUMBERP (Vns_scroll_event_delta_factor)) 6668 if (NUMBERP (Vns_scroll_event_delta_factor))
@@ -10037,10 +10037,6 @@ This variable is ignored on macOS < 10.7 and GNUstep. Default is t. */);
10037 doc: /* SKIP: real doc in xterm.c. */); 10037 doc: /* SKIP: real doc in xterm.c. */);
10038 x_underline_at_descent_line = 0; 10038 x_underline_at_descent_line = 0;
10039 10039
10040 DEFVAR_BOOL ("x-coalesce-scroll-events", x_coalesce_scroll_events,
10041 doc: /* SKIP: real doc in xterm.c. */);
10042 x_coalesce_scroll_events = true;
10043
10044 DEFSYM (Qx_underline_at_descent_line, "x-underline-at-descent-line"); 10040 DEFSYM (Qx_underline_at_descent_line, "x-underline-at-descent-line");
10045 10041
10046 DEFVAR_LISP ("ns-scroll-event-delta-factor", Vns_scroll_event_delta_factor, 10042 DEFVAR_LISP ("ns-scroll-event-delta-factor", Vns_scroll_event_delta_factor,
diff --git a/src/w32fns.c b/src/w32fns.c
index c1686beaaa9..65463b52616 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -5173,6 +5173,13 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
5173 my_post_msg (&wmsg, hwnd, msg, wParam, lParam); 5173 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
5174 goto dflt; 5174 goto dflt;
5175 5175
5176 case WM_SETTINGCHANGE:
5177 /* Inform the Lisp thread that some system-wide setting has
5178 changed, so if Emacs is interested in some of them, it could
5179 update its internal values. */
5180 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
5181 goto dflt;
5182
5176 case WM_SETFOCUS: 5183 case WM_SETFOCUS:
5177 dpyinfo->faked_key = 0; 5184 dpyinfo->faked_key = 0;
5178 reset_modifiers (); 5185 reset_modifiers ();
diff --git a/src/w32term.c b/src/w32term.c
index 07a5cd35649..6b7cbbea6ca 100644
--- a/src/w32term.c
+++ b/src/w32term.c
@@ -164,6 +164,10 @@ int last_scroll_bar_drag_pos;
164/* Keyboard code page - may be changed by language-change events. */ 164/* Keyboard code page - may be changed by language-change events. */
165int w32_keyboard_codepage; 165int w32_keyboard_codepage;
166 166
167/* The number of screen lines to scroll for the default mouse-wheel
168 scroll amount, given by WHEEL_DELTA. */
169static UINT w32_wheel_scroll_lines;
170
167#ifdef CYGWIN 171#ifdef CYGWIN
168int w32_message_fd = -1; 172int w32_message_fd = -1;
169#endif /* CYGWIN */ 173#endif /* CYGWIN */
@@ -272,6 +276,19 @@ XGetGCValues (void *ignore, XGCValues *gc,
272#endif 276#endif
273 277
274static void 278static void
279w32_get_mouse_wheel_vertical_delta (void)
280{
281 if (os_subtype != OS_SUBTYPE_NT)
282 return;
283
284 UINT scroll_lines;
285 BOOL ret = SystemParametersInfo (SPI_GETWHEELSCROLLLINES, 0,
286 &scroll_lines, 0);
287 if (ret)
288 w32_wheel_scroll_lines = scroll_lines;
289}
290
291static void
275w32_set_clip_rectangle (HDC hdc, RECT *rect) 292w32_set_clip_rectangle (HDC hdc, RECT *rect)
276{ 293{
277 if (rect) 294 if (rect)
@@ -3203,32 +3220,94 @@ w32_construct_mouse_wheel (struct input_event *result, W32Msg *msg,
3203{ 3220{
3204 POINT p; 3221 POINT p;
3205 int delta; 3222 int delta;
3223 static int sum_delta_y = 0;
3206 3224
3207 result->kind = msg->msg.message == WM_MOUSEHWHEEL ? HORIZ_WHEEL_EVENT 3225 result->kind = msg->msg.message == WM_MOUSEHWHEEL ? HORIZ_WHEEL_EVENT
3208 : WHEEL_EVENT; 3226 : WHEEL_EVENT;
3209 result->code = 0; 3227 result->code = 0;
3210 result->timestamp = msg->msg.time; 3228 result->timestamp = msg->msg.time;
3229 result->arg = Qnil;
3211 3230
3212 /* A WHEEL_DELTA positive value indicates that the wheel was rotated 3231 /* A WHEEL_DELTA positive value indicates that the wheel was rotated
3213 forward, away from the user (up); a negative value indicates that 3232 forward, away from the user (up); a negative value indicates that
3214 the wheel was rotated backward, toward the user (down). */ 3233 the wheel was rotated backward, toward the user (down). */
3215 delta = GET_WHEEL_DELTA_WPARAM (msg->msg.wParam); 3234 delta = GET_WHEEL_DELTA_WPARAM (msg->msg.wParam);
3235 if (delta == 0)
3236 {
3237 result->kind = NO_EVENT;
3238 return Qnil;
3239 }
3240
3241 /* With multiple monitors, we can legitimately get negative
3242 coordinates, so cast to short to interpret them correctly. */
3243 p.x = (short) LOWORD (msg->msg.lParam);
3244 p.y = (short) HIWORD (msg->msg.lParam);
3245
3246 if (eabs (delta) < WHEEL_DELTA)
3247 {
3248 /* This is high-precision mouse wheel, which sends
3249 fine-resolution wheel events. Produce a wheel event only if
3250 the conditions for sending such an event are fulfilled. */
3251 int scroll_unit = max (w32_wheel_scroll_lines, 1), nlines;
3252 double value_to_report;
3253
3254 /* w32_wheel_scroll_lines == INT_MAX means the user asked for
3255 "entire page" to be the scroll unit. We interpret that as
3256 the height of the window under the mouse pointer. */
3257 if (w32_wheel_scroll_lines == INT_MAX)
3258 {
3259 Lisp_Object window = window_from_coordinates (f, p.x, p.y, NULL,
3260 false, false);
3261 if (!WINDOWP (window))
3262 {
3263 result->kind = NO_EVENT;
3264 return Qnil;
3265 }
3266 scroll_unit = XWINDOW (window)->pixel_height;
3267 if (scroll_unit < 1) /* paranoia */
3268 scroll_unit = 1;
3269 }
3270
3271 /* If mwheel-coalesce-scroll-events is non-nil, report a wheel event
3272 only when we have accumulated enough delta's for WHEEL_DELTA. */
3273 if (mwheel_coalesce_scroll_events)
3274 {
3275 /* If the user changed the direction, reset the accumulated
3276 deltas. */
3277 if ((delta > 0) != (sum_delta_y > 0))
3278 sum_delta_y = 0;
3279 sum_delta_y += delta;
3280 /* https://docs.microsoft.com/en-us/previous-versions/ms997498(v=msdn.10) */
3281 if (eabs (sum_delta_y) < WHEEL_DELTA)
3282 {
3283 result->kind = NO_EVENT;
3284 return Qnil;
3285 }
3286 value_to_report =
3287 ((double)FRAME_LINE_HEIGHT (f) * scroll_unit)
3288 / ((double)WHEEL_DELTA / sum_delta_y);
3289 sum_delta_y = 0;
3290 }
3291 else
3292 value_to_report =
3293 ((double)FRAME_LINE_HEIGHT (f) * scroll_unit)
3294 / ((double)WHEEL_DELTA / delta);
3295 nlines = value_to_report / FRAME_LINE_HEIGHT (f) + 0.5;
3296 result->arg = list3 (make_fixnum (nlines),
3297 make_float (0.0),
3298 make_float (value_to_report));
3299 }
3216 3300
3217 /* The up and down modifiers indicate if the wheel was rotated up or 3301 /* The up and down modifiers indicate if the wheel was rotated up or
3218 down based on WHEEL_DELTA value. */ 3302 down based on WHEEL_DELTA value. */
3219 result->modifiers = (msg->dwModifiers 3303 result->modifiers = (msg->dwModifiers
3220 | ((delta < 0 ) ? down_modifier : up_modifier)); 3304 | ((delta < 0 ) ? down_modifier : up_modifier));
3221 3305
3222 /* With multiple monitors, we can legitimately get negative
3223 coordinates, so cast to short to interpret them correctly. */
3224 p.x = (short) LOWORD (msg->msg.lParam);
3225 p.y = (short) HIWORD (msg->msg.lParam);
3226 /* For the case that F's w32 window is not msg->msg.hwnd. */ 3306 /* For the case that F's w32 window is not msg->msg.hwnd. */
3227 ScreenToClient (FRAME_W32_WINDOW (f), &p); 3307 ScreenToClient (FRAME_W32_WINDOW (f), &p);
3228 XSETINT (result->x, p.x); 3308 XSETINT (result->x, p.x);
3229 XSETINT (result->y, p.y); 3309 XSETINT (result->y, p.y);
3230 XSETFRAME (result->frame_or_window, f); 3310 XSETFRAME (result->frame_or_window, f);
3231 result->arg = Qnil;
3232 return Qnil; 3311 return Qnil;
3233} 3312}
3234 3313
@@ -4905,6 +4984,14 @@ w32_read_socket (struct terminal *terminal,
4905 } 4984 }
4906 break; 4985 break;
4907 4986
4987 case WM_SETTINGCHANGE:
4988 /* We are only interested in changes of the number of lines
4989 to scroll when the vertical mouse wheel is moved. This
4990 is only supported on NT. */
4991 if (msg.msg.wParam == SPI_SETWHEELSCROLLLINES)
4992 w32_get_mouse_wheel_vertical_delta ();
4993 break;
4994
4908 case WM_KEYDOWN: 4995 case WM_KEYDOWN:
4909 case WM_SYSKEYDOWN: 4996 case WM_SYSKEYDOWN:
4910 f = w32_window_to_frame (dpyinfo, msg.msg.hwnd); 4997 f = w32_window_to_frame (dpyinfo, msg.msg.hwnd);
@@ -7522,6 +7609,8 @@ w32_initialize (void)
7522 horizontal_scroll_bar_left_border = horizontal_scroll_bar_right_border 7609 horizontal_scroll_bar_left_border = horizontal_scroll_bar_right_border
7523 = GetSystemMetrics (SM_CYHSCROLL); 7610 = GetSystemMetrics (SM_CYHSCROLL);
7524 } 7611 }
7612
7613 w32_get_mouse_wheel_vertical_delta ();
7525} 7614}
7526 7615
7527void 7616void
diff --git a/src/xterm.c b/src/xterm.c
index ed6a31125c9..d633953018c 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -10024,7 +10024,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
10024 10024
10025 val->emacs_value += delta; 10025 val->emacs_value += delta;
10026 10026
10027 if (x_coalesce_scroll_events 10027 if (mwheel_coalesce_scroll_events
10028 && (fabs (val->emacs_value) < 1)) 10028 && (fabs (val->emacs_value) < 1))
10029 continue; 10029 continue;
10030 10030
@@ -15214,13 +15214,6 @@ consuming frame position adjustments. In newer versions of GTK, Emacs
15214always uses gtk_window_move and ignores the value of this variable. */); 15214always uses gtk_window_move and ignores the value of this variable. */);
15215 x_gtk_use_window_move = true; 15215 x_gtk_use_window_move = true;
15216 15216
15217 DEFVAR_BOOL ("x-coalesce-scroll-events", x_coalesce_scroll_events,
15218 doc: /* Non-nil means send a wheel event only for scrolling at least one screen line.
15219Otherwise, a wheel event will be sent every time the mouse wheel is
15220moved. This option is only effective when Emacs is built with XInput
152212, with Haiku windowing support, or with NS. */);
15222 x_coalesce_scroll_events = true;
15223
15224 DEFVAR_LISP ("x-scroll-event-delta-factor", Vx_scroll_event_delta_factor, 15217 DEFVAR_LISP ("x-scroll-event-delta-factor", Vx_scroll_event_delta_factor,
15225 doc: /* A scale to apply to pixel deltas reported in scroll events. 15218 doc: /* A scale to apply to pixel deltas reported in scroll events.
15226This option is only effective when Emacs is built with XInput 2 15219This option is only effective when Emacs is built with XInput 2