keymap.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  1. /* Copyright 2021 Yonatan Zunger
  2. *
  3. * This program is free software: you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation, either version 2 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include QMK_KEYBOARD_H
  17. #include <assert.h>
  18. // This keymap is designed to make it easy to type in a wide variety of languages, as well as
  19. // generate mathematical symbols (à la Space Cadet), without relying on the host OS to do
  20. // key mappings or handle accents. Why? Because different OS's do this in radically different
  21. // ways, and don't support all of the features one often needs.
  22. //
  23. // LAYER MAGIC (aka, typing in many alphabets)
  24. //
  25. // This keyboard has three sets of "polyglot" layers: GREEK, CADET, and YIDDISH. Each of these
  26. // is actually a pair of layers, FOO and SHIFTFOO, which are full of Unicode points that let you
  27. // type in them. (The Greek and Yiddish keymaps selected here are very canted towards use on a
  28. // QWERTY layout, rather than the "standard" layouts often used for those languages in monolingual
  29. // environments. This is useful if your keyboard doesn't have legends for all of them, which in
  30. // most cases it won't. Of course, you could easily add more.)
  31. //
  32. // These each have their own layer select key, which can act as a held modifier key (GREEK+s to
  33. // produce sigma, etc). There's also a "layer lock" key; layer lock + modifier switches you into
  34. // that layer until you hit "layer lock" again to bounce back to QWERTY.
  35. //
  36. // ACCENT MAGIC
  37. //
  38. // We want to support easy typing of diacriticals, again without relying on the host OS. (On
  39. // MacOS, if you want Unicode to work you have to lose all the normal accent combining keys, and
  40. // if you're in a multi-OS world, each OS has a totally different input method)
  41. //
  42. // The real nuance comes from the three different ways Unicode represents these. Many common
  43. // accent + letter combinations like é have their own dedicated code points (the combined
  44. // normal form). One can also place a "combining accent mark" after the letter's code point to
  45. // form the decomposed normal form (NFKD); this often renders the same as the combined form, but
  46. // many less-sophisticated apps won't realize it's the same thing as the combined form (thus messing
  47. // up string matching), and if you backspace you need to backspace *twice* to remove the character,
  48. // because it's literally two characters. Finally, if you want to render just the accent mark as a
  49. // symbol of its own, that's a *third* code point. If you're simply typing, you don't want to think
  50. // about any of this!
  51. //
  52. // We thus have a bunch of special keycodes for "accent requests," which live on the FUNCTION
  53. // layer. Accent requests don't do anything immediate, but when the *next* non-modifier key is hit,
  54. // we generate a combined code point (if possible), two uncombined points (in cases where combined
  55. // points don't exist), or the isolated accent followed by the next character typed (in cases where
  56. // what you typed next isn't a letterform at all, e.g. you hit the space bar). You can also hit
  57. // shift-<accent request> to just generate the uncombined accent on its own.
  58. //
  59. // The current accent request codes are modeled on the ones in MacOS.
  60. //
  61. // fn+` Grave accent (`)
  62. // fn+e Acute accent (´)
  63. // fn+i Circumflex (^)
  64. // fn+u Diaresis / umlaut / trema (¨)
  65. // fn+c Cedilla (¸)
  66. // fn+n Tilde (˜)
  67. //
  68. // Together, these functions make for a nice "polyglot" keyboard: one that can easily type in a wide
  69. // variety of languages, which is very useful for people who, well, need to type in a bunch of
  70. // languages.
  71. //
  72. // The major TODOs are:
  73. // - Add accent support for Hebrew accents.
  74. // - Factor the code below so that the data layers are more clearly separated from the code logic,
  75. // so that other users of this keymap can easily add whichever alphabets they need without
  76. // having to deeply understand the implementation. Probably something similar to
  77. // users/drashna/keyrecords/unicode.c, but I want to see if I can do some preprocessor magic
  78. // so that we can actually have the rendered *character* sitting in the code instead of just the
  79. // hex code point!
  80. //
  81. // PLATFORM MAGIC (aka, working well on both Mac and Windows)
  82. //
  83. // Finally, this keyboard can switch between Mac and Windows modes, changing various macro
  84. // combinations, the Unicode mode, and the position of the ALT and GUI keys.
  85. enum custom_keycodes {
  86. // We provide special layer management keys:
  87. // GREEK triggers the Greek (aka "Front") layer, or the SHIFTGREEK layer when shift is held.
  88. // (Because we use Unicode, we need to implement shift-handling at the firmware level,
  89. // rather than the OS level like we do in the QWERTY layer)
  90. // CADET or GREEK+ALT triggers the Cadet (aka "Top") layer, or the SHIFTCADET layer when
  91. // shift is held.
  92. // YIDDISH triggers a keymap designed for easy Hebrew and Yiddish, based loosely on QWERTY
  93. // layouts.
  94. // LAYER_LOCK locks the "base" layer (i.e., QWERTY, GREEK, or CADET) to the value which is
  95. // pressed at the moment that it is being released. When a layer lock is set, the
  96. // analogous layer modifier key is reversed; e.g., if you lock the GREEK layer, then the
  97. // GREEK button bounces you back to QWERTY.
  98. //
  99. // We also parse the shift, alt, and caps lock keys to provide management of those which is
  100. // compatible with these various layers.
  101. KC_GREEK = SAFE_RANGE,
  102. KC_CADET,
  103. KC_YIDDISH,
  104. KC_LAYER_LOCK,
  105. KC_PLATFORM, // Platform select
  106. // OS-dependent macros
  107. KC_VC_MUTE, // Video conference mute
  108. KC_VC_HAND, // Video conference hand-raise
  109. KC_SCRNSHT, // Screenshot (gui-shift-S on Windows, gui-shift-4 on Mac)
  110. // These are the keycodes generated by the various "accent request" keystrokes.
  111. KC_ACCENT_START,
  112. KC_CGRV = KC_ACCENT_START, // Grave accent
  113. KC_CAGU, // Acute accent
  114. KC_CDIA, // Diaresis / umlaut / trema
  115. KC_CCIR, // Circumflex
  116. KC_CCED, // Cedilla
  117. KC_CTIL, // Tilde
  118. KC_ACCENT_END,
  119. };
  120. enum layers_keymap {
  121. _QWERTY = 0,
  122. _FIRST_LANGUAGE_LAYER,
  123. _YIDDISH = _FIRST_LANGUAGE_LAYER,
  124. _SHIFTYIDDISH,
  125. _GREEK,
  126. _SHIFTGREEK,
  127. _CADET,
  128. _SHIFTCADET,
  129. _LAST_LANGUAGE_LAYER,
  130. // Function goes last.
  131. _FUNCTION = _LAST_LANGUAGE_LAYER,
  132. };
  133. // We manage our OS mode internally, and store it in a static, rather than EEPROM, bit. That's
  134. // because it changes as we flip machines, and there's no good reason to wear out the memory.
  135. enum os_modes {
  136. _WINDOWS = 0,
  137. _MAC = 1,
  138. _OS_MODES_MAX = 2,
  139. };
  140. static uint8_t os_mode = _MAC;
  141. // Key types matter for accent handling. If there's a pending accent request and another key is
  142. // pressed:
  143. // - If it's a normal key, we trigger all our magic accent handling.
  144. // - If it's a modifier key, we do nothing and let the accent request hold until the next keypress.
  145. // - If it's a special key, we drop the accent request but don't handle it.
  146. enum key_types {
  147. _NORMAL_KEY,
  148. _MODIFIER_KEY,
  149. _SPECIAL_KEY,
  150. };
  151. // msec to hold the platform key to trigger a switch
  152. #define PLATFORM_HOLD_DURATION 750
  153. // This is so that H(xxxx) has the same width as _______, which makes the grids more legible.
  154. #define H(x) UC(0x##x)
  155. #define MO_FN MO(_FUNCTION)
  156. #define KC_LLCK KC_LAYER_LOCK
  157. // Values for our OS-dependent keys, as arrays keyed by OS mode. Use Meet shortcuts on Mac, Teams on Windows
  158. const char *VC_MUTE_VALUES[_OS_MODES_MAX] = {SS_LCTL(SS_LSFT("m")), SS_LCMD("d")};
  159. const char *VC_HAND_VALUES[_OS_MODES_MAX] = {SS_LCTL(SS_LSFT("k")), SS_LCTL(SS_LCMD("h"))};
  160. const char *SCRNSHT_VALUES[_OS_MODES_MAX] = {SS_LGUI(SS_LSFT("s")), SS_LCMD(SS_LSFT("4"))};
  161. const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
  162. [_QWERTY] = LAYOUT_all(
  163. KC_ESC, KC_LLCK, KC_GRAVE,KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_HOME,
  164. KC_PLATFORM, KC_MPLY, KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_PGUP,
  165. KC_SCRNSHT, KC_YIDDISH, KC_LCTL, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, KC_PGDN,
  166. KC_GREEK, KC_CADET, KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_UP, KC_END,
  167. KC_VC_HAND, KC_VC_MUTE, KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, MO_FN, KC_LEFT, KC_DOWN, KC_RGHT),
  168. /* The Greek and Cadet layers. Tab, backspace, the nav and modifier keys, and the control block
  169. * are always transparent.
  170. *
  171. * QWERTY GREEK SGREEK CADET SCADET YID SYID
  172. * ` ׳ 05f3 ״ 05f4
  173. * 1 ₁ 2081 ¹ 00b9 ¡ 00a1 ¿ 00bf [transparent]
  174. * 2 ₂ 2082 ² 00b2 « 00ab » 00bb [transparent]
  175. * 3 ₃ 2083 ³ 00b3 £ 00a3 € 20ac [transparent]
  176. * 4 ₄ 2084 ⁴ 2074 [transparent]
  177. * 5 ₅ 2085 ⁵ 2075 [transparent]
  178. * 6 ₆ 2086 ⁶ 2076 [transparent]
  179. * 7 ₇ 2087 ⁷ 2077 [transparent]
  180. * 8 ₈ 2088 ⁸ 2078 ° 00b0 ⊗ 2297 [transparent]
  181. * 9 ₉ 2089 ⁹ 2079 [transparent]
  182. * 0 ₀ 2080 ⁰ 2070 ∅ 2205 [transparent]
  183. * - ₋ 208b ⁻ 207b ¬ 00ac ⊖ 2296 [transparent]
  184. * = ₊ 208a ₋ 208b ≠ 2260 ⊕ 2295 [transparent]
  185. * q θ 03b8 Θ 0398 ℚ 211a ק 05e7
  186. * w ω 03c9 Ω 03a9 ש 05e9
  187. * e ε 03b5 Ε 0395 ∃ 2203 ∄ 2204 ע 05e2
  188. * r ρ 03c1 Ρ 03a1 ℝ 211d ר 05e8
  189. * t τ 03c4 Τ 03a4 ט 05d8 תּ fb4a
  190. * y ψ 03c8 Ψ 03a8 ∨ 2228 ∧ 2227 ײ 05f2 ײַ fb1f
  191. * u υ 03c5 Υ 03a5 ∪ 222a ∩ 2229 ו 05d5 ױ 05f1
  192. * i ι 03b9 Ι 0399 ∞ 221e ℵ 2135 י 05d9
  193. * o ο 03bf Ο 039f ו 05d5 אָ fb2f
  194. * p π 03c0 Π 03a0 ≡ 2261 ≢ 2262 פ 05e4 ף 05e3
  195. * [ ± 00b1 ∓ 2213
  196. * ] ≈ 2248 ≉ 2249
  197. * \ ∼ 223c ≁ 2241
  198. * a α 03b1 Α 0391 ∀ 2200 Å 212b א 05d0 אַ fb2e
  199. * s σ 03c3 Σ 03a3 ∈ 2208 ∉ 2209 ס 05e1 ת 05ea
  200. * d δ 03b4 Δ 0394 ⊂ 2282 ⊄ 2284 ד 05d3
  201. * f φ 03c6 Φ 03a6 ⊆ 2286 ⊈ 2288 פֿ fb4e
  202. * g γ 03b3 Γ 0393 ⊇ 2287 ⊉ 2289 ג 05d2
  203. * h η 03b7 Η 0397 ← 2190 ⇐ 21d0 ה 05d4
  204. * j ϑ 03d1 ↓ 2193 ⇓ 21d3 ח 05d7 כֿ fb4d
  205. * k κ 03ba Κ 039a ↑ 2191 ⇑ 21d1 כ 05db ך 05da
  206. * l λ 03bb Λ 039b → 2192 ⇒ 21d2 ל 05dc
  207. * ; … 2026 ⋯ 22ef ↔ 2194 ⇔ 21d4
  208. * ' · 00b7 • 2022 ∴ 2234 ⊙ 2299
  209. * z ζ 03b6 Ζ 0396 ℤ 2124 ז 05d6
  210. * x ξ 03be Ξ 039e ✘ 2718 צ 05e6 ץ 05e5
  211. * c χ 03c7 Χ 03a7 ℂ 2102 כ 05db ך 05da
  212. * v ς 03c2 ✔ 2714 √ 221a װ 05f0 בֿ fb4c
  213. * b β 03b2 Β 0392 ב 05d1
  214. * n ν 03bd Ν 039d ℕ 2115 נ 05e0 ן 05df
  215. * m μ 03bc Μ 039c מ 05de ם 05dd
  216. * , ≪ 226a ≫ 226b ∂ 2202 ∫ 222b
  217. * . ≲ 2272 ≳ 2273 ≰ 2270 ≱ 2271
  218. * / ⊘ 2298
  219. */
  220. [_YIDDISH] = LAYOUT_all(
  221. KC_TRNS, KC_TRNS, H(05f3), KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
  222. KC_TRNS, KC_TRNS, KC_TRNS, H(05e7), H(05e9), H(05e2), H(05e8), H(05d8), H(05f2), H(05d5), H(05d9), H(05d5), H(05e4), KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
  223. KC_TRNS, KC_TRNS, KC_TRNS, H(05d0), H(05e1), H(05d3), H(fb4e), H(05d2), H(05d4), H(05d7), H(05db), H(05dc), KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
  224. KC_TRNS, KC_TRNS, KC_TRNS, H(05d6), H(05e6), H(05db), H(05f0), H(05d1), H(05e0), H(05de), KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
  225. KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS),
  226. [_SHIFTYIDDISH] = LAYOUT_all(
  227. KC_TRNS, KC_TRNS, H(05f4), KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
  228. KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, H(fb4a), H(fb1f), H(05f1), KC_TRNS, H(fb2f), H(05e3), KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
  229. KC_TRNS, KC_TRNS, KC_TRNS, H(fb2e), H(05ea), KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, H(fb4d), H(05da), KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
  230. KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, H(05e5), H(05da), H(fb4c), KC_TRNS, H(05df), H(05dd), KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
  231. KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS),
  232. [_GREEK] = LAYOUT_all(
  233. KC_TRNS, KC_TRNS, XXXXXXX, H(2081), H(2082), H(2083), H(2084), H(2085), H(2086), H(2087), H(2088), H(2089), H(2080), H(208b), H(208a), KC_TRNS, KC_TRNS,
  234. KC_TRNS, KC_TRNS, KC_TRNS, H(03b8), H(03c9), H(03b5), H(03c1), H(03c4), H(03c8), H(03c5), H(03b9), H(03bf), H(03c0), XXXXXXX, XXXXXXX, XXXXXXX, KC_TRNS,
  235. KC_TRNS, KC_TRNS, KC_TRNS, H(03b1), H(03c3), H(03b4), H(03c6), H(03b3), H(03b7), XXXXXXX, H(03ba), H(03bb), H(2026), H(00b7), KC_TRNS, KC_TRNS,
  236. KC_TRNS, KC_TRNS, KC_TRNS, H(03b6), H(03be), H(03c7), XXXXXXX, H(03b2), H(03bd), H(03bc), H(226a), H(2272), XXXXXXX, KC_TRNS, KC_TRNS, KC_TRNS,
  237. KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS),
  238. [_SHIFTGREEK] = LAYOUT_all(
  239. KC_TRNS, KC_TRNS, XXXXXXX, H(00b9), H(00b2), H(00b3), H(2074), H(2075), H(2076), H(2077), H(2078), H(2079), H(2070), H(207b), H(208b), KC_TRNS, KC_TRNS,
  240. KC_TRNS, KC_TRNS, KC_TRNS, H(0398), H(03a9), H(0395), H(03a1), H(03a4), H(03a8), H(03a5), H(0399), H(039f), H(03a0), XXXXXXX, XXXXXXX, XXXXXXX, KC_TRNS,
  241. KC_TRNS, KC_TRNS, KC_TRNS, H(0391), H(03a3), H(0394), H(03a6), H(0393), H(0397), H(03d1), H(039a), H(039b), H(22ef), H(2022), KC_TRNS, KC_TRNS,
  242. KC_TRNS, KC_TRNS, KC_TRNS, H(0396), H(039e), H(03a7), H(03c2), H(0392), H(039d), H(039c), H(226b), H(2273), XXXXXXX, KC_TRNS, KC_TRNS, KC_TRNS,
  243. KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS),
  244. [_CADET] = LAYOUT_all(
  245. KC_TRNS, KC_TRNS, XXXXXXX, H(00a1), H(00ab), H(00a3), XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, H(00b0), XXXXXXX, H(2205), H(00ac), H(2260), KC_TRNS, KC_TRNS,
  246. KC_TRNS, KC_TRNS, KC_TRNS, H(211a), XXXXXXX, H(2203), H(211d), XXXXXXX, H(2228), H(222a), H(221e), XXXXXXX, H(2261), H(00b1), H(2248), H(223c), KC_TRNS,
  247. KC_TRNS, KC_TRNS, KC_TRNS, H(2200), H(2208), H(2282), H(2286), H(2287), H(2190), H(2193), H(2191), H(2192), H(2194), H(2234), KC_TRNS, KC_TRNS,
  248. KC_TRNS, KC_TRNS, KC_TRNS, H(2124), H(2718), H(2102), H(2714), XXXXXXX, H(2115), XXXXXXX, H(2202), H(2270), XXXXXXX, KC_TRNS, KC_TRNS, KC_TRNS,
  249. KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS),
  250. [_SHIFTCADET] = LAYOUT_all(
  251. KC_TRNS, KC_TRNS, XXXXXXX, H(00bf), H(00bb), H(20ac), XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, H(2297), XXXXXXX, XXXXXXX, H(2296), H(2295), KC_TRNS, KC_TRNS,
  252. KC_TRNS, KC_TRNS, KC_TRNS, XXXXXXX, XXXXXXX, H(2204), XXXXXXX, XXXXXXX, H(2227), H(2229), H(2135), XXXXXXX, H(2262), H(2213), H(2249), H(2241), KC_TRNS,
  253. KC_TRNS, KC_TRNS, KC_TRNS, H(212b), H(2209), H(2284), H(2288), H(2289), H(21d0), H(21d3), H(21d1), H(21d2), H(21d4), H(2299), KC_TRNS, KC_TRNS,
  254. KC_TRNS, KC_TRNS, KC_TRNS, XXXXXXX, XXXXXXX, XXXXXXX, H(221a), XXXXXXX, XXXXXXX, XXXXXXX, H(222b), H(2271), H(2298), KC_TRNS, KC_TRNS, KC_TRNS,
  255. KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS),
  256. // The function layer mostly contains the accent marks, but also has a few meta-control
  257. // operations. The accent marks are placed by analogy with Mac OS.
  258. [_FUNCTION] = LAYOUT_all(
  259. QK_BOOT, KC_TRNS, KC_CGRV, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, XXXXXXX, XXXXXXX,
  260. KC_TRNS, KC_TRNS, KC_TRNS, XXXXXXX, XXXXXXX, KC_CAGU, XXXXXXX, XXXXXXX, XXXXXXX, KC_CDIA, KC_CCIR, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
  261. KC_TRNS, KC_TRNS, KC_TRNS, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
  262. KC_TRNS, KC_TRNS, KC_TRNS, XXXXXXX, XXXXXXX, KC_CCED, XXXXXXX, XXXXXXX, KC_CTIL, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, KC_TRNS, XXXXXXX, XXXXXXX,
  263. KC_TRNS, KC_TRNS, KC_RCTL, KC_RGUI, KC_RALT, KC_TRNS, KC_TRNS, XXXXXXX, XXXXXXX, XXXXXXX),
  264. };
  265. ////////////////////////////////////////////////////////////////////////////////////////////////////
  266. // Accent implementation
  267. //
  268. // In the body of process_record_user, we store an "accent_request", which is the accent keycode if
  269. // one was just selected, or zero otherwise. When the *next* key is hit, we look up whether the
  270. // accent request plus that next keycode (plus the state of the shift key) together amount to an
  271. // interesting combined (NFKC) character, and if so, emit it; otherwise, we emit the accent as a
  272. // separate character and then process the next key normally. The resulting UI behavior is similar
  273. // to that of the combining accent keys in MacOS.
  274. //
  275. // We store two arrays, depending on whether shift is or isn't held. Each is two-dimensional, with
  276. // its outer key by the next keycode struck, and the inner key by the accent requested. The outer
  277. // array has KC_Z + 1 as its upper bound, so that we can save memory by only coding alphabetic keys.
  278. // The contents are either Unicode code points, or zero to indicate that we don't have a point for
  279. // this combination.
  280. #define KC_NUM_ACCENTS (KC_ACCENT_END - KC_ACCENT_START)
  281. #define KC_NUM_SLOTS (KC_Z + 1)
  282. const uint16_t PROGMEM unshifted_accents[KC_NUM_SLOTS][KC_NUM_ACCENTS] = {
  283. // KC_CGRV, KC_CAGU, KC_CDIA, KC_CCIR, KC_CCED, KC_CTIL
  284. [KC_A] = { 0x00e0, 0x00e1, 0x00e4, 0x00e2, 0, 0x00e3 },
  285. [KC_E] = { 0x00e8, 0x00e9, 0x00eb, 0x00ea, 0, 0 },
  286. [KC_I] = { 0x00ec, 0x00ed, 0x00ef, 0x00ee, 0, 0 },
  287. [KC_O] = { 0x00f2, 0x00f3, 0x00f6, 0x00f4, 0, 0x00f5 },
  288. [KC_U] = { 0x00f9, 0x00fa, 0x00fc, 0x00fb, 0, 0 },
  289. [KC_Y] = { 0, 0, 0x00ff, 0, 0, 0 },
  290. [KC_N] = { 0, 0, 0, 0, 0, 0x00f1 },
  291. [KC_C] = { 0, 0, 0, 0, 0x00e7, 0 },
  292. };
  293. const uint16_t PROGMEM shifted_accents[KC_NUM_SLOTS][KC_NUM_ACCENTS] = {
  294. // KC_CGRV, KC_CAGU, KC_CDIA, KC_CCIR, KC_CCED, KC_CTIL
  295. [KC_A] = { 0x00c0, 0x00c1, 0x00c4, 0x00c2, 0, 0x00c3 },
  296. [KC_E] = { 0x00c8, 0x00c9, 0x00cb, 0x00ca, 0, 0 },
  297. [KC_I] = { 0x00cc, 0x00cd, 0x00cf, 0x00ce, 0, 0 },
  298. [KC_O] = { 0x00d2, 0x00d3, 0x00d6, 0x00d4, 0, 0x00d5 },
  299. [KC_U] = { 0x00d9, 0x00da, 0x00dc, 0x00db, 0, 0 },
  300. [KC_Y] = { 0, 0, 0x00df, 0, 0, 0 },
  301. [KC_N] = { 0, 0, 0, 0, 0, 0x00d1 },
  302. [KC_C] = { 0, 0, 0, 0, 0x00c7, 0 },
  303. };
  304. // The uncombined and combined forms of the accents, for when we want to emit them as single
  305. // characters.
  306. const uint16_t PROGMEM uncombined_accents[KC_NUM_ACCENTS] = {
  307. [KC_CGRV - KC_ACCENT_START] = 0x0060,
  308. [KC_CAGU - KC_ACCENT_START] = 0x00b4,
  309. [KC_CDIA - KC_ACCENT_START] = 0x00a8,
  310. [KC_CCIR - KC_ACCENT_START] = 0x005e,
  311. [KC_CCED - KC_ACCENT_START] = 0x00b8,
  312. [KC_CTIL - KC_ACCENT_START] = 0x02dc,
  313. };
  314. const uint16_t PROGMEM combined_accents[KC_NUM_ACCENTS] = {
  315. [KC_CGRV - KC_ACCENT_START] = 0x0300,
  316. [KC_CAGU - KC_ACCENT_START] = 0x0301,
  317. [KC_CDIA - KC_ACCENT_START] = 0x0308,
  318. [KC_CCIR - KC_ACCENT_START] = 0x0302,
  319. [KC_CCED - KC_ACCENT_START] = 0x0327,
  320. [KC_CTIL - KC_ACCENT_START] = 0x0303,
  321. };
  322. // This function manages keypresses that happen after an accent has been selected by an earlier
  323. // keypress.
  324. // Args:
  325. // accent_key: The accent key which was earlier selected. This must be in the range
  326. // [KC_ACCENT_START, KC_ACCENT_END).
  327. // keycode: The keycode which was just pressed.
  328. // is_shifted: The current shift state (as set by a combination of shift and caps lock)
  329. //
  330. // Returns true if the keycode has been completely handled by this function (and so should not be
  331. // processed further by process_record_user) or false otherwise.
  332. bool process_key_after_accent(
  333. uint16_t accent_key,
  334. uint16_t keycode,
  335. bool is_shifted
  336. ) {
  337. assert(accent_key >= KC_ACCENT_START);
  338. assert(accent_key < KC_ACCENT_END);
  339. const int accent_index = accent_key - KC_ACCENT_START;
  340. // If the keycode is outside A..Z, we know we shouldn't even bother with a table lookup.
  341. if (keycode <= KC_Z) {
  342. // Pick the correct array. Because this is progmem, we're going to need to do the
  343. // two-dimensional array indexing by hand, and so we just cast it to a single-dimensional array.
  344. const uint16_t *points = (const uint16_t*)(is_shifted ? shifted_accents : unshifted_accents);
  345. const uint16_t code_point = pgm_read_word(points + KC_NUM_ACCENTS * keycode + accent_index);
  346. if (code_point) {
  347. register_unicode(code_point);
  348. return true;
  349. }
  350. }
  351. // If we get here, there was no accent match. Emit the accent as its own character (i.e. a
  352. // Unicode combining accent mark) and return false so that process_record_user also registers
  353. // whatever is appropriate for the keycode after that. The host can figure out what to do with
  354. // combining Unicode.
  355. register_unicode(pgm_read_word(uncombined_accents + accent_index));
  356. return false;
  357. }
  358. // This is a bitmask which selects the activation bits for layers *other* than our language
  359. // selectors.
  360. #define NON_LANGUAGE_LAYERS ~(((1UL << _LAST_LANGUAGE_LAYER) - 1) - ((1UL << _FIRST_LANGUAGE_LAYER) - 1))
  361. // Update the current layer state and return the layer we're in.
  362. uint8_t update_layer(
  363. uint8_t layer_lock,
  364. uint8_t layer_select_held,
  365. bool shifted
  366. ) {
  367. uint8_t current_layer = layer_lock;
  368. layer_state_t language_layers = 0;
  369. // If there's a layer select being held right now, then it updates the current layer.
  370. // (If it's the layer select for the currently locked layer, then instead it's a toggle
  371. // back to _QWERTY!)
  372. if (layer_select_held != _QWERTY) {
  373. current_layer = (layer_lock == layer_select_held ? _QWERTY : layer_select_held);
  374. }
  375. language_layers |= (1UL << current_layer);
  376. // If we're shifted (with either shift or caps lock), and we're in one of our special
  377. // layers, bump up to the SHIFTED version of that layer. We don't do this for QWERTY;
  378. // there we just emit USB HID codes and let the host deal with shift.
  379. if (shifted && current_layer != _QWERTY) {
  380. ++current_layer;
  381. language_layers |= (1UL << current_layer);
  382. }
  383. // Update the QMK layer state by stomping just the language layer bits.
  384. const layer_state_t new_layer_state = (layer_state & NON_LANGUAGE_LAYERS) | language_layers;
  385. if (new_layer_state != layer_state) {
  386. layer_state_set(new_layer_state);
  387. }
  388. return current_layer;
  389. }
  390. void set_os_mode(uint8_t new_mode) {
  391. os_mode = new_mode;
  392. // NB: We set unicode_config.input_mode directly, rather than calling
  393. // set_unicode_input_mode, because we don't want to persist this and so we shouldn't put
  394. // extra load on the EEPROMs.
  395. unicode_config.input_mode = (os_mode == _MAC ? UNICODE_MODE_MACOS : UNICODE_MODE_WINCOMPOSE);
  396. // Swap LALT and LGUI depending on Mac/Windows.
  397. keymap_config.swap_lalt_lgui = (os_mode == _MAC);
  398. // This would be a great moment for some auditory or visual feedback, but this keyboard
  399. // doesn't support it. :(
  400. }
  401. void toggle_os_mode(void) {
  402. set_os_mode((os_mode + 1) % _OS_MODES_MAX);
  403. }
  404. void keyboard_post_init_user(void) {
  405. set_os_mode(_WINDOWS);
  406. }
  407. bool process_record_user(uint16_t keycode, keyrecord_t *record) {
  408. // We track these persistent globals and manage them on our own, rather than trying to rely on
  409. // get_mods or the like, because this function is called *before* that's updated!
  410. static bool shift_held = false;
  411. static bool alt_held = false;
  412. static bool ctrl_held = false;
  413. static bool super_held = false;
  414. // These are where we remember the values of lock states.
  415. static bool shift_lock = false;
  416. static uint8_t layer_lock = _QWERTY; // The currently locked layer
  417. static uint8_t next_layer_lock = _QWERTY; // Used when layer_lock is held
  418. // Which layer select key is currently being held down. _QWERTY is equivalent to "none."
  419. static uint8_t layer_select_held = _QWERTY;
  420. // When the hold on the platform key started
  421. static uint16_t platform_hold_start = 0;
  422. // The accent request, or zero if there isn't one.
  423. static uint16_t accent_request = 0;
  424. // What kind of key we're striking right now, so that we know what to do if any accent requests
  425. // are hanging around.
  426. uint8_t key_type = _NORMAL_KEY;
  427. // The layer selection and locking logic is:
  428. // * By default, the current layer is given by saved value layer_lock.
  429. // * If a layer select key is held down, we update the current layer to that value.
  430. // (But special thing: If the current layer lock is <layer> and you hit the select key
  431. // for <layer>, it instead toggles the current layer back to _QWERTY! That way you can
  432. // insert some QWERTY keys in the midst of other-layer text.)
  433. // * If the KC_LAYER_LOCK key is held down and a layer select key gets pressed, we update
  434. // next_layer_lock to that selected layer. When KC_LAYER_LOCK is released, we update
  435. // layer_lock to next_layer_lock. Note that that simply tapping KC_LAYER_LOCK resets
  436. // layer_lock to _QWERTY.
  437. // * After all of this is done, we check if shift is held (via either shift or caps lock);
  438. // if it is, and our current layer isn't _QWERTY, then we bump the current layer ID by 1
  439. // to get the shifted layer.
  440. // Step 1: Process various interesting keycodes, especially ones that update our running
  441. // state variables.
  442. switch (keycode) {
  443. // Monitoring the modifier keys, because we'll need them for our logic!
  444. case KC_LSFT:
  445. case KC_RSFT:
  446. shift_held = record->event.pressed;
  447. key_type = _MODIFIER_KEY;
  448. break;
  449. case KC_CAPS:
  450. // If we're in QWERTY mode, caps lock is already going to be managed by the host OS, but by
  451. // tracking it ourselves we can also usefully apply it to the GREEK and CADET layers.
  452. shift_lock = !shift_lock;
  453. key_type = _MODIFIER_KEY;
  454. break;
  455. case KC_LALT:
  456. case KC_RALT:
  457. alt_held = record->event.pressed;
  458. key_type = _MODIFIER_KEY;
  459. break;
  460. case KC_LCTL:
  461. case KC_RCTL:
  462. ctrl_held = record->event.pressed;
  463. key_type = _MODIFIER_KEY;
  464. break;
  465. case KC_LGUI:
  466. case KC_RGUI:
  467. super_held = record->event.pressed;
  468. key_type = _MODIFIER_KEY;
  469. break;
  470. case KC_LAYER_LOCK:
  471. if (record->event.pressed) {
  472. // On press, get ready for a layer selection.
  473. next_layer_lock = _QWERTY;
  474. } else {
  475. // On release, propagate next_layer_lock to layer_lock.
  476. layer_lock = next_layer_lock;
  477. }
  478. key_type = _MODIFIER_KEY;
  479. break;
  480. // Layer selectors
  481. case KC_GREEK:
  482. if (record->event.pressed) {
  483. layer_select_held = _GREEK;
  484. next_layer_lock = _GREEK;
  485. } else {
  486. layer_select_held = _QWERTY;
  487. }
  488. key_type = _MODIFIER_KEY;
  489. break;
  490. case KC_CADET:
  491. if (record->event.pressed) {
  492. layer_select_held = _CADET;
  493. next_layer_lock = _CADET;
  494. } else {
  495. layer_select_held = _QWERTY;
  496. }
  497. key_type = _MODIFIER_KEY;
  498. break;
  499. case KC_YIDDISH:
  500. if (record->event.pressed) {
  501. layer_select_held = _YIDDISH;
  502. next_layer_lock = _YIDDISH;
  503. } else {
  504. layer_select_held = _QWERTY;
  505. }
  506. key_type = _MODIFIER_KEY;
  507. break;
  508. // Accent selectors
  509. case KC_CGRV:
  510. case KC_CAGU:
  511. case KC_CDIA:
  512. case KC_CCIR:
  513. case KC_CCED:
  514. case KC_CTIL:
  515. // The accent request keys normally update accent_request (whose effect will trigger the next
  516. // time we see a "normal" key pressed). However, shift+accent request will instead immediately
  517. // generate the Unicode combining accent symbol instead.
  518. if (shift_held) {
  519. register_unicode(pgm_read_word(combined_accents + keycode - KC_ACCENT_START));
  520. return false;
  521. } else {
  522. accent_request = keycode;
  523. }
  524. key_type = _MODIFIER_KEY;
  525. break;
  526. // Our special keycodes
  527. case KC_PLATFORM:
  528. if (record->event.pressed) {
  529. platform_hold_start = record->event.time;
  530. } else if (platform_hold_start != 0 && record->event.time - platform_hold_start > PLATFORM_HOLD_DURATION) {
  531. toggle_os_mode();
  532. }
  533. key_type = _SPECIAL_KEY;
  534. return true;
  535. case KC_VC_MUTE:
  536. if (record->event.pressed) {
  537. send_string(VC_MUTE_VALUES[os_mode]);
  538. return true;
  539. }
  540. key_type = _SPECIAL_KEY;
  541. break;
  542. case KC_VC_HAND:
  543. if (record->event.pressed) {
  544. send_string(VC_HAND_VALUES[os_mode]);
  545. return true;
  546. }
  547. key_type = _SPECIAL_KEY;
  548. break;
  549. case KC_SCRNSHT:
  550. if (record->event.pressed) {
  551. send_string(SCRNSHT_VALUES[os_mode]);
  552. return true;
  553. }
  554. key_type = _SPECIAL_KEY;
  555. break;
  556. case QK_BOOT:
  557. key_type = _SPECIAL_KEY;
  558. break;
  559. }
  560. // Step 2: Finalize current_layer and update the QMK layer state.
  561. const bool shifted = (shift_held != shift_lock);
  562. const uint8_t current_layer = update_layer(layer_lock, layer_select_held, shifted);
  563. // Step 3: Handle accents.
  564. bool handled = false;
  565. if (accent_request && record->event.pressed) {
  566. // If we're in any layer other than _QWERTY, or a modifier key is being held down,
  567. // then we're actually generating a special key, not a normal one.
  568. if (key_type == _NORMAL_KEY &&
  569. (current_layer != _QWERTY || ctrl_held || super_held || alt_held)) {
  570. key_type = _SPECIAL_KEY;
  571. }
  572. switch (key_type) {
  573. case _NORMAL_KEY:
  574. handled = process_key_after_accent(accent_request, keycode, shifted);
  575. accent_request = 0;
  576. break;
  577. case _SPECIAL_KEY:
  578. accent_request = 0;
  579. break;
  580. case _MODIFIER_KEY:
  581. break;
  582. }
  583. }
  584. return !handled;
  585. }