unicode.c 11 KB

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