oantolin / embark

Emacs Mini-Buffer Actions Rooted in Keymaps

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Trackpad Scrolling accelerates when embark target is active

jdtsmith opened this issue · comments

This is a strange one. I find that when embark has a target selected, scrolling with the trackpad is accelerated by 10x or more. Once you cancel embark-act, scrolling returns to normal. emacs-mac v29.1, checked in emacs -Q with only embark active.

Oh, weird! That doesn't seem to happen here. This will be hard for me to figure out since I can't reproduce it. (Also, I use Embark completely from the keyboard so I never would have noticed this. 😄 )

Interesting. I just checked with an NS build and it doesn't happen there. So it's something specific about emacs-mac. Is there anything special that happens when a target is marked that may provide a simpler debug entry point for Yamamoto-san, something which could (at all) be related to scrolling?

I knew it! I almost asked if you were on a mac. I have no access to mac's, in my country those are only for rich people. 😛 (A 14 inch macbook pro costs more than a month of my salary, I've never bought a computer that costs more than a fifth of that!) I'll let you first-worlders debug this.

Oh, that's not quite true: I did buy a gaming desktop for my son that cost about 2/3 of a 14 inch macbook pro. But for myself or my wife it is true I have never bought a computer that costs more than 1/5 of a macbook.

The MB Air is much more affordable! My last MPB lasted from 2014 - 2023, so I make up for the cost with longevity ;). The entire OS has Emacs bindings everywhere which is nice.

But anyway, what does Embark do to mark targets? Just a simple overlay? Any other settings of interest? Must be some reason the (trackpad only) scrolling goes to ludicrous speed.

Yes, just an overlay. I have no idea what could possibly be affecting the scroll speed.

Yes, just an overlay. I have no idea what could possibly be affecting the scroll speed.

Maybe the way the action key press is read?

The only code related to scrolling is that the keymap-prompter treats some scroll commands specially, in the sense that it does not run them as actions, but just runs them directly:

  ((or 'scroll-bar-toolkit-scroll 'mwheel-scroll 'mac-mwheel-scroll)
       (funcall cmd last-command-event)
       (embark-keymap-prompter keymap update))

The only code related to scrolling is that the keymap-prompter treats some scroll commands specially, in the sense that it does not run them as actions, but just runs them directly:

This is likely the culprit. I guess some command coalescing is disabled that way. (EDIT: See mwheel-coalesce-scroll-events)

Maybe the way the action key press is read?

Maybe, embark uses read-key-sequence-vector.

This is likely the culprit. I guess some command coalescing is disabled that way.

I don't know what that means, but I agree it does sound likely.

I don't know what that means, but I agree it does sound likely.

I also don't know, all I know is that there is this variable mwheel-coalesce-scroll-events.

The coalescing might mean that when Emacs sees n consecutive scroll events it only generates floor(n/10) of them, which would explain the speed up. Since I can't seem to reproduce the problem, I can't fix it, but I'd welcome a PR, @jdtsmith.

OK interesting. I commented out the scrolling snippet you mentioned above from embark-keymap-prompter, and indeed that "fixes" the problem, but only by disabling the marked target... so not much of a fix. mwheel-coalesce-scroll-events has no effect.

But here's what else I found by tracing mac-forward-wheel-event (which mac-mwheel-scroll uses to forward events to mwheel-scroll): while embark is not reading its keymap vs. when it is, the nature of the events passed in changes:

Without embark-keymap-prompter in the event chain

All events look like this:

(triple-wheel-down (#<window 87 on mac-win.el.gz> 88692 (543 . 415) 24527666 nil 88692 (56 . 29) nil (39 . 9) (7 . 14)) 17 (:direction-inverted-from-device-p t :delta-x 0.0 :delta-y 0.0 :delta-z 0.0 :scrolling-delta-x 0.0 :scrolling-delta-y -1.0 :phase changed :momentum-phase none :swipe-tracking-from-scroll-events-enabled-p t)) nil)

Sometimes these are single- and double- wheel-down. Lots of these (and for the trackpad, I mean lots)! Note the additional plist at the end of the event with lots of mac-specific info. mac-mwheel-scroll explains this additional plist:

  ;; (nth 3 event) is a plist that may contain the following keys:
  ;; :direction-inverted-from-device-p		(boolean)
  ;; :delta-x, :delta-y, :delta-z		(floats)
  ;; :scrolling-delta-x, :scrolling-delta-y	(floats)
  ;; :phase, :momentum-phase			(symbols)
  ;;	possible value: `none', `began', `stationary', `changed',
  ;;			`ended', `cancelled', or `may-begin'
  ;; :swipe-tracking-from-scroll-events-enabled-p (boolean)

With embark-keymap prompter active:

Simpler, unadorned events ala:

(wheel-down (#<window 87 on mac-win.el.gz> 100990 (407 . 489) 24699614 nil 100990 (58 . 34) nil (274 . 11) (7 . 14)))

Further Details

This "event simplification" occurs with both mouse scroll and trackpad, but only for the trackpad does it lead to "ridiculous acceleration" of scrolling, likely because the trackpad sends so many more events. Perhaps emacs-mac is not correctly setting its fancy extended events into last-command-event, but just adds this plist at the last moment prior to handing to the event handler? [Update: No, see below].

By inserting message into embark-keymap-prompter, I see that the keys it reads include a final element that contains exactly one event with the fancy plist, then all the rest are "unadorned". So somehow embark is indirectly stripping this information out! Here's a log of the last item on the keys vector that prompter collects using embark--read-key-sequence during one continuous scrolling sequence. Notice how only the first event has its plist intact.

Last of PROMPTER keys: (wheel-down (#<window 61 on embark.el> 53704 (428 . 474) 26689502 nil 53704 (61 . 33) nil (78 . 12) (7 . 14)) 1 (:direction-inverted-from-device-p t :delta-x 0.0 :delta-y 0.0 :delta-z 0.0 :scrolling-delta-x 0.0 :scrolling-delta-y -1.0 :phase began :momentum-phase none :swipe-tracking-from-scroll-events-enabled-p t))
Last of PROMPTER keys: (wheel-down (#<window 61 on embark.el> 53704 (428 . 474) 26689502 nil 53704 (61 . 33) nil (78 . 12) (7 . 14)))
Last of PROMPTER keys: (wheel-down (#<window 61 on embark.el> 53704 (428 . 474) 26689518 nil 53704 (61 . 33) nil (78 . 12) (7 . 14)))
Last of PROMPTER keys: (wheel-down (#<window 61 on embark.el> 53704 (428 . 474) 26689535 nil 53704 (61 . 33) nil (78 . 12) (7 . 14)))
Last of PROMPTER keys: (wheel-down (#<window 61 on embark.el> 53704 (428 . 474) 26689552 nil 53704 (61 . 33) nil (78 . 12) (7 . 14)))
Last of PROMPTER keys: (wheel-down (#<window 61 on embark.el> 53704 (428 . 474) 26689568 nil 53704 (61 . 33) nil (78 . 12) (7 . 14)))
Last of PROMPTER keys: (wheel-down (#<window 61 on embark.el> 53704 (428 . 474) 26689592 nil 53704 (61 . 33) nil (78 . 12) (7 . 14)))
Last of PROMPTER keys: (wheel-down (#<window 61 on embark.el> 53704 (428 . 474) 26689614 nil 53704 (61 . 33) nil (78 . 12) (7 . 14)))
Last of PROMPTER keys: (wheel-down (#<window 61 on embark.el> 53704 (428 . 474) 26689637 nil 53704 (61 . 33) nil (78 . 12) (7 . 14)))
Last of PROMPTER keys: (wheel-down (#<window 61 on embark.el> 53704 (428 . 474) 26689652 nil 53704 (61 . 33) nil (78 . 12) (7 . 14)))
Last of PROMPTER keys: (wheel-down (#<window 61 on embark.el> 53704 (428 . 474) 26689668 nil 53704 (61 . 33) nil (78 . 12) (7 . 14)))
Last of PROMPTER keys: (wheel-down (#<window 61 on embark.el> 53704 (428 . 474) 26689685 nil 53704 (61 . 33) nil (78 . 12) (7 . 14)))
Last of PROMPTER keys: (wheel-down (#<window 61 on embark.el> 53704 (428 . 474) 26689702 nil 53704 (61 . 33) nil (78 . 12) (7 . 14)))
Last of PROMPTER keys: (wheel-down (#<window 61 on embark.el> 53704 (428 . 474) 26689718 nil 53704 (61 . 33) nil (78 . 12) (7 . 14)))
Last of PROMPTER keys: (wheel-down (#<window 61 on embark.el> 53704 (428 . 474) 26689735 nil 53704 (61 . 33) nil (78 . 12) (7 . 14)))
Last of PROMPTER keys: (wheel-down (#<window 61 on embark.el> 53704 (428 . 474) 26689752 nil 53704 (61 . 33) nil (78 . 12) (7 . 14)))
Last of PROMPTER keys: (wheel-down (#<window 61 on embark.el> 53704 (428 . 474) 26689769 nil 53704 (61 . 33) nil (78 . 12) (7 . 14)))
Last of PROMPTER keys: (wheel-down (#<window 61 on embark.el> 53704 (428 . 474) 26689785 nil 53704 (61 . 33) nil (78 . 12) (7 . 14)))
Last of PROMPTER keys: (wheel-down (#<window 61 on embark.el> 53704 (428 . 474) 26689802 nil 53704 (61 . 33) nil (78 . 12) (7 . 14)))
Last of PROMPTER keys: (wheel-down (#<window 61 on embark.el> 53704 (428 . 474) 26689818 nil 53704 (61 . 33) nil (78 . 12) (7 . 14)))
Last of PROMPTER keys: (wheel-down (#<window 61 on embark.el> 53704 (428 . 474) 26689835 nil 53704 (61 . 33) nil (78 . 12) (7 . 14)))
Last of PROMPTER keys: (wheel-down (#<window 61 on embark.el> 53704 (428 . 474) 26689852 nil 53704 (61 . 33) nil (78 . 12) (7 . 14)))
Last of PROMPTER keys: (wheel-down (#<window 61 on embark.el> 53704 (428 . 474) 26689868 nil 53704 (61 . 33) nil (78 . 12) (7 . 14)))
Last of PROMPTER keys: (wheel-down (#<window 61 on embark.el> 53704 (428 . 474) 26689885 nil 53704 (61 . 33) nil (78 . 12) (7 . 14)))
Last of PROMPTER keys: (wheel-down (#<window 61 on embark.el> 53704 (428 . 474) 26689902 nil 53704 (61 . 33) nil (78 . 12) (7 . 14)))
Last of PROMPTER keys: (wheel-down (#<window 61 on embark.el> 53704 (428 . 474) 26689918 nil 53704 (61 . 33) nil (78 . 12) (7 . 14)))
Last of PROMPTER keys: (wheel-down (#<window 61 on embark.el> 53704 (428 . 474) 26689935 nil 53704 (61 . 33) nil (78 . 12) (7 . 14)))
Last of PROMPTER keys: (wheel-down (#<window 61 on embark.el> 53704 (428 . 474) 26689952 nil 53704 (61 . 33) nil (78 . 12) (7 . 14)))
Last of PROMPTER keys: (wheel-down (#<window 61 on embark.el> 53704 (428 . 474) 26689968 nil 53704 (61 . 33) nil (78 . 12) (7 . 14)))
Last of PROMPTER keys: (wheel-down (#<window 61 on embark.el> 53704 (428 . 474) 26689985 nil 53704 (61 . 33) nil (78 . 12) (7 . 14)))
Last of PROMPTER keys: (wheel-down (#<window 61 on embark.el> 53704 (428 . 474) 26690002 nil 53704 (61 . 33) nil (78 . 12) (7 . 14)))

BTW, it also seems kind of crazy that embark-keymap-prompter calls itself recursively on every scroll event, leading to wild-looking nested trace trees:

image

It's done to discourage scrolling beyond the stack depth. 😛 But if it's a problem we can switch to a while loop, so far it doesn't seem to be a problem.

:).

Simple test rig to exhibit the "loss of PLIST adornment":

(while t
  (sit-for 0.2)
  (message "%S" (read-key-sequence-vector nil nil nil t 'cmd-loop)))

First event is "adorned", rest (in that direction) are "plain", so replaying them (as the embark-prompter does) leads to major acceleration. I'd grade this as "not embark's fault". I've contacted the emacs-mac maintainer.

It's done to discourage scrolling beyond the stack depth. 😛 But if it's a problem we can switch to a while loop, so far it doesn't seem to be a problem.

Stack overflow by scrolling - I have to search through the issue tracker to find where we had this discussion before. Please keep this spacebar heating feature intact. For Emacs developers working on the memory subsystem it is useful to have an easy way to trigger stack overflows.

I also use the macport and can try reproducing. Using embark-act in a markdown buffer to select an identifier and scrolling with a trackpad (I'm on an iMac if that makes a difference, not a laptop) didn't seem to make anything crazy.

@hmelman are you on an NS or Carbon port (M-x emacs-version should say Carbon).

Mitsuharu Yamamoto's port. "GNU Emacs 29.1 (build 1, x86_64-apple-darwin21.6.0, Carbon Version 165 AppKit 2113.6) of 2023-08-08"

OK thanks; same here (but aarch64). Try the "simple test" above. For me I get one event with the extra PLIST, then all subsequent events are plain. Is that what you see?

I bet the distinction is how many events your trackpad delivers. For my normal cheap mouse scrollbar, it's not too many so you don't really notice (even though the plist gets dropped). Only with new trackpad does it accelerate.

I evaluated the simple test below in *scratch*

(while t
  (sit-for 0.2)
  (message "%S" (read-key-sequence-vector nil nil nil t 'cmd-loop)))

and two-fingered swiped up an inch or so and then ^g to quit the loop and saw this in *messages*:

[(wheel-down (#<window 137 on *scratch*> 216 (264 . 512) 1059433918 nil 216 (33 . 8) nil (264 . 384) (8 . 16)) 1 (:direction-inverted-from-device-p t :delta-x 0.0 :delta-y 0.0 :delta-z 0.0 :scrolling-delta-x 0.0 :scrolling-delta-y -1.0 :phase began :momentum-phase none :swipe-tracking-from-scroll-events-enabled-p t))]
[(wheel-down (#<window 137 on *scratch*> 216 (264 . 512) 1059433933 nil 216 (33 . 8) nil (264 . 384) (8 . 16)))]
[(wheel-down (#<window 137 on *scratch*> 216 (264 . 512) 1059433949 nil 216 (33 . 8) nil (264 . 384) (8 . 16)))]
[(wheel-down (#<window 137 on *scratch*> 216 (264 . 512) 1059433966 nil 216 (33 . 8) nil (264 . 384) (8 . 16)))]
[(wheel-down (#<window 137 on *scratch*> 216 (264 . 512) 1059433983 nil 216 (33 . 8) nil (264 . 384) (8 . 16)))]
[(wheel-down (#<window 137 on *scratch*> 216 (264 . 512) 1059433999 nil 216 (33 . 8) nil (264 . 384) (8 . 16)))]
[(wheel-down (#<window 137 on *scratch*> 216 (264 . 512) 1059434016 nil 216 (33 . 8) nil (264 . 384) (8 . 16)))]
[(wheel-down (#<window 137 on *scratch*> 216 (264 . 512) 1059434033 nil 216 (33 . 8) nil (264 . 384) (8 . 16)))]
[(wheel-down (#<window 137 on *scratch*> 216 (264 . 512) 1059434049 nil 216 (33 . 8) nil (264 . 384) (8 . 16)))]
[(wheel-down (#<window 137 on *scratch*> 216 (264 . 512) 1059434066 nil 216 (33 . 8) nil (264 . 384) (8 . 16)))]
[(wheel-down (#<window 137 on *scratch*> 216 (264 . 512) 1059434083 nil 216 (33 . 8) nil (264 . 384) (8 . 16)))]
[(wheel-down (#<window 137 on *scratch*> 216 (264 . 512) 1059434099 nil 216 (33 . 8) nil (264 . 384) (8 . 16)))]
[(wheel-down (#<window 137 on *scratch*> 216 (264 . 512) 1059434116 nil 216 (33 . 8) nil (264 . 384) (8 . 16)))]
[(wheel-down (#<window 137 on *scratch*> 216 (264 . 512) 1059434133 nil 216 (33 . 8) nil (264 . 384) (8 . 16)))]
[(wheel-down (#<window 137 on *scratch*> 216 (264 . 512) 1059434149 nil 216 (33 . 8) nil (264 . 384) (8 . 16)))]
[(wheel-down (#<window 137 on *scratch*> 216 (264 . 512) 1059434166 nil 216 (33 . 8) nil (264 . 384) (8 . 16)))]
[(wheel-down (#<window 137 on *scratch*> 216 (264 . 512) 1059434183 nil 216 (33 . 8) nil (264 . 384) (8 . 16)))]
[(wheel-down (#<window 137 on *scratch*> 216 (264 . 512) 1059434199 nil 216 (33 . 8) nil (264 . 384) (8 . 16)))]
[(wheel-down (#<window 137 on *scratch*> 216 (264 . 512) 1059434216 nil 216 (33 . 8) nil (264 . 384) (8 . 16)))]
[(wheel-down (#<window 137 on *scratch*> 216 (264 . 512) 1059434233 nil 216 (33 . 8) nil (264 . 384) (8 . 16)))]
[(wheel-down (#<window 137 on *scratch*> 216 (264 . 512) 1059434249 nil 216 (33 . 8) nil (264 . 384) (8 . 16)))]
[(wheel-down (#<window 137 on *scratch*> 216 (264 . 512) 1059434266 nil 216 (33 . 8) nil (264 . 384) (8 . 16)))]
[(wheel-down (#<window 137 on *scratch*> 216 (264 . 512) 1059434283 nil 216 (33 . 8) nil (264 . 384) (8 . 16)))]
[(wheel-down (#<window 137 on *scratch*> 216 (264 . 512) 1059434299 nil 216 (33 . 8) nil (264 . 384) (8 . 16)))]
[(wheel-down (#<window 137 on *scratch*> 216 (264 . 512) 1059434316 nil 216 (33 . 8) nil (264 . 384) (8 . 16)))]
[(wheel-down (#<window 137 on *scratch*> 216 (264 . 512) 1059434333 nil 216 (33 . 8) nil (264 . 384) (8 . 16)))]
[(wheel-down (#<window 137 on *scratch*> 216 (264 . 512) 1059434349 nil 216 (33 . 8) nil (264 . 384) (8 . 16)))]
[(wheel-down (#<window 137 on *scratch*> 216 (264 . 512) 1059434366 nil 216 (33 . 8) nil (264 . 384) (8 . 16)))]
[(wheel-down (#<window 137 on *scratch*> 216 (264 . 512) 1059434383 nil 216 (33 . 8) nil (264 . 384) (8 . 16)))]
[(wheel-down (#<window 137 on *scratch*> 216 (264 . 512) 1059434399 nil 216 (33 . 8) nil (264 . 384) (8 . 16)))]
[(wheel-down (#<window 137 on *scratch*> 216 (264 . 512) 1059434416 nil 216 (33 . 8) nil (264 . 384) (8 . 16)))]
[(wheel-down (#<window 137 on *scratch*> 216 (264 . 512) 1059434433 nil 216 (33 . 8) nil (264 . 384) (8 . 16)))]
[(wheel-down (#<window 137 on *scratch*> 216 (264 . 512) 1059434449 nil 216 (33 . 8) nil (264 . 384) (8 . 16)))]
[(wheel-down (#<window 137 on *scratch*> 216 (264 . 512) 1059434466 nil 216 (33 . 8) nil (264 . 384) (8 . 16)))]
[(wheel-down (#<window 137 on *scratch*> 216 (264 . 512) 1059434483 nil 216 (33 . 8) nil (264 . 384) (8 . 16)))]
[(wheel-down (#<window 137 on *scratch*> 216 (264 . 512) 1059434499 nil 216 (33 . 8) nil (264 . 384) (8 . 16)))]
[(wheel-down (#<window 137 on *scratch*> 216 (264 . 512) 1059434516 nil 216 (33 . 8) nil (264 . 384) (8 . 16)))]
[(wheel-down (#<window 137 on *scratch*> 216 (264 . 512) 1059434533 nil 216 (33 . 8) nil (264 . 384) (8 . 16)))]
[(wheel-down (#<window 137 on *scratch*> 216 (264 . 512) 1059434550 nil 216 (33 . 8) nil (264 . 384) (8 . 16)))]
[(wheel-down (#<window 137 on *scratch*> 216 (264 . 512) 1059434558 nil 216 (33 . 8) nil (264 . 384) (8 . 16)))]
[(wheel-left (#<window 137 on *scratch*> 216 (264 . 512) 1059434592 nil 216 (33 . 8) nil (264 . 384) (8 . 16)) 1 (:direction-inverted-from-device-p t :delta-x 0.0 :delta-y 0.0 :delta-z 0.0 :phase ended :momentum-phase none :swipe-tracking-from-scroll-events-enabled-p t))]

If you want me to try something else, please be specific.

Yes, that's the same behavior I see. Notice how only the first event of a given type has the MacOS additional PLIST. All scroll events should have that; they encode "partial" scroll movements among other things. I've submitted this to Yamamoto, will update if I hear anything.