Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a special Mod modifier that translates to either Meta on Mac or Control on other platforms #66

Merged
merged 24 commits into from
Oct 10, 2023

Conversation

theinterned
Copy link
Contributor

@theinterned theinterned commented Dec 17, 2021

resolves #56

What is this?

On Mac, Meta (command) is frequently used as the modifier for shortcuts: on Windows and Linux Control is used instead. Therefor in order to correctly localize hotkeys, it's common to see code that handles swapping platform-specific modifier keys in users of this library. It would make sense to do this in the library and eliminate all that custom code!

Mod modifier

This PR adds support for using a special Mod modifier that automatically localizes to Control on Windows / Linux, or Meta on Mac.

The rational is that this allows an easy way to define cross-platform shortcuts. Without this feature, an implementer would have to either support both Control and Meta forms of shortcuts, or write their own code to handle swapping these.

Consistent sorting of modifiers

Although it was only documented in #62 , hotkey has always had a hard requirement that modifiers are sorted in the order that matches the order eventToHotkeyString formats the modifier keys from an event.

Since the Control and Meta keys appear in different places in the hotkey string, in order to support the Mod key, I also had to ensure that modifiers in a hotkey string are consistently sorted before comparoson to an event that is serialized via eventToHotkeyString.

So this PR also removes the hard requirement that modifiers be sorted in a strict order.

Approach

I chose to add a new normalizeHotkey function to handle localizing the Mod key and sorting the modifiers. This normalizeHotkey is applied to the hotkey string in the expandHotkeyToEdges before it is added to the Trie. This ensures that when we later look for a serialized event in the trie, the hotkey string is already normalized to match the serialized output of eventToHotkeyString.

Limitations

The "Mod" key is not currently compatible with Shift and Alt modifiers.

Because Mac treats event.key differently than Windows or Linux when the Shift and / or Alt key is pressed, it means that the Mod modifier will not localize as expected when paired with Shift. I have noted this limitation in the tests and in the README. I was hoping to address #54 and #68 in this PR too but decided to defer to keep the size of the PR down.

TODO

  • implement normalizeHotkey function to allow comparing a eventToHotkey string to a hotkey string containing a Mod character.
    • Account for hotkeys that contain both Control and Meta!
    • Account for how Mac lowercases event.key when Meta+Shift are pressed.
  • Make normalizeHotkey platform specific: convert Mod to Meta on Mac or Control on other platforms.
  • Use this normalizeHotkey to map hotkey to Trie in expandHotkeyToEdges so that the Trie contains the platform-specific modifier: use it to allow keyDownHandler to match events to hotkey strings containing the Mod alias.
  • Add docs about Mod character
    • Add special notes about Shift etc?

@theinterned theinterned self-assigned this Dec 17, 2021
@theinterned theinterned added the enhancement New feature or request label Dec 17, 2021
@theinterned theinterned mentioned this pull request Dec 21, 2021
3 tasks
@theinterned theinterned force-pushed the theinterned/mod-character branch from 112547a to 4ab901f Compare December 31, 2021 16:36
@@ -1,45 +1,61 @@
<!doctype html>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there's no functional change — this is just the result form running prettier on this file.

@@ -1,29 +1,33 @@
<!doctype html>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same — there's no functional change — this is just the result form running prettier on this file.

src/utils.ts Outdated
@@ -25,5 +27,5 @@ export function fireDeterminedAction(el: HTMLElement, path: string[]): void {
}

export function expandHotkeyToEdges(hotkey: string): string[][] {
return hotkey.split(',').map(edge => edge.split(' '))
return hotkey.split(',').map(edge => edge.split(' ').map(k => normalizeHotkey(k)))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is where the normalization is applied, so we take the user-provided hotkey string, normalize (or localize?) it for the current platform and store that on the trie. Then when we later serialize a keyboard event we compare it to the normalized version of the string.

Comment on lines 18 to 22
['Mod+A', 'Meta+A', 'mac'], // TODO: on a mac upper-case keys are lowercased when Meta is pressed
['Mod+9', 'Control+9', 'win'],
['Mod+9', 'Meta+9', 'mac'],
['Mod+)', 'Control+)', 'win'],
['Mod+)', 'Meta+)', 'mac'], // TODO: on a mac upper-case keys are lowercased when Meta is pressed
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that the tests on line 18 and 22 are incorrect: the hotkey Meta+A won't match on Mac: instead it should be Meta+Shift+a in the current implementation. Likewise, Meta+) should be Meta+Shift+0.

I hope to address this in #54

README.md Outdated
6. `"Mod"` is a special modifier that localizes to `Meta` on MacOS/iOS, and `Control` on Windows/Linux.
1. `"Mod+"` can appear in any order in a hotkey string. For example: `"Mod+Alt+Shift+KEY"`
2. Neither the `Control` or `Meta` modifiers should appear in a hotkey string with `Mod`.
3. Due to the inconsistent lower-caseing of `event.key` on Mac and iOS when `Meta` is pressed along with `Shift`, it is recommended to avoid hotkey strings containing both `Mod` and `Shift`.
Copy link
Contributor Author

@theinterned theinterned Dec 31, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added this note for now, but hope to resolve this inconsistency in #54I have made a note to update the README in that issue.

@theinterned theinterned marked this pull request as ready for review December 31, 2021 22:43
@theinterned theinterned requested a review from a team as a code owner December 31, 2021 22:43
@theinterned theinterned changed the title [WIP] Add a special Mod character that translates to either Meta on Mac or Control on other platforms Add a special Mod character that translates to either Meta on Mac or Control on other platforms Dec 31, 2021
@theinterned theinterned changed the title Add a special Mod character that translates to either Meta on Mac or Control on other platforms Add a special Mod modifier that translates to either Meta on Mac or Control on other platforms Dec 31, 2021
Copy link
Contributor

@khiga8 khiga8 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding the notes around inconsistent behavior 🙇‍♀️

['Mod+Alt+a', 'Alt+Meta+a', 'mac'],
// Modifier sorting
['Shift+Alt+Meta+Control+m', 'Control+Alt+Meta+Shift+m'],
['Shift+Alt+Mod+m', 'Control+Alt+Shift+m', 'win']
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we include linux in these tests to demonstrate that it is considered, as noted in the README?
Also, should we have tests for the other apple platform matches: /Mac|iPod|iPhone|iPad/i?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can make this change for sure!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

I'm not sure if this is what you had in mind for consideration of linux? 2a61fcb

I also added a test for the other Mac platform strings 9171795

README.md Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
['Mod+Alt+a', 'Control+Alt+a', 'win'],
['Mod+Alt+a', 'Alt+Meta+a', 'mac'],
// Modifier sorting
['Shift+Alt+Meta+Control+m', 'Control+Alt+Meta+Shift+m'],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this test is only meant to demonstrate sorting works but wondering if we should exclude this given it's invalid. Or maybe we can add a note that this is invalid along with note to not use Mod with Meta or Control

Copy link
Contributor Author

@theinterned theinterned Jan 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is valid to have shortcuts that pair Control and Meta (just not either of those keys with Mod).

Control+Meta+a
🚫 Mod+Control+a ... would localize as Control+Meta+a on Mac / Control+a on windows / linux
🚫 Mod+Meta+a ... would localize as Meta+a on Mac / Control+Meta+a on windows / linux
⚠️ Mod+Control+Meta+a (would localize as Control+Meta+a ... which is okay but weird)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, it's technically valid on mac!

theinterned and others added 4 commits January 4, 2022 17:28
Co-authored-by: Kate Higa  <16447748+khiga8@users.noreply.github.com>
Co-authored-by: Kate Higa  <16447748+khiga8@users.noreply.github.com>
Copy link
Contributor Author

@theinterned theinterned left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't approve this because it's my own PR, but there are a few minor tweaks regardless. Besides that I think this all makes sense. Exciting to see this finally getting finalized 😃

pages/demo.html Outdated
Comment on lines 20 to 21
// import {install} from '../dist/index.js'
import {install} from 'https://unpkg.com/@github/hotkey@latest?module'
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think given the change @iansan5653 just made in #91 this change should no longer apply

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed this change 6693f1f

README.md Outdated Show resolved Hide resolved
given changes from #91 this change was no longer relevant
5. Modifier key combos are separated with a `+` and are prepended to a key in a consistent order as follows: `Control+Alt+Meta+Shift+KEY`.
6. You can use the comma key `,` as a hotkey, e.g. `a,,` would activate if the user typed `a` or `,`. `Control+,,x` would activate for `Control+,` or `x`.
5. Modifier key combos are separated with a `+` and are prepended to a key in a consistent order as follows: `"Control+Alt+Meta+Shift+KEY"`.
6. `"Mod"` is a special modifier that localizes to `Meta` on MacOS/iOS, and `Control` on Windows/Linux.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Super nitpick, control on Android as well? I'm not really familiar with that ecosystem

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think technically Android is Linux, so that might cover it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, right -- that's fair! I've read enough "Android isn't REAL Linux" stuff on the internet I completely forgot about this 😆

@iansan5653 iansan5653 merged commit 6297512 into main Oct 10, 2023
2 checks passed
@iansan5653 iansan5653 deleted the theinterned/mod-character branch October 10, 2023 17:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add a special Mod character that translates to either Meta on Mac or Control on other platforms
4 participants