unicode.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. /* Copyright 2022
  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 "unicode.h"
  17. #include "eeconfig.h"
  18. #include "action.h"
  19. #include "action_util.h"
  20. #include "host.h"
  21. #include "keycode.h"
  22. #include "wait.h"
  23. #include "send_string.h"
  24. #include "utf8.h"
  25. #include "debug.h"
  26. #include "quantum.h"
  27. #if defined(AUDIO_ENABLE)
  28. # include "audio.h"
  29. #endif
  30. #if defined(UNICODE_ENABLE) + defined(UNICODEMAP_ENABLE) + defined(UCIS_ENABLE) > 1
  31. # error "Cannot enable more than one Unicode method (UNICODE, UNICODEMAP, UCIS) at the same time"
  32. #endif
  33. // Keycodes used for starting Unicode input on different platforms
  34. #ifndef UNICODE_KEY_MAC
  35. # define UNICODE_KEY_MAC KC_LEFT_ALT
  36. #endif
  37. #ifndef UNICODE_KEY_LNX
  38. # define UNICODE_KEY_LNX LCTL(LSFT(KC_U))
  39. #endif
  40. #ifndef UNICODE_KEY_WINC
  41. # define UNICODE_KEY_WINC KC_RIGHT_ALT
  42. #endif
  43. // Whether input mode changes in cycle should be written to EEPROM
  44. #ifndef UNICODE_CYCLE_PERSIST
  45. # define UNICODE_CYCLE_PERSIST true
  46. #endif
  47. // Delay between starting Unicode input and sending a sequence, in ms
  48. #ifndef UNICODE_TYPE_DELAY
  49. # define UNICODE_TYPE_DELAY 10
  50. #endif
  51. unicode_config_t unicode_config;
  52. uint8_t unicode_saved_mods;
  53. led_t unicode_saved_led_state;
  54. #ifdef UNICODE_SELECTED_MODES
  55. static uint8_t selected[] = {UNICODE_SELECTED_MODES};
  56. static int8_t selected_count = ARRAY_SIZE(selected);
  57. static int8_t selected_index;
  58. #endif
  59. __attribute__((weak)) void unicode_input_mode_set_user(uint8_t input_mode) {}
  60. __attribute__((weak)) void unicode_input_mode_set_kb(uint8_t input_mode) {
  61. unicode_input_mode_set_user(input_mode);
  62. }
  63. #ifdef AUDIO_ENABLE
  64. # ifdef UNICODE_SONG_MAC
  65. static float song_mac[][2] = UNICODE_SONG_MAC;
  66. # endif
  67. # ifdef UNICODE_SONG_LNX
  68. static float song_lnx[][2] = UNICODE_SONG_LNX;
  69. # endif
  70. # ifdef UNICODE_SONG_WIN
  71. static float song_win[][2] = UNICODE_SONG_WIN;
  72. # endif
  73. # ifdef UNICODE_SONG_BSD
  74. static float song_bsd[][2] = UNICODE_SONG_BSD;
  75. # endif
  76. # ifdef UNICODE_SONG_WINC
  77. static float song_winc[][2] = UNICODE_SONG_WINC;
  78. # endif
  79. # ifdef UNICODE_SONG_EMACS
  80. static float song_emacs[][2] = UNICODE_SONG_EMACS;
  81. # endif
  82. static void unicode_play_song(uint8_t mode) {
  83. switch (mode) {
  84. # ifdef UNICODE_SONG_MAC
  85. case UNICODE_MODE_MACOS:
  86. PLAY_SONG(song_mac);
  87. break;
  88. # endif
  89. # ifdef UNICODE_SONG_LNX
  90. case UNICODE_MODE_LINUX:
  91. PLAY_SONG(song_lnx);
  92. break;
  93. # endif
  94. # ifdef UNICODE_SONG_WIN
  95. case UNICODE_MODE_WINDOWS:
  96. PLAY_SONG(song_win);
  97. break;
  98. # endif
  99. # ifdef UNICODE_SONG_BSD
  100. case UNICODE_MODE_BSD:
  101. PLAY_SONG(song_bsd);
  102. break;
  103. # endif
  104. # ifdef UNICODE_SONG_WINC
  105. case UNICODE_MODE_WINCOMPOSE:
  106. PLAY_SONG(song_winc);
  107. break;
  108. # endif
  109. # ifdef UNICODE_SONG_EMACS
  110. case UNICODE_MODE_EMACS:
  111. PLAY_SONG(song_emacs);
  112. break;
  113. # endif
  114. }
  115. }
  116. #endif
  117. void unicode_input_mode_init(void) {
  118. eeconfig_read_unicode_mode(&unicode_config);
  119. #ifdef UNICODE_SELECTED_MODES
  120. # if UNICODE_CYCLE_PERSIST
  121. // Find input_mode in selected modes
  122. int8_t i;
  123. for (i = 0; i < selected_count; i++) {
  124. if (selected[i] == unicode_config.input_mode) {
  125. selected_index = i;
  126. break;
  127. }
  128. }
  129. if (i == selected_count) {
  130. // Not found: input_mode isn't selected, change to one that is
  131. unicode_config.input_mode = selected[selected_index = 0];
  132. }
  133. # else
  134. // Always change to the first selected input mode
  135. unicode_config.input_mode = selected[selected_index = 0];
  136. # endif
  137. #endif
  138. unicode_input_mode_set_kb(unicode_config.input_mode);
  139. dprintf("Unicode input mode init to: %u\n", unicode_config.input_mode);
  140. }
  141. uint8_t get_unicode_input_mode(void) {
  142. return unicode_config.input_mode;
  143. }
  144. static void persist_unicode_input_mode(void) {
  145. eeconfig_update_unicode_mode(&unicode_config);
  146. }
  147. void set_unicode_input_mode(uint8_t mode) {
  148. unicode_config.input_mode = mode;
  149. persist_unicode_input_mode();
  150. #ifdef AUDIO_ENABLE
  151. unicode_play_song(mode);
  152. #endif
  153. unicode_input_mode_set_kb(mode);
  154. dprintf("Unicode input mode set to: %u\n", unicode_config.input_mode);
  155. }
  156. static void cycle_unicode_input_mode(int8_t offset) {
  157. #ifdef UNICODE_SELECTED_MODES
  158. selected_index = (selected_index + offset) % selected_count;
  159. if (selected_index < 0) {
  160. selected_index += selected_count;
  161. }
  162. unicode_config.input_mode = selected[selected_index];
  163. # if UNICODE_CYCLE_PERSIST
  164. persist_unicode_input_mode();
  165. # endif
  166. # ifdef AUDIO_ENABLE
  167. unicode_play_song(unicode_config.input_mode);
  168. # endif
  169. unicode_input_mode_set_kb(unicode_config.input_mode);
  170. dprintf("Unicode input mode cycle to: %u\n", unicode_config.input_mode);
  171. #endif
  172. }
  173. void unicode_input_mode_step(void) {
  174. cycle_unicode_input_mode(1);
  175. }
  176. void unicode_input_mode_step_reverse(void) {
  177. cycle_unicode_input_mode(-1);
  178. }
  179. __attribute__((weak)) void unicode_input_start(void) {
  180. unicode_saved_led_state = host_keyboard_led_state();
  181. // Note the order matters here!
  182. // Need to do this before we mess around with the mods, or else
  183. // UNICODE_KEY_LNX (which is usually Ctrl-Shift-U) might not work
  184. // correctly in the shifted case.
  185. if (unicode_config.input_mode == UNICODE_MODE_LINUX && unicode_saved_led_state.caps_lock) {
  186. tap_code(KC_CAPS_LOCK);
  187. }
  188. unicode_saved_mods = get_mods(); // Save current mods
  189. clear_mods(); // Unregister mods to start from a clean state
  190. clear_weak_mods();
  191. switch (unicode_config.input_mode) {
  192. case UNICODE_MODE_MACOS:
  193. register_code(UNICODE_KEY_MAC);
  194. break;
  195. case UNICODE_MODE_LINUX:
  196. tap_code16(UNICODE_KEY_LNX);
  197. break;
  198. case UNICODE_MODE_WINDOWS:
  199. // For increased reliability, use numpad keys for inputting digits
  200. if (!unicode_saved_led_state.num_lock) {
  201. tap_code(KC_NUM_LOCK);
  202. }
  203. register_code(KC_LEFT_ALT);
  204. wait_ms(UNICODE_TYPE_DELAY);
  205. tap_code(KC_KP_PLUS);
  206. break;
  207. case UNICODE_MODE_WINCOMPOSE:
  208. tap_code(UNICODE_KEY_WINC);
  209. tap_code(KC_U);
  210. break;
  211. case UNICODE_MODE_EMACS:
  212. // The usual way to type unicode in emacs is C-x-8 <RET> then the unicode number in hex
  213. tap_code16(LCTL(KC_X));
  214. tap_code16(KC_8);
  215. tap_code16(KC_ENTER);
  216. break;
  217. }
  218. wait_ms(UNICODE_TYPE_DELAY);
  219. }
  220. __attribute__((weak)) void unicode_input_finish(void) {
  221. switch (unicode_config.input_mode) {
  222. case UNICODE_MODE_MACOS:
  223. unregister_code(UNICODE_KEY_MAC);
  224. break;
  225. case UNICODE_MODE_LINUX:
  226. tap_code(KC_SPACE);
  227. if (unicode_saved_led_state.caps_lock) {
  228. tap_code(KC_CAPS_LOCK);
  229. }
  230. break;
  231. case UNICODE_MODE_WINDOWS:
  232. unregister_code(KC_LEFT_ALT);
  233. if (!unicode_saved_led_state.num_lock) {
  234. tap_code(KC_NUM_LOCK);
  235. }
  236. break;
  237. case UNICODE_MODE_WINCOMPOSE:
  238. tap_code(KC_ENTER);
  239. break;
  240. case UNICODE_MODE_EMACS:
  241. tap_code16(KC_ENTER);
  242. break;
  243. }
  244. set_mods(unicode_saved_mods); // Reregister previously set mods
  245. }
  246. __attribute__((weak)) void unicode_input_cancel(void) {
  247. switch (unicode_config.input_mode) {
  248. case UNICODE_MODE_MACOS:
  249. unregister_code(UNICODE_KEY_MAC);
  250. break;
  251. case UNICODE_MODE_LINUX:
  252. tap_code(KC_ESCAPE);
  253. if (unicode_saved_led_state.caps_lock) {
  254. tap_code(KC_CAPS_LOCK);
  255. }
  256. break;
  257. case UNICODE_MODE_WINCOMPOSE:
  258. tap_code(KC_ESCAPE);
  259. break;
  260. case UNICODE_MODE_WINDOWS:
  261. unregister_code(KC_LEFT_ALT);
  262. if (!unicode_saved_led_state.num_lock) {
  263. tap_code(KC_NUM_LOCK);
  264. }
  265. break;
  266. case UNICODE_MODE_EMACS:
  267. tap_code16(LCTL(KC_G)); // C-g cancels
  268. break;
  269. }
  270. set_mods(unicode_saved_mods); // Reregister previously set mods
  271. }
  272. // clang-format off
  273. static void send_nibble_wrapper(uint8_t digit) {
  274. if (unicode_config.input_mode == UNICODE_MODE_WINDOWS) {
  275. uint8_t kc = digit < 10
  276. ? KC_KP_1 + (10 + digit - 1) % 10
  277. : KC_A + (digit - 10);
  278. tap_code(kc);
  279. return;
  280. }
  281. send_nibble(digit);
  282. }
  283. // clang-format on
  284. void register_hex(uint16_t hex) {
  285. for (int i = 3; i >= 0; i--) {
  286. uint8_t digit = ((hex >> (i * 4)) & 0xF);
  287. send_nibble_wrapper(digit);
  288. }
  289. }
  290. void register_hex32(uint32_t hex) {
  291. bool first_digit = true;
  292. bool needs_leading_zero = (unicode_config.input_mode == UNICODE_MODE_WINCOMPOSE);
  293. for (int i = 7; i >= 0; i--) {
  294. // Work out the digit we're going to transmit
  295. uint8_t digit = ((hex >> (i * 4)) & 0xF);
  296. // If we're still searching for the first digit, and found one
  297. // that needs a leading zero sent out, send the zero.
  298. if (first_digit && needs_leading_zero && digit > 9) {
  299. send_nibble_wrapper(0);
  300. }
  301. // Always send digits (including zero) if we're down to the last
  302. // two bytes of nibbles.
  303. bool must_send = i < 4;
  304. // If we've found a digit worth transmitting, do so.
  305. if (digit != 0 || !first_digit || must_send) {
  306. send_nibble_wrapper(digit);
  307. first_digit = false;
  308. }
  309. }
  310. }
  311. void register_unicode(uint32_t code_point) {
  312. if (code_point > 0x10FFFF || (code_point > 0xFFFF && unicode_config.input_mode == UNICODE_MODE_WINDOWS)) {
  313. // Code point out of range, do nothing
  314. return;
  315. }
  316. unicode_input_start();
  317. if (code_point > 0xFFFF && unicode_config.input_mode == UNICODE_MODE_MACOS) {
  318. // Convert code point to UTF-16 surrogate pair on macOS
  319. code_point -= 0x10000;
  320. uint32_t lo = code_point & 0x3FF, hi = (code_point & 0xFFC00) >> 10;
  321. register_hex32(hi + 0xD800);
  322. register_hex32(lo + 0xDC00);
  323. } else {
  324. register_hex32(code_point);
  325. }
  326. unicode_input_finish();
  327. }
  328. void send_unicode_string(const char *str) {
  329. if (!str) {
  330. return;
  331. }
  332. while (*str) {
  333. int32_t code_point = 0;
  334. str = decode_utf8(str, &code_point);
  335. if (code_point >= 0) {
  336. register_unicode(code_point);
  337. }
  338. }
  339. }