diff options
| author | Alan Third | 2017-09-08 19:26:47 +0100 |
|---|---|---|
| committer | Alan Third | 2017-09-19 20:08:51 +0100 |
| commit | a5fec62b519ae8c0a6528366ac8b71cd0c7ac52e (patch) | |
| tree | f9b300285aacb4df9995ea5e4559663f2afee735 | |
| parent | 7b3d1c6beb54ef6c423a93df88aebfd6fecbe2c2 (diff) | |
| download | emacs-a5fec62b519ae8c0a6528366ac8b71cd0c7ac52e.tar.gz emacs-a5fec62b519ae8c0a6528366ac8b71cd0c7ac52e.zip | |
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.
| -rw-r--r-- | etc/NEWS | 6 | ||||
| -rw-r--r-- | lisp/mwheel.el | 1 | ||||
| -rw-r--r-- | lisp/subr.el | 5 | ||||
| -rw-r--r-- | lisp/term/ns-win.el | 19 | ||||
| -rw-r--r-- | src/keyboard.c | 5 | ||||
| -rw-r--r-- | src/nsterm.m | 158 | ||||
| -rw-r--r-- | src/termhooks.h | 4 |
7 files changed, 184 insertions, 14 deletions
| @@ -1882,6 +1882,12 @@ of frame decorations on macOS 10.9+. | |||
| 1882 | --- | 1882 | --- |
| 1883 | ** 'process-attributes' on Darwin systems now returns more information. | 1883 | ** 'process-attributes' on Darwin systems now returns more information. |
| 1884 | 1884 | ||
| 1885 | --- | ||
| 1886 | ** Mousewheel and trackpad scrolling on macOS 10.7+ now behaves more | ||
| 1887 | like the macOS default. The new variables | ||
| 1888 | 'ns-use-system-mwheel-acceleration', 'ns-touchpad-scroll-line-height' | ||
| 1889 | and 'ns-touchpad-use-momentum' can be used to customise the behavior. | ||
| 1890 | |||
| 1885 | 1891 | ||
| 1886 | ---------------------------------------------------------------------- | 1892 | ---------------------------------------------------------------------- |
| 1887 | This file is part of GNU Emacs. | 1893 | This file is part of GNU Emacs. |
diff --git a/lisp/mwheel.el b/lisp/mwheel.el index 2956ba55162..0c0dcb3beb1 100644 --- a/lisp/mwheel.el +++ b/lisp/mwheel.el | |||
| @@ -232,6 +232,7 @@ non-Windows systems." | |||
| 232 | ;; When the double-mouse-N comes in, a mouse-N has been executed already, | 232 | ;; When the double-mouse-N comes in, a mouse-N has been executed already, |
| 233 | ;; So by adding things up we get a squaring up (1, 3, 6, 10, 15, ...). | 233 | ;; So by adding things up we get a squaring up (1, 3, 6, 10, 15, ...). |
| 234 | (setq amt (* amt (event-click-count event)))) | 234 | (setq amt (* amt (event-click-count event)))) |
| 235 | (when (numberp amt) (setq amt (* amt (event-line-count event)))) | ||
| 235 | (unwind-protect | 236 | (unwind-protect |
| 236 | (let ((button (mwheel-event-button event))) | 237 | (let ((button (mwheel-event-button event))) |
| 237 | (cond ((eq button mouse-wheel-down-event) | 238 | (cond ((eq button mouse-wheel-down-event) |
diff --git a/lisp/subr.el b/lisp/subr.el index 96b1ac19b4b..cf15ec287ff 100644 --- a/lisp/subr.el +++ b/lisp/subr.el | |||
| @@ -1270,6 +1270,11 @@ See `event-start' for a description of the value returned." | |||
| 1270 | "Return the multi-click count of EVENT, a click or drag event. | 1270 | "Return the multi-click count of EVENT, a click or drag event. |
| 1271 | The return value is a positive integer." | 1271 | The return value is a positive integer." |
| 1272 | (if (and (consp event) (integerp (nth 2 event))) (nth 2 event) 1)) | 1272 | (if (and (consp event) (integerp (nth 2 event))) (nth 2 event) 1)) |
| 1273 | |||
| 1274 | (defsubst event-line-count (event) | ||
| 1275 | "Return the line count of EVENT, a mousewheel event. | ||
| 1276 | The return value is a positive integer." | ||
| 1277 | (if (and (consp event) (integerp (nth 3 event))) (nth 3 event) 1)) | ||
| 1273 | 1278 | ||
| 1274 | ;;;; Extracting fields of the positions in an event. | 1279 | ;;;; Extracting fields of the positions in an event. |
| 1275 | 1280 | ||
diff --git a/lisp/term/ns-win.el b/lisp/term/ns-win.el index 68b659bf751..bc211ea9589 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.") | |||
| 736 | (global-unset-key [horizontal-scroll-bar drag-mouse-1]) | 736 | (global-unset-key [horizontal-scroll-bar drag-mouse-1]) |
| 737 | 737 | ||
| 738 | 738 | ||
| 739 | ;;;; macOS-like defaults for trackpad and mouse wheel scrolling on | ||
| 740 | ;;;; macOS 10.7+. | ||
| 741 | |||
| 742 | ;; FIXME: This doesn't look right. Is there a better way to do this | ||
| 743 | ;; that keeps customize happy? | ||
| 744 | (let ((appkit-version (progn | ||
| 745 | (string-match "^appkit-\\([^\s-]*\\)" ns-version-string) | ||
| 746 | (string-to-number (match-string 1 ns-version-string))))) | ||
| 747 | ;; Appkit 1138 ~= macOS 10.7. | ||
| 748 | (when (and (featurep 'cocoa) (>= appkit-version 1138)) | ||
| 749 | (setq mouse-wheel-scroll-amount '(1 ((shift) . 5) ((control)))) | ||
| 750 | (put 'mouse-wheel-scroll-amount 'customized-value | ||
| 751 | (list (custom-quote (symbol-value 'mouse-wheel-scroll-amount)))) | ||
| 752 | |||
| 753 | (setq mouse-wheel-progressive-speed nil) | ||
| 754 | (put 'mouse-wheel-progressive-speed 'customized-value | ||
| 755 | (list (custom-quote (symbol-value 'mouse-wheel-progressive-speed)))))) | ||
| 756 | |||
| 757 | |||
| 739 | ;;;; Color support. | 758 | ;;;; Color support. |
| 740 | 759 | ||
| 741 | ;; Functions for color panel + drag | 760 | ;; Functions for color panel + drag |
diff --git a/src/keyboard.c b/src/keyboard.c index 4db50be855c..e8701b88708 100644 --- a/src/keyboard.c +++ b/src/keyboard.c | |||
| @@ -5925,7 +5925,10 @@ make_lispy_event (struct input_event *event) | |||
| 5925 | ASIZE (wheel_syms)); | 5925 | ASIZE (wheel_syms)); |
| 5926 | } | 5926 | } |
| 5927 | 5927 | ||
| 5928 | if (event->modifiers & (double_modifier | triple_modifier)) | 5928 | if (NUMBERP (event->arg)) |
| 5929 | return list4 (head, position, make_number (double_click_count), | ||
| 5930 | event->arg); | ||
| 5931 | else if (event->modifiers & (double_modifier | triple_modifier)) | ||
| 5929 | return list3 (head, position, make_number (double_click_count)); | 5932 | return list3 (head, position, make_number (double_click_count)); |
| 5930 | else | 5933 | else |
| 5931 | return list2 (head, position); | 5934 | return list2 (head, position); |
diff --git a/src/nsterm.m b/src/nsterm.m index 27515335332..776635980e1 100644 --- a/src/nsterm.m +++ b/src/nsterm.m | |||
| @@ -6498,24 +6498,139 @@ not_in_argv (NSString *arg) | |||
| 6498 | 6498 | ||
| 6499 | if ([theEvent type] == NSEventTypeScrollWheel) | 6499 | if ([theEvent type] == NSEventTypeScrollWheel) |
| 6500 | { | 6500 | { |
| 6501 | CGFloat delta = [theEvent deltaY]; | 6501 | #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 |
| 6502 | /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */ | 6502 | #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 |
| 6503 | if (delta == 0) | 6503 | if ([theEvent respondsToSelector:@selector(hasPreciseScrollingDeltas)]) |
| 6504 | { | 6504 | { |
| 6505 | delta = [theEvent deltaX]; | 6505 | #endif |
| 6506 | if (delta == 0) | 6506 | /* If the input device is a touchpad or similar, use precise |
| 6507 | * scrolling deltas. These are measured in pixels, so we | ||
| 6508 | * have to add them up until they exceed one line height, | ||
| 6509 | * then we can send a scroll wheel event. | ||
| 6510 | * | ||
| 6511 | * If the device only has coarse scrolling deltas, like a | ||
| 6512 | * real mousewheel, the deltas represent a ratio of whole | ||
| 6513 | * lines, so round up the number of lines. This means we | ||
| 6514 | * always send one scroll event per click, but can still | ||
| 6515 | * scroll more than one line if the OS tells us to. | ||
| 6516 | */ | ||
| 6517 | bool horizontal; | ||
| 6518 | int lines = 0; | ||
| 6519 | int scrollUp = NO; | ||
| 6520 | |||
| 6521 | /* FIXME: At the top or bottom of the buffer we should | ||
| 6522 | * ignore momentum-phase events. */ | ||
| 6523 | if (! ns_touchpad_use_momentum | ||
| 6524 | && [theEvent momentumPhase] != NSEventPhaseNone) | ||
| 6525 | return; | ||
| 6526 | |||
| 6527 | if ([theEvent hasPreciseScrollingDeltas]) | ||
| 6507 | { | 6528 | { |
| 6508 | NSTRACE_MSG ("deltaIsZero"); | 6529 | static int totalDeltaX, totalDeltaY; |
| 6509 | return; | 6530 | int lineHeight; |
| 6531 | |||
| 6532 | if (NUMBERP (ns_touchpad_scroll_line_height)) | ||
| 6533 | lineHeight = XINT (ns_touchpad_scroll_line_height); | ||
| 6534 | else | ||
| 6535 | { | ||
| 6536 | /* FIXME: Use actual line height instead of the default. */ | ||
| 6537 | lineHeight = default_line_pixel_height | ||
| 6538 | (XWINDOW (FRAME_SELECTED_WINDOW (emacsframe))); | ||
| 6539 | } | ||
| 6540 | |||
| 6541 | if ([theEvent phase] == NSEventPhaseBegan) | ||
| 6542 | { | ||
| 6543 | totalDeltaX = 0; | ||
| 6544 | totalDeltaY = 0; | ||
| 6545 | } | ||
| 6546 | |||
| 6547 | totalDeltaX += [theEvent scrollingDeltaX]; | ||
| 6548 | totalDeltaY += [theEvent scrollingDeltaY]; | ||
| 6549 | |||
| 6550 | /* Calculate the number of lines, if any, to scroll, and | ||
| 6551 | * reset the total delta for the direction we're NOT | ||
| 6552 | * scrolling so that small movements don't add up. */ | ||
| 6553 | if (abs (totalDeltaX) > abs (totalDeltaY) | ||
| 6554 | && abs (totalDeltaX) > lineHeight) | ||
| 6555 | { | ||
| 6556 | horizontal = YES; | ||
| 6557 | scrollUp = totalDeltaX > 0; | ||
| 6558 | |||
| 6559 | lines = abs (totalDeltaX / lineHeight); | ||
| 6560 | totalDeltaX = totalDeltaX % lineHeight; | ||
| 6561 | totalDeltaY = 0; | ||
| 6562 | } | ||
| 6563 | else if (abs (totalDeltaY) >= abs (totalDeltaX) | ||
| 6564 | && abs (totalDeltaY) > lineHeight) | ||
| 6565 | { | ||
| 6566 | horizontal = NO; | ||
| 6567 | scrollUp = totalDeltaY > 0; | ||
| 6568 | |||
| 6569 | lines = abs (totalDeltaY / lineHeight); | ||
| 6570 | totalDeltaY = totalDeltaY % lineHeight; | ||
| 6571 | totalDeltaX = 0; | ||
| 6572 | } | ||
| 6573 | |||
| 6574 | if (lines > 1 && ! ns_use_system_mwheel_acceleration) | ||
| 6575 | lines = 1; | ||
| 6510 | } | 6576 | } |
| 6511 | emacs_event->kind = HORIZ_WHEEL_EVENT; | 6577 | else |
| 6578 | { | ||
| 6579 | CGFloat delta; | ||
| 6580 | |||
| 6581 | if ([theEvent scrollingDeltaY] == 0) | ||
| 6582 | { | ||
| 6583 | horizontal = YES; | ||
| 6584 | delta = [theEvent scrollingDeltaX]; | ||
| 6585 | } | ||
| 6586 | else | ||
| 6587 | { | ||
| 6588 | horizontal = NO; | ||
| 6589 | delta = [theEvent scrollingDeltaY]; | ||
| 6590 | } | ||
| 6591 | |||
| 6592 | lines = (ns_use_system_mwheel_acceleration) | ||
| 6593 | ? ceil (fabs (delta)) : 1; | ||
| 6594 | |||
| 6595 | scrollUp = delta > 0; | ||
| 6596 | } | ||
| 6597 | |||
| 6598 | if (lines == 0) | ||
| 6599 | return; | ||
| 6600 | |||
| 6601 | emacs_event->kind = horizontal ? HORIZ_WHEEL_EVENT : WHEEL_EVENT; | ||
| 6602 | emacs_event->arg = (make_number (lines)); | ||
| 6603 | |||
| 6604 | emacs_event->code = 0; | ||
| 6605 | emacs_event->modifiers = EV_MODIFIERS (theEvent) | | ||
| 6606 | (scrollUp ? up_modifier : down_modifier); | ||
| 6607 | #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 | ||
| 6512 | } | 6608 | } |
| 6513 | else | 6609 | else |
| 6514 | emacs_event->kind = WHEEL_EVENT; | 6610 | #endif |
| 6611 | #endif /* defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */ | ||
| 6612 | #if defined (NS_IMPL_GNUSTEP) || MAC_OS_X_VERSION_MIN_REQUIRED < 1070 | ||
| 6613 | { | ||
| 6614 | CGFloat delta = [theEvent deltaY]; | ||
| 6615 | /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */ | ||
| 6616 | if (delta == 0) | ||
| 6617 | { | ||
| 6618 | delta = [theEvent deltaX]; | ||
| 6619 | if (delta == 0) | ||
| 6620 | { | ||
| 6621 | NSTRACE_MSG ("deltaIsZero"); | ||
| 6622 | return; | ||
| 6623 | } | ||
| 6624 | emacs_event->kind = HORIZ_WHEEL_EVENT; | ||
| 6625 | } | ||
| 6626 | else | ||
| 6627 | emacs_event->kind = WHEEL_EVENT; | ||
| 6515 | 6628 | ||
| 6516 | emacs_event->code = 0; | 6629 | emacs_event->code = 0; |
| 6517 | emacs_event->modifiers = EV_MODIFIERS (theEvent) | | 6630 | emacs_event->modifiers = EV_MODIFIERS (theEvent) | |
| 6518 | ((delta > 0) ? up_modifier : down_modifier); | 6631 | ((delta > 0) ? up_modifier : down_modifier); |
| 6632 | } | ||
| 6633 | #endif | ||
| 6519 | } | 6634 | } |
| 6520 | else | 6635 | else |
| 6521 | { | 6636 | { |
| @@ -6524,9 +6639,11 @@ not_in_argv (NSString *arg) | |||
| 6524 | emacs_event->modifiers = EV_MODIFIERS (theEvent) | 6639 | emacs_event->modifiers = EV_MODIFIERS (theEvent) |
| 6525 | | EV_UDMODIFIERS (theEvent); | 6640 | | EV_UDMODIFIERS (theEvent); |
| 6526 | } | 6641 | } |
| 6642 | |||
| 6527 | XSETINT (emacs_event->x, lrint (p.x)); | 6643 | XSETINT (emacs_event->x, lrint (p.x)); |
| 6528 | XSETINT (emacs_event->y, lrint (p.y)); | 6644 | XSETINT (emacs_event->y, lrint (p.y)); |
| 6529 | EV_TRAILER (theEvent); | 6645 | EV_TRAILER (theEvent); |
| 6646 | return; | ||
| 6530 | } | 6647 | } |
| 6531 | 6648 | ||
| 6532 | 6649 | ||
| @@ -9166,6 +9283,23 @@ Note that this does not apply to images. | |||
| 9166 | This variable is ignored on Mac OS X < 10.7 and GNUstep. */); | 9283 | This variable is ignored on Mac OS X < 10.7 and GNUstep. */); |
| 9167 | ns_use_srgb_colorspace = YES; | 9284 | ns_use_srgb_colorspace = YES; |
| 9168 | 9285 | ||
| 9286 | DEFVAR_BOOL ("ns-use-system-mwheel-acceleration", | ||
| 9287 | ns_use_system_mwheel_acceleration, | ||
| 9288 | doc: /*Non-nil means use macOS's standard mouse wheel acceleration. | ||
| 9289 | This variable is ignored on macOS < 10.7 and GNUstep. Default is t. */); | ||
| 9290 | ns_use_system_mwheel_acceleration = YES; | ||
| 9291 | |||
| 9292 | DEFVAR_LISP ("ns-touchpad-scroll-line-height", ns_touchpad_scroll_line_height, | ||
| 9293 | doc: /*The number of pixels touchpad scrolling considers a line. | ||
| 9294 | Nil or a non-number means use the default frame line height. | ||
| 9295 | This variable is ignored on macOS < 10.7 and GNUstep. Default is nil. */); | ||
| 9296 | ns_touchpad_scroll_line_height = Qnil; | ||
| 9297 | |||
| 9298 | DEFVAR_BOOL ("ns-touchpad-use-momentum", ns_touchpad_use_momentum, | ||
| 9299 | doc: /*Non-nil means touchpad scrolling uses momentum. | ||
| 9300 | This variable is ignored on macOS < 10.7 and GNUstep. Default is t. */); | ||
| 9301 | ns_touchpad_use_momentum = YES; | ||
| 9302 | |||
| 9169 | /* TODO: move to common code */ | 9303 | /* TODO: move to common code */ |
| 9170 | DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars, | 9304 | DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars, |
| 9171 | doc: /* Which toolkit scroll bars Emacs uses, if any. | 9305 | doc: /* Which toolkit scroll bars Emacs uses, if any. |
diff --git a/src/termhooks.h b/src/termhooks.h index 97c128ba4e2..b5171bf1229 100644 --- a/src/termhooks.h +++ b/src/termhooks.h | |||
| @@ -116,7 +116,9 @@ enum event_kind | |||
| 116 | .frame_or_window gives the frame | 116 | .frame_or_window gives the frame |
| 117 | the wheel event occurred in. | 117 | the wheel event occurred in. |
| 118 | .timestamp gives a timestamp (in | 118 | .timestamp gives a timestamp (in |
| 119 | milliseconds) for the event. */ | 119 | milliseconds) for the event. |
| 120 | .arg may contain the number of | ||
| 121 | lines to scroll. */ | ||
| 120 | HORIZ_WHEEL_EVENT, /* A wheel event generated by a second | 122 | HORIZ_WHEEL_EVENT, /* A wheel event generated by a second |
| 121 | horizontal wheel that is present on some | 123 | horizontal wheel that is present on some |
| 122 | mice. See WHEEL_EVENT. */ | 124 | mice. See WHEEL_EVENT. */ |