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.
This commit is contained in:
parent
7b3d1c6beb
commit
a5fec62b51
7 changed files with 184 additions and 14 deletions
6
etc/NEWS
6
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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
158
src/nsterm.m
158
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.
|
||||
|
|
|
@ -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. */
|
||||
|
|
Loading…
Add table
Reference in a new issue