You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

386 lines
11 KiB

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