zmkfirmware / zmk

ZMK Firmware Repository
https://zmk.dev/
MIT License
2.67k stars 2.74k forks source link

Keyboard Language/Layout Support #177

Open innovaker opened 4 years ago

innovaker commented 4 years ago

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

How should ZMK support or facilitate this use case?

Suggestions so far:

xudongzheng commented 4 years ago

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:

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 commented 3 years ago

@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.

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 commented 3 years ago

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.

toniz4 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 1 year ago

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 commented 1 year ago

@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 commented 1 year ago

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 commented 1 year ago

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

MajykOyster commented 1 year ago

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 commented 1 year ago

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 commented 11 months ago

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 commented 4 months ago

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 commented 4 months ago

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 commented 4 months ago

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