mirror of
https://github.com/masscollaborationlabs/emacs.git
synced 2025-07-05 11:49:37 +00:00
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.
|
** '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.
|
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,
|
;; 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, ...).
|
;; So by adding things up we get a squaring up (1, 3, 6, 10, 15, ...).
|
||||||
(setq amt (* amt (event-click-count event))))
|
(setq amt (* amt (event-click-count event))))
|
||||||
|
(when (numberp amt) (setq amt (* amt (event-line-count event))))
|
||||||
(unwind-protect
|
(unwind-protect
|
||||||
(let ((button (mwheel-event-button event)))
|
(let ((button (mwheel-event-button event)))
|
||||||
(cond ((eq button mouse-wheel-down-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.
|
"Return the multi-click count of EVENT, a click or drag event.
|
||||||
The return value is a positive integer."
|
The return value is a positive integer."
|
||||||
(if (and (consp event) (integerp (nth 2 event))) (nth 2 event) 1))
|
(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.
|
;;;; 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])
|
(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.
|
;;;; Color support.
|
||||||
|
|
||||||
;; Functions for color panel + drag
|
;; Functions for color panel + drag
|
||||||
|
|
|
@ -5925,7 +5925,10 @@ make_lispy_event (struct input_event *event)
|
||||||
ASIZE (wheel_syms));
|
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));
|
return list3 (head, position, make_number (double_click_count));
|
||||||
else
|
else
|
||||||
return list2 (head, position);
|
return list2 (head, position);
|
||||||
|
|
158
src/nsterm.m
158
src/nsterm.m
|
@ -6498,24 +6498,139 @@ - (void)mouseDown: (NSEvent *)theEvent
|
||||||
|
|
||||||
if ([theEvent type] == NSEventTypeScrollWheel)
|
if ([theEvent type] == NSEventTypeScrollWheel)
|
||||||
{
|
{
|
||||||
CGFloat delta = [theEvent deltaY];
|
#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||||||
/* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
|
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
|
||||||
if (delta == 0)
|
if ([theEvent respondsToSelector:@selector(hasPreciseScrollingDeltas)])
|
||||||
{
|
{
|
||||||
delta = [theEvent deltaX];
|
#endif
|
||||||
if (delta == 0)
|
/* 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");
|
static int totalDeltaX, totalDeltaY;
|
||||||
return;
|
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
|
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->code = 0;
|
||||||
emacs_event->modifiers = EV_MODIFIERS (theEvent) |
|
emacs_event->modifiers = EV_MODIFIERS (theEvent) |
|
||||||
((delta > 0) ? up_modifier : down_modifier);
|
((delta > 0) ? up_modifier : down_modifier);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -6524,9 +6639,11 @@ - (void)mouseDown: (NSEvent *)theEvent
|
||||||
emacs_event->modifiers = EV_MODIFIERS (theEvent)
|
emacs_event->modifiers = EV_MODIFIERS (theEvent)
|
||||||
| EV_UDMODIFIERS (theEvent);
|
| EV_UDMODIFIERS (theEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
XSETINT (emacs_event->x, lrint (p.x));
|
XSETINT (emacs_event->x, lrint (p.x));
|
||||||
XSETINT (emacs_event->y, lrint (p.y));
|
XSETINT (emacs_event->y, lrint (p.y));
|
||||||
EV_TRAILER (theEvent);
|
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. */);
|
This variable is ignored on Mac OS X < 10.7 and GNUstep. */);
|
||||||
ns_use_srgb_colorspace = YES;
|
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 */
|
/* TODO: move to common code */
|
||||||
DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
|
DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
|
||||||
doc: /* Which toolkit scroll bars Emacs uses, if any.
|
doc: /* Which toolkit scroll bars Emacs uses, if any.
|
||||||
|
|
|
@ -116,7 +116,9 @@ enum event_kind
|
||||||
.frame_or_window gives the frame
|
.frame_or_window gives the frame
|
||||||
the wheel event occurred in.
|
the wheel event occurred in.
|
||||||
.timestamp gives a timestamp (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
|
HORIZ_WHEEL_EVENT, /* A wheel event generated by a second
|
||||||
horizontal wheel that is present on some
|
horizontal wheel that is present on some
|
||||||
mice. See WHEEL_EVENT. */
|
mice. See WHEEL_EVENT. */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue