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 Missing Keymappings for Czech Language on macOS #23346

Open
1 of 4 tasks
Tabonx opened this issue Mar 25, 2024 · 6 comments
Open
1 of 4 tasks

Add Missing Keymappings for Czech Language on macOS #23346

Tabonx opened this issue Mar 25, 2024 · 6 comments

Comments

@Tabonx
Copy link

Tabonx commented Mar 25, 2024

Feature Request Type

  • Core functionality
  • Add-on hardware support (eg. audio, RGB, OLED screen, etc.)
  • Alteration (enhancement/optimization) of existing feature(s)
  • New behavior

Description

Currently, QMK lacks keymapping support for the Czech language on macOS. This presents a challenge for users who aim to type in Czech on QMK-configured keyboards, as they must manually map keys. Furthermore, there are layout inconsistencies with Czech keyboards on macOS, with some keys misplaced compared to the ISO standard. For instance, I've found that KC_NUBS is incorrectly positioned instead of KC_GRV, resulting in the system interpreting it as <, >, ≤, or ≥. Although I've made some custom bindings, not all have been tested, and I haven't created mappings for symbols I don't use or accidentally discovered.

These are the custom key bindings I've created for my own reference. (I use normal QMK KC bindings in my keymap)

#define CZ_1 S(KC_1) // 1
#define CZ_2 S(KC_2) // 2
#define CZ_3 S(KC_3) // 3
#define CZ_4 S(KC_4) // 4
#define CZ_5 S(KC_5) // 5
#define CZ_6 S(KC_6) // 6
#define CZ_7 S(KC_7) // 7
#define CZ_8 S(KC_8) // 8
#define CZ_9 S(KC_9) // 9
#define CZ_0 S(KC_0) // 0
#define CZ_PLUS KS_1 // +
#define CZ_ECAR KC_2 // ě
#define CZ_SCAR KC_3 // š
#define CZ_CCAR KC_4 // č
#define CZ_RCAR KC_5 // ř
#define CZ_ZCAR KC_6 // ž
#define CZ_YACU KC_7 // ý
#define CZ_AACU KC_8 // á
#define CZ_IACU KC_9 // í
#define CZ_EACU KC_0 // é
#define CZ_UCAR KC_SCLN // ů
#define CZ_DQTS S(KC_SCLN) // "
#define CZ_SCOL ALGR(KC_SCLN) // ;
#define CZ_HELIPS S(ALGR(KC_SCLN)) // …
#define CZ_UACU KC_LBRC // ú
#define CZ_SLSH S(KC_LBRC) // /
#define CZ_LARR S(ALGR(KC_LBRC)) // ‹
#define CZ_RARR S(ALGR(KC_RBRC)) // ›
#define CZ_RBRC KC_RBRC // )
#define CZ_LBRC S(KC_RBRC) // (
#define CZ_SRBRC ALGR(KC_RBRC) // ]
#define CZ_SLBRC ALGR(KC_LBRC) // [
#define CZ_PRG KC_QUOT // §
#define CZ_BANG S(KC_QUOT) // !
#define CZ_SQUOT ALGR(KC_QUOT) // '
#define CZ_TILDE S(ALGR(KC_QUOT)) // ~
#define CZ_AT ALGR(KC_2) // @
#define CZ_HASH ALGR(KC_3) // #
#define CZ_DOL ALGR(KC_4) // $
#define CZ_TILDE2 ALGR(KC_5) // ~
#define CZ_CARET ALGR(KC_6) // ^
#define CZ_APRS ALGR(KC_7) // &
#define CZ_STAR ALGR(KC_8) // *
#define CZ_CLBRC ALGR(KC_9) // {
#define CZ_CRBRC ALGR(KC_0) // }
#define CZ_EQL KC_MINS // =
#define CZ_PERC S(KC_MINS) // %
#define CZ_COMMA S(ALGR(KC_MINS)) // ,
#define CZ_CAR S(KC_EQL) // ˇ
#define CZ_MINSS S(ALGR(KC_EQL)) // - ?(Minus)?
#define CZ_SQUOT2 KC_EQL // '
#define CZ_QOTEUP KC_BSLS // ¨
#define CZ_BQUOT S(KC_BSLS) // `
#define CZ_QUOTEUP2 ALGR(KC_BSLS) // ¨
#define CZ_DQUOTE S(ALGR(KC_BSLS)) // ""
#define CZ_COMMA3 KC_COMM // ,
#define CZ_QUEMARK S(KC_COMM) // ?
#define CZ_LARROW ALGR(KC_COMM) // <
#define CZ_LESEQUAL S(ALGR(KC_COMM)) // ≤
#define CZ_DOT KC_DOT // .
#define CZ_DDOT S(KC_DOT) // :
#define CZ_RARROW ALGR(KC_DOT) // >
#define CZ_MOREQUAL S(ALGR(KC_DOT)) // ≥
#define CZ_MINS3 KC_MINS // - (Minus)
#define CZ_DASH ALGR(KC_MINS) // – (Dash)
#define CZ_EMDASH S(ALGR(KC_MINS)) // — (Em Dash)
#define CZ_BASLSH KC_GRV // \
#define CZ_BTICK KC_PIPE // `
#define CZ_LARROW2 KC_NUBS // < >< button
#define CZ_RARROW2 S(KC_NUBS) // > >< button
@noroadsleft
Copy link
Member

I found your post on reddit, and started looking into it because it's a fascinating puzzle for me.

How do the MacOS bindings differ from the existing keymap_czech assignments below?

Normal

┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
│ ; │ + │ ě │ š │ č │ ř │ ž │ ý │ á │ í │ é │ = │ ´ │       │
├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
│     │ Q │ W │ E │ R │ T │ Z │ U │ I │ O │ P │ ú │ ) │     │
├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┐    │
│      │ A │ S │ D │ F │ G │ H │ J │ K │ L │ ů │ § │ ¨ │    │
├────┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴───┴────┤
│    │ \ │ Y │ X │ C │ V │ B │ N │ M │ , │ . │ - │          │
├────┼───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
│    │    │    │                        │    │    │    │    │
└────┴────┴────┴────────────────────────┴────┴────┴────┴────┘

Shifted

┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
│ ° │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 0 │ % │ ˇ │       │
├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
│     │   │   │   │   │   │   │   │   │   │   │ / │ ( │     │
├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┐    │
│      │   │   │   │   │   │   │   │   │   │ " │ ! │ ' │    │
├────┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴───┴────┤
│    │ | │   │   │   │   │   │   │   │ ? │ : │ _ │          │
├────┼───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
│    │    │    │                        │    │    │    │    │
└────┴────┴────┴────────────────────────┴────┴────┴────┴────┘

AltGr

┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐
│   │ ~ │   │ ^ │ ˘ │   │ ˛ │ ` │ ˙ │   │ ˝ │   │ ¸ │       │
├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤
│     │   │   │ € │   │   │   │   │   │   │   │ ÷ │ × │     │
├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┐    │
│      │   │ đ │ Đ │ [ │ ] │   │   │ ł │ Ł │ $ │ ß │ ¤ │    │
├────┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴───┴────┤
│    │   │   │ # │ & │ @ │ { │ } │   │ < │ > │ * │          │
├────┼───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤
│    │    │    │                        │    │    │    │    │
└────┴────┴────┴────────────────────────┴────┴────┴────┴────┘

I will note that QMK as a project tries to stick to short-form keycodes of seven characters or less, which not all of yours do. But we can work around that once I've wrapped my head around how all the keys are supposed to behave.

@fauxpark
Copy link
Member

fauxpark commented Apr 3, 2024

macOS has its own key mappings for all of the languages it supports; in fact it has several variants depending on the "keyboard type" that is configured for a given keyboard - ANSI, ISO or JIS. For example my Macbook Pro's builtin keyboard is locked to ANSI, but it would not know anything about an external keyboard, hence the setup wizard that appears when you plug a new board in.

The ANSI Czech layout on macOS looks like this:
Base
ansi
Shifted
ansi-s
Option
ansi-a
Shift+Option
ansi-sa

ISO:
Base
iso
Shifted
iso-s
Option
iso-a
Shift+Option
iso-sa

@Tabonx
Copy link
Author

Tabonx commented Apr 3, 2024

I've already created an HJSON file for generating a Czech keymap and tested it. It seems MacOS interprets my CRKBR as ANSI and my built-in keyboard as ISO. As mentioned earlier, KC_NUBS and KC_GRV are switched, so KC_NUBS produces <> next to 1, and KC_GRV produces \| next to the left shift. I'm unsure if this issue is specific to how MacOS interprets my keyboard as ANSI or if it should be switched universally.

Below are the generated keymaps displaying KC_GRV as I think it should be, but it doesn't work for me.

#define CZ_LABK KC_GRV  // <
#define CZ_PLUS KC_1    // +
#define CZ_ECAR KC_2    // ě
#define CZ_SCAR KC_3    // š
#define CZ_CCAR KC_4    // č
#define CZ_RCAR KC_5    // ř
#define CZ_ZCAR KC_6    // ž
#define CZ_YACU KC_7    // ý
#define CZ_AACU KC_8    // á
#define CZ_IACU KC_9    // í
#define CZ_EACU KC_0    // é
#define CZ_EQL  KC_MINS // =
#define CZ_ACUT KC_EQL  // ´ (dead)
#define CZ_Q    KC_Q    // Q
#define CZ_W    KC_W    // W
#define CZ_E    KC_E    // E
#define CZ_R    KC_R    // R
#define CZ_T    KC_T    // T
#define CZ_Z    KC_Y    // Z
#define CZ_U    KC_U    // U
#define CZ_I    KC_I    // I
#define CZ_O    KC_O    // O
#define CZ_P    KC_P    // P
#define CZ_UACU KC_LBRC // ú
#define CZ_RPRN KC_RBRC // )
#define CZ_A    KC_A    // A
#define CZ_S    KC_S    // S
#define CZ_D    KC_D    // D
#define CZ_F    KC_F    // F
#define CZ_G    KC_G    // G
#define CZ_H    KC_H    // H
#define CZ_J    KC_J    // J
#define CZ_K    KC_K    // K
#define CZ_L    KC_L    // L
#define CZ_URNG KC_SCLN // ů
#define CZ_SECT KC_QUOT // §
#define CZ_DIAE KC_NUHS // ¨ (dead)
#define CZ_BSLS KC_NUBS // (backslash)
#define CZ_Y    KC_Z    // Y
#define CZ_X    KC_X    // X
#define CZ_C    KC_C    // C
#define CZ_V    KC_V    // V
#define CZ_B    KC_B    // B
#define CZ_N    KC_N    // N
#define CZ_M    KC_M    // M
#define CZ_COMM KC_COMM // ,
#define CZ_DOT  KC_DOT  // .
#define CZ_MINS KC_SLSH // -
#define CZ_RABK S(CZ_LABK) // >
#define CZ_1    S(CZ_PLUS) // 1
#define CZ_2    S(CZ_ECAR) // 2
#define CZ_3    S(CZ_SCAR) // 3
#define CZ_4    S(CZ_CCAR) // 4
#define CZ_5    S(CZ_RCAR) // 5
#define CZ_6    S(CZ_ZCAR) // 6
#define CZ_7    S(CZ_YACU) // 7
#define CZ_8    S(CZ_AACU) // 8
#define CZ_9    S(CZ_IACU) // 9
#define CZ_0    S(CZ_EACU) // 0
#define CZ_PERC S(CZ_EQL)  // %
#define CZ_CARN S(CZ_ACUT) // ˇ (dead)
#define CZ_SLSH S(CZ_UACU) // /
#define CZ_LPRN S(CZ_RPRN) // (
#define CZ_DQUO S(CZ_URNG) // "
#define CZ_EXLM S(CZ_SECT) // !
#define CZ_GRV  S(CZ_DIAE) // `
#define CZ_PIPE S(CZ_BSLS) // |
#define CZ_QUES S(CZ_COMM) // ?
#define CZ_COLN S(CZ_DOT)  // :
#define CZ_UNDS S(CZ_MINS) // _
#define CZ_LTEQ A(CZ_LABK) // ≤
#define CZ_BTCK A(CZ_PLUS) // `
#define CZ_AT   A(CZ_ECAR) // @
#define CZ_HASH A(CZ_SCAR) // #
#define CZ_DLR  A(CZ_CCAR) // $
#define CZ_TILD A(CZ_RCAR) // ~
#define CZ_CIRC A(CZ_ZCAR) // ^
#define CZ_AMPR A(CZ_YACU) // &
#define CZ_ASTR A(CZ_AACU) // *
#define CZ_LCBR A(CZ_IACU) // {
#define CZ_RCBR A(CZ_EACU) // }
#define CZ_RNGA A(CZ_EQL)  // ° (dead)
#define CZ_HAT  A(CZ_ACUT) // ^ (dead)
#define CZ_EDOT A(CZ_W)    // ė
#define CZ_EOGO A(CZ_E)    // ę
#define CZ_EURO A(CZ_R)    // €
#define CZ_LBRC A(CZ_UACU) // [
#define CZ_RBRC A(CZ_RPRN) // ]
#define CZ_AOGO A(CZ_A)    // ą
#define CZ_SS   A(CZ_S)    // ß
#define CZ_PDIF A(CZ_D)    // ∂
#define CZ_LSQU A(CZ_H)    // ‘
#define CZ_RSQU A(CZ_J)    // ’
#define CZ_LLST A(CZ_L)    // ł
#define CZ_SCLN A(CZ_URNG) // ;
#define CZ_QUOT A(CZ_SECT) // '
#define CZ_DIAC A(CZ_DIAE) // ¨ (dead)
#define CZ_COMA A(CZ_N)    // ‚
#define CZ_LTHN A(CZ_COMM) // <
#define CZ_GTHN A(CZ_DOT)  // >
#define CZ_NDSH A(CZ_MINS) // –
#define CZ_GREQ S(A(CZ_LABK)) // ≥
#define CZ_NOT  S(A(CZ_1))    // ¬
#define CZ_BULT S(A(CZ_2))    // •
#define CZ_NEQL S(A(CZ_3))    // ≠
#define CZ_PND  S(A(CZ_4))    // £
#define CZ_LOZN S(A(CZ_5))    // ◊
#define CZ_DAGG S(A(CZ_6))    // †
#define CZ_PARA S(A(CZ_7))    // ¶
#define CZ_DIV  S(A(CZ_8))    // ÷
#define CZ_LDAQ S(A(CZ_9))    // «
#define CZ_RDAQ S(A(CZ_0))    // »
#define CZ_CMA  S(A(CZ_EQL))  // , (dead)
#define CZ_DHPN S(A(CZ_ACUT)) // - (dead)
#define CZ_CEDT S(A(CZ_W))    // Ė
#define CZ_CEOG S(A(CZ_E))    // Ę
#define CZ_REGD S(A(CZ_R))    // ®
#define CZ_TM   S(A(CZ_T))    // ™
#define CZ_ZDOT S(A(CZ_Z))    // Ż
#define CZ_LSAQ S(A(CZ_UACU)) // ‹
#define CZ_RSAQ S(A(CZ_RPRN)) // ›
#define CZ_NARS S(A(CZ_S))    // ∑
#define CZ_LDQU S(A(CZ_H))    // “
#define CZ_RDQU S(A(CZ_J))    // ”
#define CZ_CLST S(A(CZ_L))    // Ł
#define CZ_ELLP S(A(CZ_URNG)) // …
#define CZ_DTIL S(A(CZ_SECT)) // ~ (dead)
#define CZ_DDQT S(A(CZ_DIAE)) // " (dead)
#define CZ_COPY S(A(CZ_C))    // ©
#define CZ_SQRT S(A(CZ_V))    // √
#define CZ_DLQU S(A(CZ_N))    // „
#define CZ_LEQ  S(A(CZ_COMM)) // ≤
#define CZ_GEQ  S(A(CZ_DOT))  // ≥
#define CZ_MDSH S(A(CZ_MINS)) // —

@fauxpark
Copy link
Member

fauxpark commented Apr 3, 2024

QMK provides both ANSI and ISO aliases, for example:
https://github.com/qmk/qmk_firmware/blob/master/data/constants/keycodes/extras/keycodes_italian_mac_ansi_0.0.1.hjson
https://github.com/qmk/qmk_firmware/blob/master/data/constants/keycodes/extras/keycodes_italian_mac_iso_0.0.1.hjson
I recommend looking at these as a jumping off point for new files as many of the Option/Shift+Option keys are the same, if maybe shuffled around sometimes. Also of note, only the first instance of a key should be defined if there are duplicates.

You can change the keyboard type at any time in the macOS keyboard settings, you just have to make sure the board you want to configure is "focused" by typing on it. In the case of boards with non-standard layouts such as the Corne, it can really be whichever one you want.

@Tabonx
Copy link
Author

Tabonx commented Apr 3, 2024

Two methods are available to produce the symbols <, >, , and . One using the buttons to 1, while the other using the KC_COMM and KC_DOT. Should I include only one of these methods?

@fauxpark
Copy link
Member

fauxpark commented Apr 3, 2024

Usually I'd say prefer the first instance from left to right, top to bottom, least modified to most, but considering the angle brackets are pretty typically located on the ,. keys, that is probably better than using KC_GRV.

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

No branches or pull requests

3 participants