emacs-diffs
[Top][All Lists]
Advanced

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

[Emacs-diffs] emacs-26 a5fec62: Provide native touchpad scrolling on mac


From: Alan Third
Subject: [Emacs-diffs] emacs-26 a5fec62: Provide native touchpad scrolling on macOS
Date: Tue, 19 Sep 2017 15:09:11 -0400 (EDT)

branch: emacs-26
commit a5fec62b519ae8c0a6528366ac8b71cd0c7ac52e
Author: Alan Third <address@hidden>
Commit: Alan Third <address@hidden>

    Provide native touchpad scrolling on macOS
    
    * etc/NEWS: Describe changes.
    * lisp/term/ns-win.el (mouse-wheel-scroll-amount,
    mouse-wheel-progressive-speed): Set to smarter values for macOS
    touchpads.
    * src/nsterm.m (emacsView::mouseDown): Use precise scrolling deltas to
    calculate scrolling for touchpads and mouse wheels.
    (syms_of_nsterm): Add variables 'ns-use-system-mwheel-acceleration',
    'ns-touchpad-scroll-line-height' and 'ns-touchpad-use-momentum'.
    * src/keyboard.c (make_lispy_event): Pass on .arg when relevant.
    * src/termhooks.h (event_kind): Update comments re. WHEEL_EVENT.
    * lisp/mwheel.el (mwheel-scroll): Use line count.
    * lisp/subr.el (event-line-count): New function.
---
 etc/NEWS            |   6 ++
 lisp/mwheel.el      |   1 +
 lisp/subr.el        |   5 ++
 lisp/term/ns-win.el |  19 +++++++
 src/keyboard.c      |   5 +-
 src/nsterm.m        | 158 ++++++++++++++++++++++++++++++++++++++++++++++++----
 src/termhooks.h     |   4 +-
 7 files changed, 184 insertions(+), 14 deletions(-)

diff --git a/etc/NEWS b/etc/NEWS
index 5aa57a7..a814c3e 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1882,6 +1882,12 @@ of frame decorations on macOS 10.9+.
 ---
 ** 'process-attributes' on Darwin systems now returns more information.
 
+---
+** Mousewheel and trackpad scrolling on macOS 10.7+ now behaves more
+like the macOS default.  The new variables
+'ns-use-system-mwheel-acceleration', 'ns-touchpad-scroll-line-height'
+and 'ns-touchpad-use-momentum' can be used to customise the behavior.
+
 
 ----------------------------------------------------------------------
 This file is part of GNU Emacs.
diff --git a/lisp/mwheel.el b/lisp/mwheel.el
index 2956ba5..0c0dcb3b 100644
--- a/lisp/mwheel.el
+++ b/lisp/mwheel.el
@@ -232,6 +232,7 @@ non-Windows systems."
       ;; When the double-mouse-N comes in, a mouse-N has been executed already,
       ;; So by adding things up we get a squaring up (1, 3, 6, 10, 15, ...).
       (setq amt (* amt (event-click-count event))))
+    (when (numberp amt) (setq amt (* amt (event-line-count event))))
     (unwind-protect
        (let ((button (mwheel-event-button event)))
          (cond ((eq button mouse-wheel-down-event)
diff --git a/lisp/subr.el b/lisp/subr.el
index 96b1ac1..cf15ec2 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -1270,6 +1270,11 @@ See `event-start' for a description of the value 
returned."
   "Return the multi-click count of EVENT, a click or drag event.
 The return value is a positive integer."
   (if (and (consp event) (integerp (nth 2 event))) (nth 2 event) 1))
+
+(defsubst event-line-count (event)
+  "Return the line count of EVENT, a mousewheel event.
+The return value is a positive integer."
+  (if (and (consp event) (integerp (nth 3 event))) (nth 3 event) 1))
 
 ;;;; Extracting fields of the positions in an event.
 
diff --git a/lisp/term/ns-win.el b/lisp/term/ns-win.el
index 68b659b..bc211ea 100644
--- a/lisp/term/ns-win.el
+++ b/lisp/term/ns-win.el
@@ -736,6 +736,25 @@ See the documentation of 
`create-fontset-from-fontset-spec' for the format.")
 (global-unset-key [horizontal-scroll-bar drag-mouse-1])
 
 
+;;;; macOS-like defaults for trackpad and mouse wheel scrolling on
+;;;; macOS 10.7+.
+
+;; FIXME: This doesn't look right.  Is there a better way to do this
+;; that keeps customize happy?
+(let ((appkit-version (progn
+                        (string-match "^appkit-\\([^\s-]*\\)" 
ns-version-string)
+                        (string-to-number (match-string 1 
ns-version-string)))))
+  ;; Appkit 1138 ~= macOS 10.7.
+  (when (and (featurep 'cocoa) (>= appkit-version 1138))
+    (setq mouse-wheel-scroll-amount '(1 ((shift) . 5) ((control))))
+    (put 'mouse-wheel-scroll-amount 'customized-value
+         (list (custom-quote (symbol-value 'mouse-wheel-scroll-amount))))
+
+    (setq mouse-wheel-progressive-speed nil)
+    (put 'mouse-wheel-progressive-speed 'customized-value
+         (list (custom-quote (symbol-value 'mouse-wheel-progressive-speed))))))
+
+
 ;;;; Color support.
 
 ;; Functions for color panel + drag
diff --git a/src/keyboard.c b/src/keyboard.c
index 4db50be..e8701b8 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -5925,7 +5925,10 @@ make_lispy_event (struct input_event *event)
                                      ASIZE (wheel_syms));
        }
 
-       if (event->modifiers & (double_modifier | triple_modifier))
+        if (NUMBERP (event->arg))
+          return list4 (head, position, make_number (double_click_count),
+                        event->arg);
+       else if (event->modifiers & (double_modifier | triple_modifier))
          return list3 (head, position, make_number (double_click_count));
        else
          return list2 (head, position);
diff --git a/src/nsterm.m b/src/nsterm.m
index 2751533..7766359 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -6498,24 +6498,139 @@ not_in_argv (NSString *arg)
 
   if ([theEvent type] == NSEventTypeScrollWheel)
     {
-      CGFloat delta = [theEvent deltaY];
-      /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
-      if (delta == 0)
+#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
+      if ([theEvent respondsToSelector:@selector(hasPreciseScrollingDeltas)])
         {
-          delta = [theEvent deltaX];
-          if (delta == 0)
+#endif
+          /* If the input device is a touchpad or similar, use precise
+           * scrolling deltas.  These are measured in pixels, so we
+           * have to add them up until they exceed one line height,
+           * then we can send a scroll wheel event.
+           *
+           * If the device only has coarse scrolling deltas, like a
+           * real mousewheel, the deltas represent a ratio of whole
+           * lines, so round up the number of lines.  This means we
+           * always send one scroll event per click, but can still
+           * scroll more than one line if the OS tells us to.
+           */
+          bool horizontal;
+          int lines = 0;
+          int scrollUp = NO;
+
+          /* FIXME: At the top or bottom of the buffer we should
+           * ignore momentum-phase events.  */
+          if (! ns_touchpad_use_momentum
+              && [theEvent momentumPhase] != NSEventPhaseNone)
+            return;
+
+          if ([theEvent hasPreciseScrollingDeltas])
             {
-              NSTRACE_MSG ("deltaIsZero");
-              return;
+              static int totalDeltaX, totalDeltaY;
+              int lineHeight;
+
+              if (NUMBERP (ns_touchpad_scroll_line_height))
+                lineHeight = XINT (ns_touchpad_scroll_line_height);
+              else
+                {
+                  /* FIXME: Use actual line height instead of the default.  */
+                  lineHeight = default_line_pixel_height
+                    (XWINDOW (FRAME_SELECTED_WINDOW (emacsframe)));
+                }
+
+              if ([theEvent phase] == NSEventPhaseBegan)
+                {
+                  totalDeltaX = 0;
+                  totalDeltaY = 0;
+                }
+
+              totalDeltaX += [theEvent scrollingDeltaX];
+              totalDeltaY += [theEvent scrollingDeltaY];
+
+              /* Calculate the number of lines, if any, to scroll, and
+               * reset the total delta for the direction we're NOT
+               * scrolling so that small movements don't add up.  */
+              if (abs (totalDeltaX) > abs (totalDeltaY)
+                  && abs (totalDeltaX) > lineHeight)
+                {
+                  horizontal = YES;
+                  scrollUp = totalDeltaX > 0;
+
+                  lines = abs (totalDeltaX / lineHeight);
+                  totalDeltaX = totalDeltaX % lineHeight;
+                  totalDeltaY = 0;
+                }
+              else if (abs (totalDeltaY) >= abs (totalDeltaX)
+                       && abs (totalDeltaY) > lineHeight)
+                {
+                  horizontal = NO;
+                  scrollUp = totalDeltaY > 0;
+
+                  lines = abs (totalDeltaY / lineHeight);
+                  totalDeltaY = totalDeltaY % lineHeight;
+                  totalDeltaX = 0;
+                }
+
+              if (lines > 1 && ! ns_use_system_mwheel_acceleration)
+                lines = 1;
             }
-          emacs_event->kind = HORIZ_WHEEL_EVENT;
+          else
+            {
+              CGFloat delta;
+
+              if ([theEvent scrollingDeltaY] == 0)
+                {
+                  horizontal = YES;
+                  delta = [theEvent scrollingDeltaX];
+                }
+              else
+                {
+                  horizontal = NO;
+                  delta = [theEvent scrollingDeltaY];
+                }
+
+              lines = (ns_use_system_mwheel_acceleration)
+                ? ceil (fabs (delta)) : 1;
+
+              scrollUp = delta > 0;
+            }
+
+          if (lines == 0)
+            return;
+
+          emacs_event->kind = horizontal ? HORIZ_WHEEL_EVENT : WHEEL_EVENT;
+          emacs_event->arg = (make_number (lines));
+
+          emacs_event->code = 0;
+          emacs_event->modifiers = EV_MODIFIERS (theEvent) |
+            (scrollUp ? up_modifier : down_modifier);
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
         }
       else
-        emacs_event->kind = WHEEL_EVENT;
+#endif
+#endif /* defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
+#if defined (NS_IMPL_GNUSTEP) || MAC_OS_X_VERSION_MIN_REQUIRED < 1070
+        {
+          CGFloat delta = [theEvent deltaY];
+          /* Mac notebooks send wheel events w/delta =0 when trackpad 
scrolling */
+          if (delta == 0)
+            {
+              delta = [theEvent deltaX];
+              if (delta == 0)
+                {
+                  NSTRACE_MSG ("deltaIsZero");
+                  return;
+                }
+              emacs_event->kind = HORIZ_WHEEL_EVENT;
+            }
+          else
+            emacs_event->kind = WHEEL_EVENT;
 
-      emacs_event->code = 0;
-      emacs_event->modifiers = EV_MODIFIERS (theEvent) |
-        ((delta > 0) ? up_modifier : down_modifier);
+          emacs_event->code = 0;
+          emacs_event->modifiers = EV_MODIFIERS (theEvent) |
+            ((delta > 0) ? up_modifier : down_modifier);
+        }
+#endif
     }
   else
     {
@@ -6524,9 +6639,11 @@ not_in_argv (NSString *arg)
       emacs_event->modifiers = EV_MODIFIERS (theEvent)
                              | EV_UDMODIFIERS (theEvent);
     }
+
   XSETINT (emacs_event->x, lrint (p.x));
   XSETINT (emacs_event->y, lrint (p.y));
   EV_TRAILER (theEvent);
+  return;
 }
 
 
@@ -9166,6 +9283,23 @@ Note that this does not apply to images.
 This variable is ignored on Mac OS X < 10.7 and GNUstep.  */);
   ns_use_srgb_colorspace = YES;
 
+  DEFVAR_BOOL ("ns-use-system-mwheel-acceleration",
+               ns_use_system_mwheel_acceleration,
+     doc: /*Non-nil means use macOS's standard mouse wheel acceleration.
+This variable is ignored on macOS < 10.7 and GNUstep.  Default is t.  */);
+  ns_use_system_mwheel_acceleration = YES;
+
+  DEFVAR_LISP ("ns-touchpad-scroll-line-height", 
ns_touchpad_scroll_line_height,
+               doc: /*The number of pixels touchpad scrolling considers a line.
+Nil or a non-number means use the default frame line height.
+This variable is ignored on macOS < 10.7 and GNUstep.  Default is nil.  */);
+  ns_touchpad_scroll_line_height = Qnil;
+
+  DEFVAR_BOOL ("ns-touchpad-use-momentum", ns_touchpad_use_momentum,
+               doc: /*Non-nil means touchpad scrolling uses momentum.
+This variable is ignored on macOS < 10.7 and GNUstep.  Default is t.  */);
+  ns_touchpad_use_momentum = YES;
+
   /* TODO: move to common code */
   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
               doc: /* Which toolkit scroll bars Emacs uses, if any.
diff --git a/src/termhooks.h b/src/termhooks.h
index 97c128b..b5171bf 100644
--- a/src/termhooks.h
+++ b/src/termhooks.h
@@ -116,7 +116,9 @@ enum event_kind
                                   .frame_or_window gives the frame
                                   the wheel event occurred in.
                                   .timestamp gives a timestamp (in
-                                  milliseconds) for the event.  */
+                                  milliseconds) for the event.
+                                   .arg may contain the number of
+                                   lines to scroll.  */
   HORIZ_WHEEL_EVENT,            /* A wheel event generated by a second
                                    horizontal wheel that is present on some
                                    mice. See WHEEL_EVENT.  */



reply via email to

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