emacs-diffs
[Top][All Lists]
Advanced

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

master 603bdc8: Add some primitive momentum-based precision scrolling


From: Po Lu
Subject: master 603bdc8: Add some primitive momentum-based precision scrolling
Date: Wed, 1 Dec 2021 22:07:07 -0500 (EST)

branch: master
commit 603bdc8d38ce4325380d29423939e5287e8aac17
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    Add some primitive momentum-based precision scrolling
    
    The algorithm used to scroll the display kinetically is very
    simple and needs improvement.  Someone should work on that
    eventually.
    
    * lisp/pixel-scroll.el (pixel-scroll-precision-use-momentum):
    New user option.
    (pixel-scroll-precision-mode-map): Add
    `pixel-scroll-start-momentum'.
    (pixel-scroll-kinetic-state):
    (pixel-scroll-accumulate-velocity):
    (pixel-scroll-calculate-velocity): New functions.
    (pixel-scroll-start-momentum): New command.
    
    * src/xterm.c (handle_one_xevent): Fix touch-end event
    generation.
---
 lisp/pixel-scroll.el | 72 +++++++++++++++++++++++++++++++++++++++++++++++++---
 src/xterm.c          | 18 ++++++++-----
 2 files changed, 80 insertions(+), 10 deletions(-)

diff --git a/lisp/pixel-scroll.el b/lisp/pixel-scroll.el
index 2d6531a..092d721 100644
--- a/lisp/pixel-scroll.el
+++ b/lisp/pixel-scroll.el
@@ -68,6 +68,7 @@
 
 (require 'mwheel)
 (require 'subr-x)
+(require 'ring)
 
 (defvar pixel-wait 0
   "Idle time on each step of pixel scroll specified in second.
@@ -97,9 +98,17 @@ is always with pixel resolution.")
   (let ((map (make-sparse-keymap)))
     (define-key map [wheel-down] #'pixel-scroll-precision)
     (define-key map [wheel-up] #'pixel-scroll-precision)
+    (define-key map [touch-end] #'pixel-scroll-start-momentum)
     map)
   "The key map used by `pixel-scroll-precision-mode'.")
 
+(defcustom pixel-scroll-precision-use-momentum nil
+  "If non-nil, continue to scroll the display after wheel movement stops.
+This is only effective if supported by your mouse or touchpad."
+  :group 'mouse
+  :type 'boolean
+  :version "29.1")
+
 (defun pixel-scroll-in-rush-p ()
   "Return non-nil if next scroll should be non-smooth.
 When scrolling request is delivered soon after the previous one,
@@ -475,9 +484,11 @@ wheel."
                 (mwheel-scroll event nil)
               (with-selected-window window
                 (condition-case nil
-                    (if (< delta 0)
-                       (pixel-scroll-precision-scroll-down (- delta))
-                      (pixel-scroll-precision-scroll-up delta))
+                    (progn
+                      (if (< delta 0)
+                         (pixel-scroll-precision-scroll-down (- delta))
+                        (pixel-scroll-precision-scroll-up delta))
+                      (pixel-scroll-accumulate-velocity delta))
                   ;; Do not ding at buffer limits.  Show a message instead.
                   (beginning-of-buffer
                    (message (error-message-string '(beginning-of-buffer))))
@@ -485,6 +496,61 @@ wheel."
                    (message (error-message-string '(end-of-buffer)))))))))
       (mwheel-scroll event nil))))
 
+(defun pixel-scroll-kinetic-state ()
+  "Return the kinetic scroll state of the current window.
+It is a vector of the form [ VELOCITY TIME ]."
+  (or (window-parameter nil 'kinetic-state)
+      (set-window-parameter nil 'kinetic-state
+                            (vector (make-ring 4) nil))))
+
+(defun pixel-scroll-accumulate-velocity (delta)
+  "Accumulate DELTA into the current window's kinetic scroll state."
+  (let* ((state (pixel-scroll-kinetic-state))
+         (time (aref state 1)))
+    (when (and time (> (- (float-time) time) 0.5))
+      (aset state 0 (make-ring 45)))
+    (ring-insert (aref state 0)
+                 (cons (aset state 1 (float-time))
+                       delta))))
+
+(defun pixel-scroll-calculate-velocity (state)
+  "Calculate velocity from the kinetic state vector STATE."
+  (let* ((ring (aref state 0))
+         (elts (ring-elements ring))
+         (total 0))
+    (dolist (tem elts)
+      (setq total (+ total (cdr tem))))
+    (/ total (* (- (caar elts)
+                   (caar (last elts)))
+                100))))
+
+(defun pixel-scroll-start-momentum (event)
+  "Start kinetic scrolling for the touch event EVENT."
+  (interactive "e")
+  (when pixel-scroll-precision-use-momentum
+    (let ((window (mwheel-event-window event))
+          (state nil))
+      (with-selected-window window
+        (setq state (pixel-scroll-kinetic-state))
+        (when (aref state 1)
+          (unwind-protect (progn
+                            (aset state 0
+                                  (pixel-scroll-calculate-velocity state))
+                            (let ((velocity (aref state 0)))
+                              (if (> velocity 0)
+                                  (while (> velocity 0)
+                                    (pixel-scroll-precision-scroll-up 1)
+                                    (setq velocity (1- velocity))
+                                    (sit-for 0.1)
+                                    (redisplay t))
+                                (while (< velocity 0)
+                                  (pixel-scroll-precision-scroll-down 1)
+                                  (setq velocity (1+ velocity))
+                                  (sit-for 0.1)
+                                  (redisplay t)))))
+            (aset state 0 (make-ring 45))
+            (aset state 1 nil)))))))
+
 ;;;###autoload
 (define-minor-mode pixel-scroll-precision-mode
   "Toggle pixel scrolling.
diff --git a/src/xterm.c b/src/xterm.c
index fe26e41..3f7b956 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -10025,11 +10025,12 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                        val->emacs_value += delta;
 
                        if (mwheel_coalesce_scroll_events
-                           && (fabs (val->emacs_value) < 1))
+                           && (fabs (val->emacs_value) < 1)
+                           && (fabs (delta) > 0))
                          continue;
 
                        bool s = signbit (val->emacs_value);
-                       inev.ie.kind = (delta != 0.0
+                       inev.ie.kind = (fabs (delta) > 0
                                        ? (val->horizontal
                                           ? HORIZ_WHEEL_EVENT
                                           : WHEEL_EVENT)
@@ -10040,17 +10041,20 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                        XSETINT (inev.ie.y, lrint (xev->event_y));
                        XSETFRAME (inev.ie.frame_or_window, f);
 
-                       inev.ie.modifiers = !s ? up_modifier : down_modifier;
-                       inev.ie.modifiers
-                         |= x_x_to_emacs_modifiers (dpyinfo,
-                                                    xev->mods.effective);
+                       if (fabs (delta) > 0)
+                         {
+                           inev.ie.modifiers = !s ? up_modifier : 
down_modifier;
+                           inev.ie.modifiers
+                             |= x_x_to_emacs_modifiers (dpyinfo,
+                                                        xev->mods.effective);
+                         }
 
                        scroll_unit = pow (FRAME_PIXEL_HEIGHT (f), 2.0 / 3.0);
 
                        if (NUMBERP (Vx_scroll_event_delta_factor))
                          scroll_unit *= XFLOATINT 
(Vx_scroll_event_delta_factor);
 
-                       if (delta != 0.0)
+                       if (fabs (delta) > 0)
                          {
                            if (val->horizontal)
                              {



reply via email to

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