From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Alan Third Newsgroups: gmane.emacs.devel Subject: Re: Smoother macOS touchpad scrolling Date: Sat, 16 Sep 2017 23:33:17 +0100 Message-ID: <20170916223317.GA58067@breton.holly.idiocy.org> References: <20170908184634.GA20058@breton.holly.idiocy.org> <86y3pox258.fsf@misasa.okayama-u.ac.jp> <20170909081805.GA20275@breton.holly.idiocy.org> <86ingrl56v.fsf@misasa.okayama-u.ac.jp> <20170910083758.GA30315@breton.holly.idiocy.org> NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="xHFwDpU9dbj6ez1V" Content-Transfer-Encoding: 8bit X-Trace: blaine.gmane.org 1505601249 11019 195.159.176.226 (16 Sep 2017 22:34:09 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Sat, 16 Sep 2017 22:34:09 +0000 (UTC) User-Agent: Mutt/1.9.0 (2017-09-02) Cc: Emacs-Devel devel To: Tak Kunihiro Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Sun Sep 17 00:34:05 2017 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by blaine.gmane.org with esmtp (Exim 4.84_2) (envelope-from ) id 1dtLf1-0002bZ-8G for ged-emacs-devel@m.gmane.org; Sun, 17 Sep 2017 00:34:03 +0200 Original-Received: from localhost ([::1]:58775 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dtLf7-000672-1o for ged-emacs-devel@m.gmane.org; Sat, 16 Sep 2017 18:34:09 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:40291) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dtLeP-00066Y-SJ for emacs-devel@gnu.org; Sat, 16 Sep 2017 18:33:27 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dtLeO-0002Q9-0A for emacs-devel@gnu.org; Sat, 16 Sep 2017 18:33:25 -0400 Original-Received: from mail-wr0-x22e.google.com ([2a00:1450:400c:c0c::22e]:53608) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1dtLeN-0002Pl-JO for emacs-devel@gnu.org; Sat, 16 Sep 2017 18:33:23 -0400 Original-Received: by mail-wr0-x22e.google.com with SMTP id l22so3926187wrc.10 for ; Sat, 16 Sep 2017 15:33:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20161025; h=sender:date:from:to:cc:subject:message-id:references:mime-version :content-disposition:content-transfer-encoding:in-reply-to :user-agent; bh=HHA36+A3EJzugGG2ztuyCucgCw70VPMCW7/LoPMNbdI=; b=YUfrT2+ucuMrBenDBCV1ImRN3MS9uWCsV0lwZU9p9QNH558N1nunP0u1NhyHzpRbLy L6svaKbX4X52smOfI39xHS/ne9W6NsqVsYw2BuF3cVfv7wdvOR5HvXLWZy6Zxj8Pxx/T modJoqyjRW1OV8K+EyKt/kj+A6NbfcUMvzHK1m00jFXSJShAMe5I6pZzxnMxBnnIc8aM s2pQLDqt7KZy1oT3FCEtZnOssINzyp4sNxkJcCDopNzAu2yha7D0qJnNquREpTekM9I8 oMOJxRc+1/5x0QuKfnZlEa7CNmJcNhklIT8pd2bCDvKzMhNqtnqZxre3iAkQfvGwq/oo T7UQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:from:to:cc:subject:message-id :references:mime-version:content-disposition :content-transfer-encoding:in-reply-to:user-agent; bh=HHA36+A3EJzugGG2ztuyCucgCw70VPMCW7/LoPMNbdI=; b=HgIz/WgI0EnbRtWry31L/wNffhxy26XeEooD4OkpynO2FhNRLcWEHwc3197cBaf6t+ ykqpCfaU/0Nj68frUM3OlFhIZIBHmLogKruabOdGdAMIk2VQrR3xyapQzsdpiyx7dPKk R8VLDDQDdMhaCAoNBdYvb/ONI/V1jl+wJBr40D/hW0YpG/OzRvplV7LsrDq7df7Qa5wb Gzn+W8g/IJQW2EElO8ZCGZU62B6UHkAY6Ya1GUzeIIPElsfX7qIMmxgJBtU0c8+HFX6O YoXMhLzbI9BrECOaJoCyqGdwLSMBM3+7e3B1nj4D/ClA7qzh6AEeoGL04J+1ijegxIBq OKtg== X-Gm-Message-State: AHPjjUismnwu3wU3T4Ip00kCK10+OWTfRhpJZ8pIW5admlejjkIgKzCL sn7oIUH5s81mog== X-Google-Smtp-Source: ADKCNb7EtCwbC1sO1XqeLb67R2q+2HDBUkQQi7ZK0Qw/FtxnFy0ZkyEwvNyUsaDGRDJHm76OKP1Ong== X-Received: by 10.223.139.157 with SMTP id o29mr26497999wra.190.1505601201260; Sat, 16 Sep 2017 15:33:21 -0700 (PDT) Original-Received: from breton.holly.idiocy.org (ip6-2001-08b0-03f8-8129-dc16-e8c9-c53b-72e4.holly.idiocy.org. [2001:8b0:3f8:8129:dc16:e8c9:c53b:72e4]) by smtp.gmail.com with ESMTPSA id k52sm5018414wrf.62.2017.09.16.15.33.19 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sat, 16 Sep 2017 15:33:19 -0700 (PDT) Content-Disposition: inline In-Reply-To: <20170910083758.GA30315@breton.holly.idiocy.org> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:400c:c0c::22e X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.org gmane.emacs.devel:218379 Archived-At: --xHFwDpU9dbj6ez1V Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: 8bit On Sun, Sep 10, 2017 at 09:37:58AM +0100, Alan Third wrote: > > You mean one event per pixel to be scrolled, or pass the delta in the > event? > > I can certainly do the former, although it will potentially result in > a torrent of scroll events. > > The latter is, I think, banned as it can’t be replicated on a Free > system, but is the better solution. I was thinking about this, and it’s not actually a new feature, it’s an optimization of a feature that already exists (progressive scroll). The fact the optimization is only available on macOS is irrelevant. So in that spirit I’ve attached another patch. Can Eli or John let me know if I’m thinking about this right? And if this patch *is* ok, is it too late for Emacs 26? -- Alan Third --xHFwDpU9dbj6ez1V Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="0001-Provide-native-touchpad-scrolling-on-macOS.patch" >From 9295fbb214b32555b55b0c1c56d0831bf6395c1c Mon Sep 17 00:00:00 2001 From: Alan Third Date: Fri, 8 Sep 2017 19:26:47 +0100 Subject: [PATCH] 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 | 7 +++ src/keyboard.c | 5 +- src/nsterm.m | 158 ++++++++++++++++++++++++++++++++++++++++++++++++---- src/termhooks.h | 4 +- 7 files changed, 172 insertions(+), 14 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 371cdf686c..6111738b0f 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -49,6 +49,12 @@ When you add a new item, use the appropriate mark if you are sure it applies, * Changes in Emacs 27.1 on Non-Free Operating Systems +--- +** 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 2956ba5516..0c0dcb3beb 100644 --- a/lisp/mwheel.el +++ b/lisp/mwheel.el @@ -232,6 +232,7 @@ mwheel-scroll ;; 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 79ae1f4830..f0d0b24462 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -1270,6 +1270,11 @@ event-click-count "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 68b659bf75..6aef27362f 100644 --- a/lisp/term/ns-win.el +++ b/lisp/term/ns-win.el @@ -736,6 +736,13 @@ ns-paste-secondary (global-unset-key [horizontal-scroll-bar drag-mouse-1]) +;;;; macOS-like defaults for trackpad and mouse wheel scrolling. + +(when (featurep 'cocoa) + (setq mouse-wheel-scroll-amount '(1 ((shift) . 5) ((control)))) + (setq mouse-wheel-progressive-speed nil)) + + ;;;; Color support. ;; Functions for color panel + drag diff --git a/src/keyboard.c b/src/keyboard.c index 4db50be855..e8701b8870 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 2751533533..776635980e 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -6498,24 +6498,139 @@ - (void)mouseDown: (NSEvent *)theEvent 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 @@ - (void)mouseDown: (NSEvent *)theEvent 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 @@ Nil means use fullscreen the old (< 10.7) way. The old way works better with 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 97c128ba4e..b5171bf122 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. */ -- 2.14.1 --xHFwDpU9dbj6ez1V--