Comments (11)
This is all very complicated. Here are some givens:
- I use "logical shortcut" to mean the shortcut string used by the hotkey library: the one returned from
eventToHotkeyString
. - I use "humanized shortcut" to mean the string we want to display to the user.
- This string sometimes has some semantic expectations: For example
?
to open a help dialog,Command+c
to copy. - This string sometimes has some mechanical expectations: for example
WASD
keys for navigation in a game,Command+v
to paste.
- This string sometimes has some semantic expectations: For example
Given
- The same
event.key
can appear as a a different character on Mac vs Windows and Linux depending on Command / Shift etc making it unreliable to map shortcuts usingevent.key
as the "humanized" character for a shortcut. - We can not determine the user's keyboard layout making it difficult to map from
event.code
to a desired "humanized" character (eg.Shift+Slash
==?
is not true everywhere). - There is a proposed
KeyboardLayoutMap
andgetLayoutMap
spec https://wicg.github.io/keyboard-map/#h-keyboard-getlayoutmap that will allow translation from US / QWERTYevent.code
to other layouts for display purposes. - Without the
KeyboardLayoutMap
, at minimum we would require the user to tell us their keyboard layout so that we can translateevent.code
to a physical labeled key on their keyboard. - The w3c
event.code
gives the code as the physical key on a standard US QWERTY keyboard.
Then
- Since
event.key
is not the same on every user's keyboard we can not define keyboard shortcus usingevent.key
: so we must useevent.code
. - Since we do not always know the user's keyboard layout, we can not define keyboard shortcuts in a "universal" way with respect to "humanized" characters: so we can not support a shortcut that uses the same humanized character regardless of layout.
- For example, if we say that the
shift+?
hotkey is represented asShift+Slash
(event.keyShift
+event.code
) would result in the "humanized" shortcutshift+Plus
on French AZERTY keyboards.
- For example, if we say that the
- Since we must use
event.code
, andevent.code
represents a standard US QWERTY keyboard, we must store shortcuts as US QWERTY. - In order to "localize" this for other regions, we should separate the display of "humanized" shortcut strings as a formatter applied to the logical shortcut.
- The formatting should default to assuming US QWERTY.
- A keyboard layout should be passed to the formatter to allow another humanizing to another layout.
- The passed keyboard layout could come from the
KeyboardLayoutMap
API, or could be supplied to by the user via UI (a select for example).
Some implications from this
- Use https://wicg.github.io/keyboard-map/#h-keyboard-getlayoutmap
- Maybe polyfill it?
- we can ask the user for their layout if the API is not available and store it in local storage .
- separate storage of logical
event.code
from display of humanizedevent.key
- store key as
event.code
- display key localized for user's keyboard layout using layout map
- Maybe have UI to capture key codes
- Store as QWERTY
keyCode
- show QWERTY locale by default
- provide UI for user to select their keyboard layout (AZERTY, DVORAK etc.)
from hotkey.
Moving form a convo from another repo:
Based off this eventToHotkeyString test, it doesn't look like an uppercase alpha character is necessarily expected
Hrm that test is simulating the events though. Maybe we need to add playwright or something to that project and do some real browser tests? I will definitely test this carefully when I work on it to figure out exactly what's actually happening in the browser.
from hotkey.
Notice above that when the Control+Meta+Shift
are pressed together the result is an upper case event.key
! 🤔
from hotkey.
For helpful background; in #43 @keithamus states that "on macOS the "Meta+Shift" plane is always lowercase". I just checked and this does appear to be the case
This is also true of special characters
I think what this means is that:
?
is a valid shortcut if we want to leave theShift+
out of the string and is equivalent toShift+?
- But combined with the
metaKey
, that?
key could beMeta+/
on Mac. So, in order to specify thatshiftKey
is pressed,Meta+Shift+/
would be the required shortcut.
This leads me to think, that we should continue to require the Shift
key in the keyboard string. What do you think @khiga8
from hotkey.
Here is my proposed "logical" hotkey format:
- (
Control+
) - (
Alt+
) - (
Meta+
) - (
Shift+
) event.code
Examples
- To represent the key combination
ctrl+alt+cmd+shift+/
we would writeControl+Alt+Meta+Shift+Slash
. - To represent
shift+cmd+k
we would writeShift+Meta+KeyK
- To represent
cmd+space
we would writeMeta+Space
- To represent the key sequence
g n
, we would writeKeyG KeyN
Humanizing
We then would want to provide a formatting function that could show the above logical representations in a human readable form. This ideally would use the Keyboard.getLayoutMap()
API.
humanizeHotkey("Control+Alt+Meta+Shift+Slash") === "ctrl+alt+cmd+?"
humanizeHotkey("Shift+Meta+KeyK") === "cmd+K"
humanizeHotkey("Meta+Space") === "cmd+space"
humanizeHotkey("KeyG KeyN") === "g n"
humanizeHotkey("KeyG Shift+KeyN") === "g N"
This helper could take a keyboard layout (eg. DVORAK, AZERTY...) with QWERTY as default for when Keyboard.getLayoutMap()
is not universally available.
humanizeHotkey("Control+Alt+Meta+Shift+Slash", { layout: "DVORAK"}) === "ctrl+alt+cmd+Z"
humanizeHotkey("KeyG Shift+KeyN", { layout: "DVORAK"}) === "i B"
event.code "Slash" maps to the "z" key on a DVORAK keyboard
We could extend this idea to take other options. For example, we could format Meta
as cmd
on Mac, win
on Windows and meta
on Linux. We could define an option to render apple's shortcut symbols (⌃ ⌥ ⌘ ⇧
) etc...
"Localized" shortcuts for different keyboard layouts
It would then be to an implementer to provide alternate shortcuts to support different semantic hotkeys. For example, in order to preserve the semantics of the "ctrl+?"
(Control+Shift+Slash
) shortcut as a way to bring up a help menu, the implementer would have to provide a "localized" Control+Shift+BracketLeft
(BracketLeft
is the event.code
that corresponds with the location of the /?
key on a DVORAK layout).
from hotkey.
-
Based on what you know, can we rely on keyboard map API at this point? Are there polyfills we could use or would we need to write our own? If we are unable to rely on the keyboard map API, have you found there other tools out there to help retrieve the humanized output given a keyboard layout?
-
What does support (if any) for non-latin keyboard layouts look like? Are we supporting only: qwerty, dvorak, and colemak?
from hotkey.
Another thought: what if we support both event.key
and event.code
and let developers decide for themselves. We could use a prefix key:?
, key:k
, key:K
etc. or code:Slash
, code:KeyK
etc. to let the developer decide between semantic meaning and keyboard location.
This would put us back in the same place when key
is combined with Shift/Meta
such as Meta+Shift+key:k
.
Update: VS Code has a similar scheme that allows distinguishing event.code
([KeyA]
, [Space]
, [Slash]
) from event.key
(a
,
, /
) as something called a "scan-code" https://code.visualstudio.com/docs/getstarted/keybindings#_keyboard-layoutindependent-bindings
from hotkey.
@khiga8 thank you! Great questions!
- As far as reliablility of the keyboard map API:
- I have not been able to find a polyfill for the keyboard map API. Since it needs to detect details of the users system, it likely can't in fact be polyfilled.
- There is a polyfill that only works for US-en QWERTY https://github.com/WICG/keyboard-map/blob/main/keyboard-polyfill.js
- This polyfill actually made me realize that this API doesn't provide a way to map from, say
Shift+KeyN
toN
(just fromKeyN
ton
).
- I also uncovered a concerning issue WICG/keyboard-map#30 that indicates that Apple has decided the API is too invasive.
- I also have not found any reliable source of mappings of
event.code
to different layouts' keys. This would potentially mean we'd have to do this ourselves. Writing a lib would be trivial, but could be a bit of a chore to maintain.
- I have not been able to find a polyfill for the keyboard map API. Since it needs to detect details of the users system, it likely can't in fact be polyfilled.
- The explainer for keyboard layout map seems to suggest that this API would be sufficient for non-latin layouts:
For keyboard shortcuts, this Latin value is what is commonly used for shortcuts in applications (even when the native writing system is not Latin-based). Keyboards in areas where the common layout does not produce Latin characters will have both the native and the Latin characaters printed on the physical key caps to make this easier for users.
Note the assumption that the labels on the keyboard match the currently active keyboard locale. This is usually, but not always, true, but since there is no way to know that the actual labels are, this is the best surrogate.
I also found this proposal which I quite like w3c/uievents#247 but hasn't had any activity since November 2019.
from hotkey.
Note: in #66 I added a test and note in the README about the inconsistent treatment of shift.
When working on this issue, that test and README note should be updated to account for however we resolve this!
from hotkey.
A solution I am leaning towards is: when we encounter Shift
, we should split the hotkey into multiple trie nodes:
For example, for the hotkey "Shift+a"
(or "A"
), we could produce the following trie nodes:
Shift+a
Shift+A
A
For the hotkey "Mod+Shift+a"
(or "Mod+A"
) ...
... on Windows, we could produce the following trie nodes:
Control+Shift+a
Control+Shift+A
Control+A
... and on Mac we could produce the following nodes:
Meta+Shift+a
Meta+Shift+A
Meta+A
I think this would allow us to be prepared for any platform inconsistencies.
This would however require us to be able to map to from "uppercase" special characters — eg. from 1
to !
or from /
to ?
and vice-versa. This in turn will create problems supporting non US-QWERTY keyboard layouts.
from hotkey.
A separate thing I am considering is that we should support the "scan-code" square-bracket syntax from VSCode for event.code
.
from hotkey.
Related Issues (20)
- Hotkeys are fired when trying to type into a text field inside a custom element HOT 4
- Add support for class-name as `data-hotkey-scope`
- Add a special `Mod` character that translates to either `Meta` on Mac or `Control` on other platforms HOT 2
- Handle keypresses in elements with dotted ids HOT 1
- `eventToHotkeyString ` returns doubled "modifier" when "key" is a modifier
- Hotkey Mapper Tool accessibility improvements HOT 4
- Hotkey version 2 HOT 1
- Release action fails on publish to npm HOT 2
- `eventToHotKey` inconsistent `alt` key behaviour on Mac
- API alterations to allow injection of hotkey parsing and event processing HOT 4
- TypeError: Cannot read properties of undefined (reading 'startsWith')
- Hotkey version 3 HOT 4
- Any ways to define which event to fire when hotkey is triggered? HOT 4
- How might I make the user press the shortcut twice before running the keyDownHandler?
- Listen for some hotkeys on form fields
- Uncomment emulator secrets when vault token is minted HOT 1
- The / hotkey does not work HOT 9
- Add support for chords to mapper tool
- Add support for `event.code`
- Expose `hotkey` and `SequenceTracker` components
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from hotkey.