Existing issues
What happened?
An extension action whose shortcut key is an arrow never fires. The action panel renders the shortcut correctly, so it looks bound, and pressing it does nothing. Picking the same action from the panel with the mouse works, so the handler is fine.
Snake (tonka3000) is the clearest case because every direction is ⌘⇧+arrow, which makes it unplayable. It isn't one extension though: 8 of my 106 installed extensions declare an arrow shortcut (snake, color-picker, homeassistant, hue, producthunt, rss-reader, translate, cleanshotx).
Cause: ASCIIKeyboardLayout.keyEquivalent(fallingBackTo:).
Extension action shortcuts are its only caller (ExtensionPaletteModifiers.swift:12). It recovers the logical ASCII key from the current layout so ⌘K still works on Dvorak, guarded by this:
let character = character(for: event)?.lowercased().first,
character.unicodeScalars.allSatisfy(\.isASCII)
That guard is there to reject a non-ASCII layout character. But UCKeyTranslate maps the arrow keycodes to ASCII control characters, and those pass isASCII happily. So the recovery returns the control character instead of falling through to SwiftUI's key, and ExtensionAction.matches compares it against KeyEquivalent.upArrow, which is U+F700. Never equal, so the action is never found.
Measured on this Mac, translating each keycode with cmdKey the way character(for:) does:
| Raycast key |
UCKeyTranslate |
SwiftUI KeyEquivalent |
passes isASCII |
fires |
arrowUp |
U+1E |
U+F700 |
yes |
no |
arrowDown |
U+1F |
U+F701 |
yes |
no |
arrowLeft |
U+1C |
U+F702 |
yes |
no |
arrowRight |
U+1D |
U+F703 |
yes |
no |
deleteForward |
U+7F |
U+F728 |
yes |
no |
pageUp |
U+B |
U+F72C |
yes |
no |
pageDown |
U+C |
U+F72D |
yes |
no |
home |
U+1 |
U+F729 |
yes |
no |
end |
U+4 |
U+F72B |
yes |
no |
return |
U+D |
U+D |
yes |
yes |
delete |
U+8 |
U+8 |
yes |
yes |
tab |
U+9 |
U+9 |
yes |
yes |
escape |
U+1B |
U+1B |
yes |
yes |
space |
U+20 |
U+20 |
yes |
yes |
c |
U+63 |
U+63 |
yes |
yes |
So it's every key whose SwiftUI KeyEquivalent lives in the private-use area. return, delete, tab, escape and space survive by luck: the control character UCKeyTranslate hands back happens to be the one SwiftUI uses for them.
One more wrinkle worth knowing before anyone tries to reproduce it. The ASCII recovery only runs when the chord carries ⌘ or ⌃:
!event.modifierFlags.isDisjoint(with: [.command, .control])
So ⌥⇧↑ works today and ⌘⇧↑ doesn't, on the same action. That's why this reads as intermittent if you go looking at a few extensions rather than at the keycodes.
Scope. Only extension action shortcuts. keyEquivalent(fallingBackTo:) has that single call site, and ASCIIKeyboardLayout.matches(_:character:) always compares against a literal letter ("k", "p"), so the palette's own bindings can't hit this. character(for:) on its own is fine everywhere it's used.
Suggested fix. Return key untouched when it's already one of SwiftUI's named special keys, before consulting the layout at all. The recovery exists for letters and punctuation on a non-QWERTY layout, and a private-use key has no layout meaning to recover. Filtering on "printable ASCII only" would also work, but the private-use test says what's actually meant.
Nothing in Tests/ covers dispatchShortcut or ExtensionAction.matches right now, which is presumably how it went unnoticed.
Steps to reproduce
- Install Snake (
tonka3000).
- Run Play Snake.
- Press
⌘⇧↑, ⌘⇧↓, ⌘⇧← or ⌘⇧→. Nothing happens, and the snake keeps going until it dies.
- Open the action panel and click Up. It moves, so the action itself works.
Screenshots or recording
The action panel showing the four direction actions with their shortcuts rendered correctly, none of which fire:
The keycode table above is the more useful artefact. It came from calling UCKeyTranslate directly with the same arguments ASCIIKeyboardLayout.character(for:) passes, then comparing against what ExtensionAction.keyEquivalent returns for each Raycast key name.
Tinycast version + channel
0.11.3 stable
macOS version
27.0 (26A428)
Contribution
Small one: an early return in keyEquivalent(fallingBackTo:) plus a harness covering ExtensionAction.matches across that key table, since there's nothing there today.
Existing issues
What happened?
An extension action whose shortcut key is an arrow never fires. The action panel renders the shortcut correctly, so it looks bound, and pressing it does nothing. Picking the same action from the panel with the mouse works, so the handler is fine.
Snake (
tonka3000) is the clearest case because every direction is⌘⇧+arrow, which makes it unplayable. It isn't one extension though: 8 of my 106 installed extensions declare an arrow shortcut (snake,color-picker,homeassistant,hue,producthunt,rss-reader,translate,cleanshotx).Cause:
ASCIIKeyboardLayout.keyEquivalent(fallingBackTo:).Extension action shortcuts are its only caller (
ExtensionPaletteModifiers.swift:12). It recovers the logical ASCII key from the current layout so⌘Kstill works on Dvorak, guarded by this:That guard is there to reject a non-ASCII layout character. But
UCKeyTranslatemaps the arrow keycodes to ASCII control characters, and those passisASCIIhappily. So the recovery returns the control character instead of falling through to SwiftUI's key, andExtensionAction.matchescompares it againstKeyEquivalent.upArrow, which isU+F700. Never equal, so the action is never found.Measured on this Mac, translating each keycode with
cmdKeythe waycharacter(for:)does:UCKeyTranslateKeyEquivalentisASCIIarrowUpU+1EU+F700arrowDownU+1FU+F701arrowLeftU+1CU+F702arrowRightU+1DU+F703deleteForwardU+7FU+F728pageUpU+BU+F72CpageDownU+CU+F72DhomeU+1U+F729endU+4U+F72BreturnU+DU+DdeleteU+8U+8tabU+9U+9escapeU+1BU+1BspaceU+20U+20cU+63U+63So it's every key whose SwiftUI
KeyEquivalentlives in the private-use area.return,delete,tab,escapeandspacesurvive by luck: the control characterUCKeyTranslatehands back happens to be the one SwiftUI uses for them.One more wrinkle worth knowing before anyone tries to reproduce it. The ASCII recovery only runs when the chord carries ⌘ or ⌃:
So
⌥⇧↑works today and⌘⇧↑doesn't, on the same action. That's why this reads as intermittent if you go looking at a few extensions rather than at the keycodes.Scope. Only extension action shortcuts.
keyEquivalent(fallingBackTo:)has that single call site, andASCIIKeyboardLayout.matches(_:character:)always compares against a literal letter ("k","p"), so the palette's own bindings can't hit this.character(for:)on its own is fine everywhere it's used.Suggested fix. Return
keyuntouched when it's already one of SwiftUI's named special keys, before consulting the layout at all. The recovery exists for letters and punctuation on a non-QWERTY layout, and a private-use key has no layout meaning to recover. Filtering on "printable ASCII only" would also work, but the private-use test says what's actually meant.Nothing in
Tests/coversdispatchShortcutorExtensionAction.matchesright now, which is presumably how it went unnoticed.Steps to reproduce
tonka3000).⌘⇧↑,⌘⇧↓,⌘⇧←or⌘⇧→. Nothing happens, and the snake keeps going until it dies.Screenshots or recording
The action panel showing the four direction actions with their shortcuts rendered correctly, none of which fire:
The keycode table above is the more useful artefact. It came from calling
UCKeyTranslatedirectly with the same argumentsASCIIKeyboardLayout.character(for:)passes, then comparing against whatExtensionAction.keyEquivalentreturns for each Raycast key name.Tinycast version + channel
0.11.3 stable
macOS version
27.0 (26A428)
Contribution
approvedSmall one: an early return in
keyEquivalent(fallingBackTo:)plus a harness coveringExtensionAction.matchesacross that key table, since there's nothing there today.