Open SamadiPour opened 9 months ago
Under "System Settings->Keyboard" moving "Delay until repeat" all the way to the right effectively the highest setting 6/6 "Short" the issue appears. However at 5/6, the issue goes away.
@lwouis I think this is why you can't recreate the issue, and why only a small portion of people are facing the issue.
I could be totally wrong here.
Occurs:
Doesn't Occur:
Under "System Settings->Keyboard" moving "Delay until repeat" all the way to the right effectively the highest setting 6/6 "Short" the issue appears. However at 5/6, the issue goes away.
@lwouis I think this is why you can't recreate the issue, and why only a small portion of people are facing the issue.
I could be totally wrong here.
Occurs:
Doesn't Occur:
I can still reproduce it even with 5/6 or 0/6
I am still facing the same issue, and I believe it comes down to the mouse cursor being on the Alt-Tab ui. I am able to reproduce the bug and I will include the screen recordings and karabiner's eventviewer keypresses for the recording when the mouse cursor is on the alt-tab ui.
Environment: macOS Sonoma Version 14.6.1 Alt-Tab Version 6.70.1
Recording with mouse cursor on alt-tab ui
https://github.com/user-attachments/assets/f6cdcbd3-7419-46af-935e-038233864aaa
Karabiner's eventviewer: You can see that after command tab is pressed, a left/right arrow key is immediately pressed even though I did not press them, and only press command + tab [ { "type": "down", "name": {"key_code":"t"}, "usagePage": "7 (0x0007)", "usage": "23 (0x0017)", "misc": "" }, { "type": "up", "name": {"key_code":"t"}, "usagePage": "7 (0x0007)", "usage": "23 (0x0017)", "misc": "" }, { "type": "down", "name": {"key_code":"t"}, "usagePage": "7 (0x0007)", "usage": "23 (0x0017)", "misc": "" }, { "type": "up", "name": {"key_code":"t"}, "usagePage": "7 (0x0007)", "usage": "23 (0x0017)", "misc": "" }, { "type": "down", "name": {"key_code":"a"}, "usagePage": "7 (0x0007)", "usage": "4 (0x0004)", "misc": "" }, { "type": "up", "name": {"key_code":"a"}, "usagePage": "7 (0x0007)", "usage": "4 (0x0004)", "misc": "" }, { "type": "down", "name": {"key_code":"b"}, "usagePage": "7 (0x0007)", "usage": "5 (0x0005)", "misc": "" }, { "type": "up", "name": {"key_code":"b"}, "usagePage": "7 (0x0007)", "usage": "5 (0x0005)", "misc": "" }, { "type": "down", "name": {"key_code":"left_shift"}, "usagePage": "7 (0x0007)", "usage": "225 (0x00e1)", "misc": "flags left_shift" }, { "type": "down", "name": {"key_code":"hyphen"}, "usagePage": "7 (0x0007)", "usage": "45 (0x002d)", "misc": "flags left_shift" }, { "type": "up", "name": {"key_code":"hyphen"}, "usagePage": "7 (0x0007)", "usage": "45 (0x002d)", "misc": "flags left_shift" }, { "type": "up", "name": {"key_code":"left_shift"}, "usagePage": "7 (0x0007)", "usage": "225 (0x00e1)", "misc": "" }, { "type": "down", "name": {"key_code":"u"}, "usagePage": "7 (0x0007)", "usage": "24 (0x0018)", "misc": "" }, { "type": "up", "name": {"key_code":"u"}, "usagePage": "7 (0x0007)", "usage": "24 (0x0018)", "misc": "" }, { "type": "down", "name": {"key_code":"i"}, "usagePage": "7 (0x0007)", "usage": "12 (0x000c)", "misc": "" }, { "type": "up", "name": {"key_code":"i"}, "usagePage": "7 (0x0007)", "usage": "12 (0x000c)", "misc": "" }, { "type": "down", "name": {"key_code":"left_command"}, "usagePage": "7 (0x0007)", "usage": "227 (0x00e3)", "misc": "flags left_command" }, { "type": "down", "name": {"key_code":"tab"}, "usagePage": "7 (0x0007)", "usage": "43 (0x002b)", "misc": "flags left_command" }, { "type": "up", "name": {"key_code":"tab"}, "usagePage": "7 (0x0007)", "usage": "43 (0x002b)", "misc": "flags left_command" }, { "type": "down", "name": {"key_code":"left_arrow"}, "usagePage": "7 (0x0007)", "usage": "80 (0x0050)", "misc": "flags left_command" }, { "type": "up", "name": {"key_code":"left_arrow"}, "usagePage": "7 (0x0007)", "usage": "80 (0x0050)", "misc": "flags left_command" }, { "type": "down", "name": {"key_code":"up_arrow"}, "usagePage": "7 (0x0007)", "usage": "82 (0x0052)", "misc": "flags left_command" }, { "type": "up", "name": {"key_code":"up_arrow"}, "usagePage": "7 (0x0007)", "usage": "82 (0x0052)", "misc": "flags left_command" }, { "type": "down", "name": {"key_code":"right_arrow"}, "usagePage": "7 (0x0007)", "usage": "79 (0x004f)", "misc": "flags left_command" }, { "type": "up", "name": {"key_code":"right_arrow"}, "usagePage": "7 (0x0007)", "usage": "79 (0x004f)", "misc": "flags left_command" }, { "type": "down", "name": {"key_code":"right_arrow"}, "usagePage": "7 (0x0007)", "usage": "79 (0x004f)", "misc": "flags left_command" }, { "type": "up", "name": {"key_code":"right_arrow"}, "usagePage": "7 (0x0007)", "usage": "79 (0x004f)", "misc": "flags left_command" }, { "type": "down", "name": {"key_code":"right_arrow"}, "usagePage": "7 (0x0007)", "usage": "79 (0x004f)", "misc": "flags left_command" }, { "type": "up", "name": {"key_code":"right_arrow"}, "usagePage": "7 (0x0007)", "usage": "79 (0x004f)", "misc": "flags left_command" }, { "type": "down", "name": {"key_code":"right_arrow"}, "usagePage": "7 (0x0007)", "usage": "79 (0x004f)", "misc": "flags left_command" }, { "type": "up", "name": {"key_code":"right_arrow"}, "usagePage": "7 (0x0007)", "usage": "79 (0x004f)", "misc": "flags left_command" }, { "type": "up", "name": {"key_code":"left_command"}, "usagePage": "7 (0x0007)", "usage": "227 (0x00e3)", "misc": "" } ]
I changed my keyboard settings to one of the solutions about reducing the "delay until repeat". However, what I found was that this only delays the jumping of windows. If you were to select your windows fast enough, i think it will seem like the bug is not occuring.
I understand this is suboptimal, but the easiest option at this point is to add a configuration option to disable the code related to key repetition, as @lwouis did in this comment. It solved the issue for everyone who tried the build.
My working theory is that on some installations, when the mouse lies over where the ui appears, the tab key release isn't properly delivered to the widget due to focusing the wrong widget, the alt tab interface appearing after the tab key is released, or the event not being delivered to the widget. I'd have to log the events received by the app's keystroke handling code to know what's going on.
I understand this is suboptimal, but the easiest option at this point is to add a configuration option to disable the code related to key repetition, as @lwouis did in this comment. It solved the issue for everyone who tried the build.
The only problem with this build is that you can’t skip to the first window if you’re already on the last one.
I had this same issue, restarted alttab and now it works as expected, weird..
I had this same issue, restarted alttab and now it works as expected, weird..
I tried this. Works for a few days and then the same issue returned
I had this same issue, restarted alttab and now it works as expected, weird..
I tried this. Works for a few days and then the same issue returned
Still working for me, no restart. Seems it somehow gets into a bad state sometimes
The bug is very intermittent for me but I got a related (not quite identical) occurrence on my self-built binary with logging:
@discardableResult
fileprivate func handleEvent(_ id: EventHotKeyID?, _ shortcutState: ShortcutState?, _ keyCode: UInt32?, _ modifiers: UInt32?, _ isARepeat: Bool) -> Bool {
debugPrint("handleEvent", id ?? "nil", shortcutState ?? "nil", keyCode ?? "nil", modifiers ?? "nil", isARepeat);
This printed:
"handleEvent" "nil" "nil" "nil" 256 false
"handleEvent" "nil" "nil" "nil" 0 false
"handleEvent" __C.EventHotKeyID(signature: 1634497652, id: 0) AltTab.ShortcutState.down "nil" "nil" false
"handleEvent" __C.EventHotKeyID(signature: 1634497652, id: 0) AltTab.ShortcutState.up "nil" "nil" false
This implies that the app saw the Cmd keypress released before the Tab keypress was registered, yet it still brought up the AltTab UI. It never closed because the Cmd keypress never got released after the UI opened. (In this case I didn't get an endless Tab key repeat alongside the stuck-open Cmd keypress. I want to take a log of that too when it happens.)
For context, handleEvent
is called from three sites (according to Xcode):
CGEvent.tapCreate(... callback=cgEventFlagsChangedHandler)
(modifiers pressed/released)addGlobalHandlerIfNeeded { InstallEventHandler(callback=closure)
(keys pressed/released)
EventTypeSpec(eventClass: OSType(kEventClassKeyboard), eventKind: OSType(kEventHotKeyPressed))
or OSType(kEventHotKeyReleased)
addLocalMonitorForKeyDownAndKeyUp() { NSEvent.addLocalMonitorForEvents(callback=closure)
(irrelevant, only used by settings panel)To me this is a clear race condition in event handling. (Unfortunately, like many race conditions I'm unable to reproduce it easily.)
cgEventFlagsChangedHandler(cmd released)
fails to update a flag which controls whether InstallEventHandler(closure)
should open the AltTab menu or not.handleEvent
, yet handleEvent
is not called on every keystroke. At this point my guess is a race condition or logic error where if the app lags or the input queue fills up, InstallEventHandler
sends a Cmd+Tab hotkey event to the app, but this (asynchronously?) enters the app's input queue after the Cmd key release gets delivered and processed by the app.
How should we address the bug?
cgEventFlagsChangedHandler
call.(Sidenote: apparently InstallEventHandler
belongs to CarbonEventsCore? I didn't know modern macOS still had Carbon libraries present and supported... Should we port the program off it or not?)
I still don't know the cause of the other bug behavior where positioning the mouse where the AltTab popup would spawn, would make it not close. I have not replicated that issue with logging yet.
Got a different issue where the Alt+Tab menu didn't close for like 2 seconds after releasing Cmd.
"handleEvent" "nil" "nil" "nil" 0 false
"handleEvent" "nil" "nil" "nil" 256 false
"handleEvent" "nil" "nil" "nil" 0 false
"handleEvent" "nil" "nil" "nil" 256 false
"handleEvent" "nil" "nil" "nil" 0 false
"handleEvent" "nil" "nil" "nil" 512 false
"handleEvent" "nil" "nil" "nil" 0 false
"handleEvent" "nil" "nil" "nil" 256 false
"handleEvent" "nil" "nil" "nil" 0 false
"handleEvent" "nil" "nil" "nil" 256 false
"handleEvent" __C.EventHotKeyID(signature: 1634497652, id: 0) AltTab.ShortcutState.down "nil" "nil" false
"handleEvent" "nil" "nil" 33 256 false
"handleEvent" __C.EventHotKeyID(signature: 1634497652, id: 0) AltTab.ShortcutState.up "nil" "nil" false
"handleEvent" "nil" "nil" "nil" 0 false
"handleEvent" "nil" "nil" "nil" 256 false
NSEvent.addLocalMonitorForEvents
is not actually only used in the settings menu, but to handle keystrokes while the popup is open.[
key. I confirmed this produced code 33 in the logs, but when I tried pressing the key during an Alt-Tab operation, I heard a warning beep and the menu did not remain open. I don't know why my observed behavior happened.I have found a way to make this bug go away, and it probably explains why "trying $random version" also helps a lot of people — changing versions should always fix it:
going to System Settings -> Privacy & Accessibility, removing AltTab, and then re-adding it back fixes the skipping for me.
This also worked for me.
System settings -> Privacy & Accessibility -> Accessibility -> Switch AltTab off and back on.
This also worked for me.
System settings -> Privacy & Accessibility -> Accessibility -> Switch AltTab off and back on.
Same, perhaps the original issue should be updated with the workarounds. Would save folks some time.
I've found a semi-reliable way to reproduce a version of this issue:
InstallEventHandler(#callback)
to lag.At this point you'll get event logs like:
"handleEvent" "nil" "nil" "nil" 256 false
"handleEvent" __C.EventHotKeyID(signature: 1634497652, id: 0) AltTab.ShortcutState.down "nil" "nil" false
"handleEvent" "nil" "nil" "nil" 0 false
"handleEvent" "nil" "nil" "nil" 256 false
"handleEvent" __C.EventHotKeyID(signature: 1634497652, id: 0) AltTab.ShortcutState.up "nil" "nil" false
"handleEvent" "nil" "nil" "nil" 0 false
"handleEvent" __C.EventHotKeyID(signature: 1634497652, id: 0) AltTab.ShortcutState.down "nil" "nil" false
"handleEvent" __C.EventHotKeyID(signature: 1634497652, id: 0) AltTab.ShortcutState.up "nil" "nil" false
This indicates:
Because the popup is opened (Cmd-Tab) after the event to close the menu (!Cmd) is received, the menu never closes.
I think the initial bug report (where "alt-tab" appears held for a second or so) is a variant where when the mouse sits above the popup while it opens, the Tab release event is delayed, and the app sees it as Alt-Tab being held for a second even if the user quickly released it. I don't know what causes "mouse sitting over Alt-Tab" to trigger shortcut processing delays on some machines sometimes, but removing AltTab from accessibility options temporarily fixes it
It's possible that (in my reproducer) the lag happens because of my logging code sending data into the XCode output log; the bug becomes harder to reproduce (I have to Alt-Tab much faster to trigger the ordering error) after clearing the log. Nonetheless the core event ordering bug is an underlying Apple footgun/bug (I don't know if they promise in-order event delivery), and the effects are consistent with behaviors I and others in this thread have observed. In particular, cycling a few windows is only explainable by AltTab.ShortcutState.up
being delayed, and "menu remains open" can be explained by the same mechanism.
Hi everyone,
Could you please test this local build?
I made the shortcut handling code more loose. It may help be more robust and close even when events arrive in the wrong order from the OS. I hope it doesn't cause regressions, so please share if you see any weird behavior.
Thank you everyone to help test this one out 🙇
Thank you @nyanpasu64 for your great analysis. Thank you for helping see this issue resolved. It's a tough one as it seems to happen only for some people and in some cases. It's probably the OS being busy in specific ways, resulting in the issue.
The build causes a new(?) problem where when I Cmd-Tab (I rebound from Alt-Tab) to an app, then press and release Cmd, it switches to the app I most recently cmd-tabbed to.
@nyanpasu64 thank you for testing it 🙇
I wasn't able to reproduce the issue you mention. Could you please share the sequence of inputs you did? For example:
I was able to reproduce with these steps. Thank you!
If I map the sequence from your logs, I see that it not in order indeed:
cmd down cmd+tab down (from a tab down) cmd up cmd down cmd+tab up [this should have happened one row before since cmd up happened] cmd up cmd+tab down (cmd down) cmd+tab up (tab up)
What AltTab does for keyboard input is listen to 3 different API callbacks:
CGEvent.tapCreate
for modifiers changes (e.g. cmd up, cmd down, etc)NSEvent.addLocalMonitorForEvents
for local key presses (local = when AltTab is the activate app) (e.g. pressing escape to close the switcher)InstallEventHandler
for global shortcuts (e.g. cmd+tab down, cmd+tab up)It never occured to me before that these 3 sources could come send events in a different order than the one that happened on the actual keyboard.
Now that I think about it, it's totally possible. These callbacks may be coming from different macOS subsystems, or uses different event queues, or receive different loads at different time.
You may think that we have a complex implementation. Why not use one source of events? That's because we support quite complex use-cases:
To support that, we have the current complex setup with 3 distinct sources of events.
I'm not sure if there is a way for us to support out-of-order events. If anyone wants to help, here's where event handling happens.
Thank you
The worst thing is that the original bug report (alt-tab acts held) seems more like a delayed tab release (hotkey), than an event reordering (which can result from delays). So there's nothing you can do in your app to detect and compensate for that issue. At this point I want to debug the actual library code that sends hotkeys to the app (eg. breakpointing AltTab and looking at parent stack frames), but I'm not planning on that yet.
Perhaps I'm misunderstanding, but would it not be possible to just listen for modifier events from CGEvent.tapCreate
as opposed to also listening for global shortcuts from InstallEventHandler
? I believe that way you wouldn't have to worry about events being delivered out of order from different APIs.
i.e. you would check cmdDown && tabDown
for cmd+tab down and cmdUp || tabUp
for cmd+tab up
in which case the flow would look something like this:
cmd down
tab down --- equivalent to cmd+tab down from InstallEventHandler
tab up --- equivalent to cmd+tab up from InstallEventHandler
cmd up
would it not be possible to just listen for modifier events from CGEvent.tapCreate as opposed to also listening for global shortcuts from InstallEventHandler?
InstallEventHandler
is used because it's the only API working during Secure Input. More info here. It's a jungle, but as a result of our complex implementation, AltTab shortcut system is extremely powerful. More than any other mac app I've seen. I've looked at how other big apps (e.g. Contexts, Witch, Alfred, Spectacles, etc) are doing it, and we support the most flexible shortcuts, and work in the most cases. That's my understanding at least.
Hi,
Could you please test this local build?
It may just be robust enough to handle some out-of-order cases. It doesn't have the issue of the previous local build.
Could you guys please try it out of a while and see if it fixes the issue for you?
Thank you 🙇
/cc @unodgs @dottedmag @jordantrizz @AlexeyKupershtokh @warrenseine @ankushagarwal @nyanpasu64 @maximvl @problame @EskelCz @AlabasterAxe @evanhammer @saitonakamura @samuelhwilliams @jebeaudet @letalumil @Joeyn1993 @RecuencoJones @xdanik
No issues so far, though the bug is intermittent so it's hard to say it's fixed.
I noticed that after pressing alt-tab, there's a few hundred ms delay before the popup appears? Probably harmless, possibly intentional, I think KDE delays the alt-tab menu appearing so quick presses won't flicker the screen, though the downside is you have to wait a bit before you can start scanning the list of window titles to look for one you want.
@nyanpasu64 AltTab does exactly what you described, to avoid flickering. You can remove that delay or adjust it in Preferences > Appearance > Animations...
👍
Describe the bug
Since a few weeks ago, I have been experiencing drifting when the mouse is hovered over an item. It only happens when the mouse is over an item, and not when it's inside or outside of the frame. When I hold down the
Command
key and pressTab
once (push and release instantly), the selector drifts through the items, sometimes until it reaches the mouse and sometimes until it reaches the end. TheMouse hover
option underAlso select windows using
is disabled.Screenshots / video
https://github.com/lwouis/alt-tab-macos/assets/24422125/44cec264-affb-4058-b880-d87e60a9a14a
Steps to reproduce the bug
Your environment