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.

392 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. #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. __attribute__((weak)) void unicode_input_mode_set_user(uint8_t input_mode) {}
  66. __attribute__((weak)) void unicode_input_mode_set_kb(uint8_t input_mode) {
  67. unicode_input_mode_set_user(input_mode);
  68. }
  69. #ifdef AUDIO_ENABLE
  70. # ifdef UNICODE_SONG_MAC
  71. static float song_mac[][2] = UNICODE_SONG_MAC;
  72. # endif
  73. # ifdef UNICODE_SONG_LNX
  74. static float song_lnx[][2] = UNICODE_SONG_LNX;
  75. # endif
  76. # ifdef UNICODE_SONG_WIN
  77. static float song_win[][2] = UNICODE_SONG_WIN;
  78. # endif
  79. # ifdef UNICODE_SONG_BSD
  80. static float song_bsd[][2] = UNICODE_SONG_BSD;
  81. # endif
  82. # ifdef UNICODE_SONG_WINC
  83. static float song_winc[][2] = UNICODE_SONG_WINC;
  84. # endif
  85. # ifdef UNICODE_SONG_EMACS
  86. static float song_emacs[][2] = UNICODE_SONG_EMACS;
  87. # endif
  88. static void unicode_play_song(uint8_t mode) {
  89. switch (mode) {
  90. # ifdef UNICODE_SONG_MAC
  91. case UNICODE_MODE_MACOS:
  92. PLAY_SONG(song_mac);
  93. break;
  94. # endif
  95. # ifdef UNICODE_SONG_LNX
  96. case UNICODE_MODE_LINUX:
  97. PLAY_SONG(song_lnx);
  98. break;
  99. # endif
  100. # ifdef UNICODE_SONG_WIN
  101. case UNICODE_MODE_WINDOWS:
  102. PLAY_SONG(song_win);
  103. break;
  104. # endif
  105. # ifdef UNICODE_SONG_BSD
  106. case UNICODE_MODE_BSD:
  107. PLAY_SONG(song_bsd);
  108. break;
  109. # endif
  110. # ifdef UNICODE_SONG_WINC
  111. case UNICODE_MODE_WINCOMPOSE:
  112. PLAY_SONG(song_winc);
  113. break;
  114. # endif
  115. # ifdef UNICODE_SONG_EMACS
  116. case UNICODE_MODE_EMACS:
  117. PLAY_SONG(song_emacs);
  118. break;
  119. # endif
  120. }
  121. }
  122. #endif
  123. void unicode_input_mode_init(void) {
  124. unicode_config.raw = eeprom_read_byte(EECONFIG_UNICODEMODE);
  125. #if UNICODE_SELECTED_MODES != -1
  126. # if UNICODE_CYCLE_PERSIST
  127. // Find input_mode in selected modes
  128. int8_t i;
  129. for (i = 0; i < selected_count; i++) {
  130. if (selected[i] == unicode_config.input_mode) {
  131. selected_index = i;
  132. break;
  133. }
  134. }
  135. if (i == selected_count) {
  136. // Not found: input_mode isn't selected, change to one that is
  137. unicode_config.input_mode = selected[selected_index = 0];
  138. }
  139. # else
  140. // Always change to the first selected input mode
  141. unicode_config.input_mode = selected[selected_index = 0];
  142. # endif
  143. #endif
  144. unicode_input_mode_set_kb(unicode_config.input_mode);
  145. dprintf("Unicode input mode init to: %u\n", unicode_config.input_mode);
  146. }
  147. uint8_t get_unicode_input_mode(void) {
  148. return unicode_config.input_mode;
  149. }
  150. static void persist_unicode_input_mode(void) {
  151. eeprom_update_byte(EECONFIG_UNICODEMODE, unicode_config.input_mode);
  152. }
  153. void set_unicode_input_mode(uint8_t mode) {
  154. unicode_config.input_mode = mode;
  155. persist_unicode_input_mode();
  156. #ifdef AUDIO_ENABLE
  157. unicode_play_song(mode);
  158. #endif
  159. unicode_input_mode_set_kb(mode);
  160. dprintf("Unicode input mode set to: %u\n", unicode_config.input_mode);
  161. }
  162. static void cycle_unicode_input_mode(int8_t offset) {
  163. #if UNICODE_SELECTED_MODES != -1
  164. selected_index = (selected_index + offset) % selected_count;
  165. if (selected_index < 0) {
  166. selected_index += selected_count;
  167. }
  168. unicode_config.input_mode = selected[selected_index];
  169. # if UNICODE_CYCLE_PERSIST
  170. persist_unicode_input_mode();
  171. # endif
  172. # ifdef AUDIO_ENABLE
  173. unicode_play_song(unicode_config.input_mode);
  174. # endif
  175. unicode_input_mode_set_kb(unicode_config.input_mode);
  176. dprintf("Unicode input mode cycle to: %u\n", unicode_config.input_mode);
  177. #endif
  178. }
  179. void unicode_input_mode_step(void) {
  180. cycle_unicode_input_mode(1);
  181. }
  182. void unicode_input_mode_step_reverse(void) {
  183. cycle_unicode_input_mode(-1);
  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 == UNICODE_MODE_LINUX && 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 UNICODE_MODE_MACOS:
  199. register_code(UNICODE_KEY_MAC);
  200. break;
  201. case UNICODE_MODE_LINUX:
  202. tap_code16(UNICODE_KEY_LNX);
  203. break;
  204. case UNICODE_MODE_WINDOWS:
  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 UNICODE_MODE_WINCOMPOSE:
  214. tap_code(UNICODE_KEY_WINC);
  215. tap_code(KC_U);
  216. break;
  217. case UNICODE_MODE_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 UNICODE_MODE_MACOS:
  229. unregister_code(UNICODE_KEY_MAC);
  230. break;
  231. case UNICODE_MODE_LINUX:
  232. tap_code(KC_SPACE);
  233. if (unicode_saved_led_state.caps_lock) {
  234. tap_code(KC_CAPS_LOCK);
  235. }
  236. break;
  237. case UNICODE_MODE_WINDOWS:
  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 UNICODE_MODE_WINCOMPOSE:
  244. tap_code(KC_ENTER);
  245. break;
  246. case UNICODE_MODE_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 UNICODE_MODE_MACOS:
  255. unregister_code(UNICODE_KEY_MAC);
  256. break;
  257. case UNICODE_MODE_LINUX:
  258. tap_code(KC_ESCAPE);
  259. if (unicode_saved_led_state.caps_lock) {
  260. tap_code(KC_CAPS_LOCK);
  261. }
  262. break;
  263. case UNICODE_MODE_WINCOMPOSE:
  264. tap_code(KC_ESCAPE);
  265. break;
  266. case UNICODE_MODE_WINDOWS:
  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 UNICODE_MODE_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 == UNICODE_MODE_WINDOWS) {
  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 == UNICODE_MODE_WINCOMPOSE);
  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 == UNICODE_MODE_WINDOWS)) {
  319. // Code point out of range, do nothing
  320. return;
  321. }
  322. unicode_input_start();
  323. if (code_point > 0xFFFF && unicode_config.input_mode == UNICODE_MODE_MACOS) {
  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. }