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

Keyboard Language/Layout Support #177

Open
innovaker opened this issue Sep 12, 2020 · 18 comments
Open

Keyboard Language/Layout Support #177

innovaker opened this issue Sep 12, 2020 · 18 comments
Labels
core Core functionality/behavior of ZMK enhancement New feature or request hid keymaps PRs and issues related to keymaps rfc

Comments

@innovaker
Copy link
Contributor

innovaker commented Sep 12, 2020

This topic was recently raised by xudongz and is increasingly on my mind as I revisit key names/codes.

  • Many potential users run their OS with an alternative keyboard layout.
  • For those unfamiliar with layouts: https://en.wikipedia.org/wiki/Keyboard_layout
  • Some users cannot change this setting on the OS due to restrictive policies.
  • The layout on a user's PC might be different to their smartphone.
  • This can be a point of confusion for mappings.

How should ZMK support or facilitate this use case?

Suggestions so far:

@innovaker innovaker added the rfc label Sep 12, 2020
@xudongzheng
Copy link
Contributor

The way I've approached this problem is distinguishing between "physical keys" (what gets sent via HID) and "virtual keys" (what is getting typed).

Suppose I want to type F. Normally you can just send KC_F if user is using QWERTY. However if user has Colemak, you need to send KC_E to get F. One can define a VirtualF key that looks at whether the device is configured for QWERTY/Colemak/etc and decide what to send.

I think some sort of "virtual key" mechanism is also useful for macros, where you have a virtual key that corresponds to a series of other virtual keys, at the lowest layer corresponding to a physical key that gets sent.

This can also be useful for making non-ASCII characters easy to define.
For example you might want a key for é and you can define VirtualETilde that does:

  • Alt-E-E on MacOS
  • AltGr-E on Linux/Windows
  • Alt-K-K on MacOS with Colemak

Similarly you can have VirtualUnicode or that Ctrl-Shift-U-[codepoint] on Linux (which by the way, probably needs to be Ctrl-Shift-I on Linux with Colemak) and adjust the sequence based on the OS (or do nothing if not supported). You can then have VirtualString that calls a series of VirtualUnicode keys.

https://github.com/ergoblue/src-adafruit/blob/master/control/keymap.go is an example implementation of my proposal (in Go).

@innovaker innovaker added the keymaps PRs and issues related to keymaps label Sep 21, 2020
@innovaker
Copy link
Contributor Author

@xudongzheng, as I've worked through #21, I've come to the same conclusion from a different angle: functional keys such as PASTE or MUTE.

  • These functional keys probably also need to be virtual, because Operating Systems don't provide consistent support across the HID specification. So, for the same user intent, the code(s) that must be sent over HID sometimes depends on the host's OS.
  • I also wouldn't be surprised if we discover nuances or platform specific codes the deeper we dig.

For the reasons you outlined, as well as my own, I'm also leaning towards the need for virtual key codes. Moreover, as we venture beyond standard keyboard codes (i.e. consumer controls, mouse buttons, axes, etc.), we may want to consider calling them intents.

However, it wouldn't be trivial to achieve, because an implementation needs to:

  1. Be aware of each host's expected layout.
  2. Provide mapping to the expected host layout. We'd only compile support for the mappings the user requires.
  3. Allow switching between host layouts.
  4. Handle the interplay of modifiers and simultaneous key events (NKRO).
  5. Minimize memory footprints (ROM and RAM). This'll largely depend on our encoding approach.
  6. Ideally associate host layout with the connection (profile). Which is probably only possible over BLE? because USB doesn't seem to have the concept of a unique connection identifier from ZMK's perspective.

I suspect that points (4) and (6) will be sticking points for virtual keys or intents.

Any thoughts?

@innovaker
Copy link
Contributor Author

A short discussion between @petejohanson and I following my comment above is relevant to this issue in the short-term:
https://discordapp.com/channels/719497620560543766/719544230497878116/764501452894765116

Suffice to say, host layout support is a consideration for the longer-term which needs to be explored.

In the short-term we're going to use workarounds for functional keys by leveraging OS-specific layers.

@innovaker innovaker added core Core functionality/behavior of ZMK enhancement New feature or request hid labels Oct 10, 2020
@toniz4
Copy link

toniz4 commented Nov 9, 2021

First it would be nice to implement something like qmk, that doesn't recognizes the host keyboard layout necessarily, just create aliases for the keycodes in the different layout. Just implementing the basic would be sufficient for most people (I think). I just use the abnt2 layout because I need to have access to ç and accented keys, so in my keyboard running qmk I just need to import the abnt2 keycodes and use it instead of the default KC_ keycodes, for most keys, most modifiers and function keys are unchanged.

This and macros are the only things stopping me from running zmk, it would be nice to have something like that implemented.

Thanks for the awesome work!

@Shahabaz-Bagwan
Copy link

Shahabaz-Bagwan commented Feb 23, 2022

as @toniz4 said about, ignoring the layout on the host. IMO it will be best thing. I was on qmk and thought zmk will also do the same and used my keyboard on other machine just to realize it will understand my keys. This also limit me from using custom layout.

correct me if I am wrong about custom layout

@alinelena
Copy link

this is something that in my opinion keeps zmk from expanding outside us/ansi world. @urob has a solution that an be simply upstreamed and simplified.

@bzgec
Copy link

bzgec commented Nov 7, 2022

When I saw this post, I felt discouraged about ZMK, but then after quite a bit of reading through the documentation I set up my layout which is Colemak-DH angle mode with a few of Slovenian letters (č, š, ž...).

My host (PC) layout is Slovenian so I needed to change quite a number of characters, but you can copy keymaps for different host layouts from QMK repo (like I did for Slovenian host layout).

My steps were to copy keymap_slovenian.h (other layouts) to my ZMK config folder (keys_si.h).
Then I changed symbols to match ZMK naming convention (take a look at keys.h).

With something like keys_si.h you can include it into your .keymap (#include "keys_si.h") and use your symbols really simply: &kp SI_A or &kp SI_ZCAR.

@tyalie
Copy link

tyalie commented Nov 13, 2022

@bzgec I've used your solution too for the German layout.
Maybe we could write a small python script or something around that corner to translate from QMK naming convention to the ZMK one?
I know that would only be provisionary, as it's a compile time thing, but it mostly works.

@toniz4
Copy link

toniz4 commented Nov 13, 2022

When I saw this post, I felt discouraged about ZMK, but then after quite a bit of reading through the documentation I set up my layout which is Colemak-DH angle mode with a few of Slovenian letters (č, š, ž...).

My host (PC) layout is Slovenian so I needed to change quite a number of characters, but you can copy keymaps for different host layouts from QMK repo (like I did for Slovenian host layout).

My steps were to copy keymap_slovenian.h (other layouts) to my ZMK config folder (keys_si.h). Then I changed symbols to match ZMK naming convention (take a look at keys.h).

With something like keys_si.h you can include it into your .keymap (#include "keys_si.h") and use your symbols really simply: &kp SI_A or &kp SI_ZCAR.

I didn't know you could do that, thanks for the info! Now I feel comfortable with trying out zmk.

@bzgec I've used your solution too for the German layout. Maybe we could write a small python script or something around that corner to translate from QMK naming convention to the ZMK one? I know that would only be provisionary, as it's a compile time thing, but it mostly works.

I could try to do something like that, probably an awk script would suffice that, if there is not many edge cases. In 2 months or so i will receive the components for my new keyboard, so by then I probably will get something made.

@KyrillGobber
Copy link

@bzgec and @tyalie thank you very much, I solved it now similarly to you for my swiss layout. Exellent!

@MajykOyster
Copy link

When I saw this post, I felt discouraged about ZMK, but then after quite a bit of reading through the documentation I set up my layout which is Colemak-DH angle mode with a few of Slovenian letters (č, š, ž...).

My host (PC) layout is Slovenian so I needed to change quite a number of characters, but you can copy keymaps for different host layouts from QMK repo (like I did for Slovenian host layout).

My steps were to copy keymap_slovenian.h (other layouts) to my ZMK config folder (keys_si.h). Then I changed symbols to match ZMK naming convention (take a look at keys.h).

With something like keys_si.h you can include it into your .keymap (#include "keys_si.h") and use your symbols really simply: &kp SI_A or &kp SI_ZCAR.

This is brilliant, thanks a lot. I followed your steps to make a french zmk keymap, it works perfectly well.

@caksoylar
Copy link
Contributor

Worth noting the ZMK locale generator project, which generates locale headers suitable for use with ZMK: https://github.com/joelspadin/zmk-locale-generator

If it is confirmed working for various locales by users, the generated headers could be incorporated into ZMK, or linked to in the documentation as an official approach.

@delriodev
Copy link

This is brilliant, thanks a lot. I followed your steps to make a french zmk keymap, it works perfectly well.

@MajykOyster I looked at your solution and I was wondering how you figured out how to compose the characters in your french_unicode.dtsi file?

@eZtaR1
Copy link

eZtaR1 commented May 13, 2024

When I saw this post, I felt discouraged about ZMK, but then after quite a bit of reading through the documentation I set up my layout which is Colemak-DH angle mode with a few of Slovenian letters (č, š, ž...).

My host (PC) layout is Slovenian so I needed to change quite a number of characters, but you can copy keymaps for different host layouts from QMK repo (like I did for Slovenian host layout).

My steps were to copy keymap_slovenian.h (other layouts) to my ZMK config folder (keys_si.h). Then I changed symbols to match ZMK naming convention (take a look at keys.h).

With something like keys_si.h you can include it into your .keymap (#include "keys_si.h") and use your symbols really simply: &kp SI_A or &kp SI_ZCAR.

Thank you very much!
I created a Danish keys.h if others are searching for something similar.
keys_dk.h.txt

@arbejd
Copy link

arbejd commented May 13, 2024

When I saw this post, I felt discouraged about ZMK, but then after quite a bit of reading through the documentation I set up my layout which is Colemak-DH angle mode with a few of Slovenian letters (č, š, ž...).
My host (PC) layout is Slovenian so I needed to change quite a number of characters, but you can copy keymaps for different host layouts from QMK repo (like I did for Slovenian host layout).
My steps were to copy keymap_slovenian.h (other layouts) to my ZMK config folder (keys_si.h). Then I changed symbols to match ZMK naming convention (take a look at keys.h).
With something like keys_si.h you can include it into your .keymap (#include "keys_si.h") and use your symbols really simply: &kp SI_A or &kp SI_ZCAR.

Thank you very much! I created a Danish keys.h if others are searching for something similar. keys_dk.h.txt

Lol what a timing, just seaching for a DK layout, my {} ends up being ¶≠ with these. do you happen to know what i do wrong?

@eZtaR1
Copy link

eZtaR1 commented May 14, 2024

Lol what a timing, just seaching for a DK layout, my {} ends up being ¶≠ with these. do you happen to know what i do wrong?

You didn't make a mistake - I did, and defined the brackets twice and one of these wrong, this should work :)

Nick from keymap editor proposed of doing it this way though, if you like having a GUI for editing.
keys_dk.h.txt

simson pushed a commit to simson/zmk-config that referenced this issue Nov 6, 2024
Mainly from zmkfirmware/zmk#177

Signed-off-by: Simeon Marijon <[email protected]>
Change-Id: I07556398a2de7185900cf371b3563ba007d43bac
simson pushed a commit to simson/zmk-config that referenced this issue Nov 6, 2024
Mainly from zmkfirmware/zmk#177

Signed-off-by: Simeon Marijon <[email protected]>
Change-Id: I07556398a2de7185900cf371b3563ba007d43bac
@bensums
Copy link

bensums commented Dec 8, 2024

Thanks @bzgec. Adapted your approach to make a UK version here: keys_uk.h

@urob
Copy link
Contributor

urob commented Dec 8, 2024

Worth noting the ZMK locale generator project, which generates locale headers suitable for use with ZMK: https://github.com/joelspadin/zmk-locale-generator

If it is confirmed working for various locales by users, the generated headers could be incorporated into ZMK, or linked to in the documentation as an official approach.

Might be worth adding Joel's module to the docs and/or editing the OP at the top so it's a bit easier to discover?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core Core functionality/behavior of ZMK enhancement New feature or request hid keymaps PRs and issues related to keymaps rfc
Projects
None yet
Development

No branches or pull requests