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 support for intl key legends based on the host keyboard layout #1161

Merged
merged 28 commits into from
Sep 4, 2022

Conversation

precondition
Copy link
Contributor

@precondition precondition commented Aug 8, 2022

Description

demo-intl-configurator.webm

(I capped the framerate at 20fps to reduce the file size, that's why it looks choppy)

I replaced the ISO toggle switch in the settings by a more general dropdown that lets the users pick the correct logical/functional keyboard layout of their OS. The only effect of this setting is to change how each keycode is displayed; nothing about the constructed keymap.json is altered.

To get started, I added the following host keyboard layouts:

  • US
  • UK
  • German
  • Russian

The lookup tables used for those host keyboard layouts can be found in src/i18n/keymap_extras and were generated with the help of the src/i18n/keymap_extras/convert_keymap_extras_header.js script. The script would allow me to easily add support for every keymap_extra input language that qmk_firmware supports, but for the sake of keeping this PR more concise, I limited myself to four OS keyboard layouts.

The bulk of the relatively impressive amount of added lines in this PR comes from those generated lookup tables, and to a lesser extend from the optional converter script used to generate them. The actual core changes to qmk_configurator are small.

Future Work

Can be addressed in follow-up PRs

  • Support more OS layouts (See Add more OS keyboard layouts #1165)
  • Add the corresponding "host_language" in the keymap.json
  • Guess the user's OS keyboard layout based on their locale
  • Possibly hide keys for capital letters in the "Shifted Symbols" section
  • Include comments and ASCII art in the generated output of convert_keymap_extras.py
  • Document the process of adding support for a new keymap_extras/OS keyboard layout
  • Sort the OS kb layout drop-down menu by localised/translated labels (Done in cc349e1)
  • Remove all dead code related to the defunct ISO toggle
  • Support localisation for the magic swap keycodes in the convert_keymap_extras_header.js script

Known Bugs

  • The text size for legends is computed based on the length of the key.name of the OS keyboard layout initially loaded and does not get updated when switching OS layouts until the user initiates a refresh. Concretely, this means that if the last saved OS layout was keymap_us, the name property of KC_SCLN would have been ":\n;". If the user switches to keymap_german, the locale keysym of KC_SCLN ("ö") will be shown in small text despite being a single character. (Solved in b84a675) Indirectly solved by Explore how to support internationalization of the keymap #1166
  • The test page (config.qmk.fm/#/test) doesn't dynamically update the key legends when switching OS layouts in the menu. You need to switch and reload the page for the new OS keyboard layout to apply. (Solved in 1bad93e) Indirectly solved by Explore how to support internationalization of the keymap #1166
  • Host Keyboard Layout dropdown is empty if an old configuratorSettings object missing the new osKeyboardLayout property is in localstorage. (Solved in 82cb033)

Motivation

Hello, I'm using an AZERTY layout and im wondering how can I set my < and > on the keyboard, mapping kc_lt & kc_gt doesn't work and puts . and / insead. Any ideas on how can I solve this ? thanks

Heya folks! Managed to flash my keyboard, and everything seems to work just fine. QMK seems powerful and great! I've been using https://config.qmk.fm/ to configure the layout, but what layout does that site assume my OS uses? For instance: Assuming I flash with the default layout and my OS's layout is set to "US-QWERTY", pressing the key z key on my keyboard would produce a z in the text editor. However, if I now change my OS's layout to "DE-QWERTZ" (which swaps the z and y keys), if I press the same key, it would produce a y instead. That means that, when the user does not set the correct layout, the layout they just flashed won't entirely function as config.qmk.fm intended or displayed it to. So what is that 'correct layout'? Related to that: Assuming I would like to build my keyboards in respect to "DE-QWERTZ" (for instance, if one visits public libraries in Germany a lot and would like to take their keyboard there), can I still use config.qmk.fm? That is, is there some setting or application that can convert from the 'correct layout' to any other layout?

my keymap is great and everything but i was just wondering if i could export it from what it is rn because some keys are out of place on it like the apostrophe and the { key are switched and the colon and semicolon button is ñ besides that everything else is in the right place i just dont know why it would be those keys instead of theyre intended one

Linked Issues

Feature Request: Add European layouts to the onscreen keyboard #866

[Feature Request] Support for other software keyboard layouts #846

Unable to add ISO-specific keys in configurator #768

Feature: Non--US Keyboard support #229

@yanfali
Copy link
Collaborator

yanfali commented Aug 10, 2022

I'm still digesting the PR, so I'm not ignoring you I promise. I think it looks pretty good, I just want to think about it.

I'm not thrilled to add python to the repo as it's even less portable than node in some respects.

Copy link
Member

@noroadsleft noroadsleft left a comment

Choose a reason for hiding this comment

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

Likewise, I'm not ignoring you or this PR either; unfortunately you've caught me just a few days ahead of being out of town for six days. I probably won't be able to properly review this until next week.

@yanfali
Copy link
Collaborator

yanfali commented Aug 10, 2022

Sometimes, switching from an OS layout where a key has a shift pair to an OS layout where that same key is just a letter displays the letter in small script because it still thinks that the length of key.name is greater than 1. A refresh fixes it.

This may be related to how the key name is being updated. The UI won't render if the reference doesn't change, depending on how it's rendering. I haven't looked at this code in a long time, It might be as simple as re-assigning the object to a new one and copying all the fields. The styling code should react to length changes, or it could just be a bug.

@precondition
Copy link
Contributor Author

I'm not thrilled to add python to the repo as it's even less portable than node in some respects.

I can translate the script into node.js if needs be. It is mostly text and hashmap manipulation so it is not hard to port.

@precondition
Copy link
Contributor Author

precondition commented Aug 11, 2022

If we ignore the deprecated keymap_nordic.h and the steno/plover header files that are out-of-scope, the converter script generates (syntaxically) correct output for every keymap_*.h header in qmk_firmware/quantum/keymap_extras!

: Assuming that one merges the PRs I opened to fix the bugs in keymap_bepo.h (qmk/qmk_firmware#17999) and keymap_lithuanian_qwerty.h (qmk/qmk_firmware#18000)
PS: Turns out there are more.

@yanfali
Copy link
Collaborator

yanfali commented Aug 12, 2022

If we ignore the deprecated keymap_nordic.h and the steno/plover header files that are out-of-scope, the converter script generates (syntaxically) correct output for every† keymap_*.h header in qmk_firmware/quantum/keymap_extras!

†: Assuming that one merges the PRs I opened to fix the bugs in keymap_bepo.h (qmk/qmk_firmware#17999) and keymap_lithuanian_qwerty.h (qmk/qmk_firmware#18000)

Thanks for doing this. I am traveling at the moment, but I will take a look this weekend. I need to test it myself.

@precondition
Copy link
Contributor Author

precondition commented Aug 12, 2022

While working on localising QK_GESC, I realised that its wording can be misleading. "Esc normally, but ~ when Shift or GUI is pressed". First of all, the Shift or GUI modifiers don't necessarily need to be pressed while pressing QK_GESC, it would work just fine even if you tapped a one-shot modifier. The important point is that one of those modifiers needs to be active. Secondly, when GUI is active, QK_GESC produces ` (at least on US), not ~.

My suggestion:

diff --git a/src/store/modules/keycodes/quantum.js b/src/store/modules/keycodes/quantum.js
index 734e9a1..90c5921 100644
--- a/src/store/modules/keycodes/quantum.js
+++ b/src/store/modules/keycodes/quantum.js
@@ -392,9 +392,9 @@ export default [
   { label: 'Special action keys', width: 'label' },
 
   {
-    name: 'Esc / ~',
+    name: '` / ~\nEsc',
     code: 'QK_GESC',
-    title: 'Esc normally, but ~ when Shift or GUI is pressed'
+    title: 'Esc normally, but ` when GUI is active or ~ when Shift is active'
   },
   {
     name: 'LS / (',
 

image

Displaying the legend on 2 lines would also be more coherent with the rest of the shift pairs. If you think about it, the shift pair of QK_GESC is base=Esc and Shift=~ after all. Although I'm not entirely convinced by the ` / part.

See commit 5b36bf9

precondition added a commit to precondition/qmk_configurator that referenced this pull request Aug 12, 2022
precondition added a commit to precondition/qmk_configurator that referenced this pull request Aug 12, 2022
@yanfali
Copy link
Collaborator

yanfali commented Aug 12, 2022

While working on localising QK_GESC, I realised that its wording can be misleading. "Esc normally, but ~ when Shift or GUI is pressed". First of all, the Shift or GUI modifiers don't necessarily need to be pressed while pressing QK_GESC, it would work just fine even if you tapped a one-shot modifier. The important point is that one of those modifiers needs to be active. Secondly, when GUI is active, QK_GESC produces ` (at least on US), not ~.

My suggestion:

diff --git a/src/store/modules/keycodes/quantum.js b/src/store/modules/keycodes/quantum.js
index 734e9a1..90c5921 100644
--- a/src/store/modules/keycodes/quantum.js
+++ b/src/store/modules/keycodes/quantum.js
@@ -392,9 +392,9 @@ export default [
   { label: 'Special action keys', width: 'label' },
 
   {
-    name: 'Esc / ~',
+    name: '` / ~\nEsc',
     code: 'QK_GESC',
-    title: 'Esc normally, but ~ when Shift or GUI is pressed'
+    title: 'Esc normally, but ` when GUI is active or ~ when Shift is active'
   },
   {
     name: 'LS / (',
 

image

Displaying the legend on 2 lines would also be more coherent with the rest of the shift pairs. If you think about it, the shift pair of QK_GESC is base=Esc and Shift=~ after all. Although I'm not entirely convinced by the / ~ part.

See commit 5b36bf9

I have no opinion on this, as it doesn't work on macOS at all due to a different binding policy. @qmk/collaborators may have other opinions.

@precondition
Copy link
Contributor Author

precondition commented Aug 13, 2022

I just realised that since I mostly rely on the old pre-existing ISO toggle mechanism to update the key legends text, the test page (config.qmk.fm/#/test) doesn't dynamically update the key legends when switching OS layouts in the menu (since the old ISO toggle has no effect on that page). You need to switch and reload the page for the new OS keyboard layout to apply.

I have a feeling that fixing the first known bug will also patch this. However, I'm in the middle of a move right now and I will not have Wi-Fi in the next few days so I don't know when I'll be able to look into the issue.

@yanfali
Copy link
Collaborator

yanfali commented Aug 16, 2022

I just realised that since I mostly rely on the old pre-existing ISO toggle mechanism to update the key legends text, the test page (config.qmk.fm/#/test) doesn't dynamically update the key legends when switching OS layouts in the menu (since the old ISO toggle has no effect on that page). You need to switch and reload the page for the new OS keyboard layout to apply.

I have a feeling that fixing the first known bug will also patch this. However, I'm in the middle of a move right now and I will not have Wi-Fi in the next few days so I don't know when I'll be able to look into the issue.

This never needed to work iirc as you could

I just realised that since I mostly rely on the old pre-existing ISO toggle mechanism to update the key legends text, the test page (config.qmk.fm/#/test) doesn't dynamically update the key legends when switching OS layouts in the menu (since the old ISO toggle has no effect on that page). You need to switch and reload the page for the new OS keyboard layout to apply.

I have a feeling that fixing the first known bug will also patch this. However, I'm in the middle of a move right now and I will not have Wi-Fi in the next few days so I don't know when I'll be able to look into the issue.

As there are explicit ISO and ANSI buttons it was never really a priority to make this toggle either. It wouldn't be too hard to fix this though.

@yanfali
Copy link
Collaborator

yanfali commented Aug 16, 2022

super busy at work. I'll try and make time for this on thursday

@yanfali
Copy link
Collaborator

yanfali commented Aug 18, 2022

Thank you for all the hardwork. I will be reviewing this properly today, evening PST.

@precondition
Copy link
Contributor Author

precondition commented Aug 19, 2022

As I've guessed, the two known bugs share a common root cause. The root cause is that the values of this.meta (and by extension, this.meta.name) are set according to the OS keyboard layout selected during the initial loading of the web page, and does not get updated when the user switches OS layouts in the settings panel. Consequently, any components like BaseKey.vue or TesterKey.vue that rely on the value of this.meta.name to carry out their tasks do not react appropriately to the new OS layout settings (until a refresh of the page is made).

My solution, as presented in commits b84a675 and 1bad93e, is to use const { name } = this.lookupKeycode(this.meta.code); instead of this.meta.name. It works but I'm not a big fan of paying the O(n) price of the lookupKeycode call (due to state.keycodes.find()). Ideally, this.meta.name should get updated when the user switches OS keyboard layouts so that we can stay in O(1).

@yanfali
Copy link
Collaborator

yanfali commented Aug 19, 2022

There's an issue for the very first time it loads, the localstorage stuff is out of sync until the first reload.

@yanfali
Copy link
Collaborator

yanfali commented Aug 19, 2022

when switching to russian the ISO big enter doesn't kick in. Is that the expected behavior?

@precondition
Copy link
Contributor Author

when switching to russian the ISO big enter doesn't kick in. Is that the expected behavior?

Yes, the Russian keymap is set to be ANSI because the OS layout produces the same keysym for KC_BSLS, KC_NUHS and KC_NUBS. Additionally, the keymap_russian.h file included in qmk_firmware clearly shows an ANSI ASCII art:

/*
 * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
 * │ Ё │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 0 │ - │ = │       │
 * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
 * │     │ Й │ Ц │ У │ К │ Е │ Н │ Г │ Ш │ Щ │ З │ Х │ Ъ │  \  │
 * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤
 * │      │ Ф │ Ы │ В │ А │ П │ Р │ О │ Л │ Д │ Ж │ Э │        │
 * ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────────┤
 * │        │ Я │ Ч │ С │ М │ И │ Т │ Ь │ Б │ Ю │ . │          │
 * ├────┬───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
 * │    │    │    │                        │    │    │    │    │
 * └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘
 */

Copy link
Collaborator

@yanfali yanfali left a comment

Choose a reason for hiding this comment

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

I think this is looking really good. I'll try and re-test it this weekend and I think we can probably get it merged then. Thank you for your hard work and patience.

@noroadsleft
Copy link
Member

Can you try again with commit ac76998 ? After this commit, I can't reproduce the issue you describe but it wouldn't be the first time that the drop-down suffers from unforeseen bugs.

The changes should in theory prevent other similar new-property-missing-from-locally-stored-settings problems in the future.

Issue is fixed. ✔️

// so it is important to merge them with the default configurator settings to ensure that all
// settings are set.
let conf = {
...getDefaultConfiguratorSettings(),
Copy link
Collaborator

Choose a reason for hiding this comment

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

nice.

Copy link
Collaborator

@yanfali yanfali left a comment

Choose a reason for hiding this comment

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

A few minor changes need to manipulating the configurator saved state, otherwise LGTM.

@yanfali
Copy link
Collaborator

yanfali commented Aug 28, 2022

@precondition I think we're almost ready to merge this. Thanks again for this. Very cool feature. Just a couple of very small clean ups and we're good to go.

This is done so that the Shift+GESC and GUI+GESC keysyms/keycode names
remain on the same line because the `breakLines` functions of
PrintKey.vue and TesterKey.vue replace spaces ' ' with newlines '\n'.
@precondition precondition requested a review from yanfali August 28, 2022 18:51
Copy link
Collaborator

@yanfali yanfali left a comment

Choose a reason for hiding this comment

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

Lgtm. @noroadsleft can you give it one more test. Otherwise I think it's ready to merge.

@yanfali
Copy link
Collaborator

yanfali commented Sep 3, 2022

@noroadsleft bump

Copy link
Member

@noroadsleft noroadsleft left a comment

Choose a reason for hiding this comment

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

Looks good to me.

Thanks for this; been wanting this feature for a long time.

@noroadsleft noroadsleft merged commit 165258a into qmk:master Sep 4, 2022
@precondition precondition deleted the intl_support branch September 4, 2022 10:34
@precondition
Copy link
Contributor Author

Should the linked issues be closed now?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants