emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master bab2969: Support precision mouse scrolling on MS-Windows


From: Eli Zaretskii
Subject: master bab2969: Support precision mouse scrolling on MS-Windows
Date: Wed, 1 Dec 2021 08:39:03 -0500 (EST)

branch: master
commit bab29694047d060bb58ff88e1a4d2cc7ef05df2a
Author: Eli Zaretskii <eliz@gnu.org>
Commit: Eli Zaretskii <eliz@gnu.org>

    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.
---
 doc/lispref/commands.texi | 20 +++++-----
 src/haikuterm.c           |  6 +--
 src/keyboard.c            |  6 +++
 src/nsterm.m              | 14 +++----
 src/w32fns.c              |  7 ++++
 src/w32term.c             | 99 ++++++++++++++++++++++++++++++++++++++++++++---
 src/xterm.c               |  9 +----
 7 files changed, 124 insertions(+), 37 deletions(-)

diff --git a/doc/lispref/commands.texi b/doc/lispref/commands.texi
index 920d380..073cdd8 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
 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
diff --git a/src/haikuterm.c b/src/haikuterm.c
index 6bf4589..f3c37b0 100644
--- a/src/haikuterm.c
+++ b/src/haikuterm.c
@@ -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;
diff --git a/src/keyboard.c b/src/keyboard.c
index c98175a..b3e6e50 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'.
 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);
 }
 
diff --git a/src/nsterm.m b/src/nsterm.m
index 807309e..5c19b0c 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -6606,7 +6606,7 @@ not_in_argv (NSString *arg)
                * 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 @@ not_in_argv (NSString *arg)
 
                   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 @@ not_in_argv (NSString *arg)
 
                   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 @@ not_in_argv (NSString *arg)
              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 @@ This variable is ignored on macOS < 10.7 and GNUstep.  
Default is t.  */);
      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,
diff --git a/src/w32fns.c b/src/w32fns.c
index c1686be..65463b5 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -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 ();
diff --git a/src/w32term.c b/src/w32term.c
index 07a5cd3..6b7cbbe 100644
--- a/src/w32term.c
+++ b/src/w32term.c
@@ -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 */
@@ -272,6 +276,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)
 {
   if (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
diff --git a/src/xterm.c b/src/xterm.c
index ed6a311..d633953 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]