]> git.donarmstrong.com Git - qmk_firmware.git/blob - quantum/process_keycode/process_unicode.c
Merge remote-tracking branch 'refs/remotes/qmk/master'
[qmk_firmware.git] / quantum / process_keycode / process_unicode.c
1 #include "process_unicode.h"
2 #include "action_util.h"
3
4 static uint8_t input_mode;
5 uint8_t mods;
6
7 __attribute__((weak))
8 uint16_t hex_to_keycode(uint8_t hex)
9 {
10   if (hex == 0x0) {
11     return KC_0;
12   } else if (hex < 0xA) {
13     return KC_1 + (hex - 0x1);
14   } else {
15     return KC_A + (hex - 0xA);
16   }
17 }
18
19 void set_unicode_input_mode(uint8_t os_target)
20 {
21   input_mode = os_target;
22 }
23
24 uint8_t get_unicode_input_mode(void) {
25   return input_mode;
26 }
27
28 __attribute__((weak))
29 void unicode_input_start (void) {
30   // save current mods
31   mods = keyboard_report->mods;
32
33   // unregister all mods to start from clean state
34   if (mods & MOD_BIT(KC_LSFT)) unregister_code(KC_LSFT);
35   if (mods & MOD_BIT(KC_RSFT)) unregister_code(KC_RSFT);
36   if (mods & MOD_BIT(KC_LCTL)) unregister_code(KC_LCTL);
37   if (mods & MOD_BIT(KC_RCTL)) unregister_code(KC_RCTL);
38   if (mods & MOD_BIT(KC_LALT)) unregister_code(KC_LALT);
39   if (mods & MOD_BIT(KC_RALT)) unregister_code(KC_RALT);
40   if (mods & MOD_BIT(KC_LGUI)) unregister_code(KC_LGUI);
41   if (mods & MOD_BIT(KC_RGUI)) unregister_code(KC_RGUI);
42
43   switch(input_mode) {
44   case UC_OSX:
45     register_code(KC_LALT);
46     break;
47   case UC_LNX:
48     register_code(KC_LCTL);
49     register_code(KC_LSFT);
50     register_code(KC_U);
51     unregister_code(KC_U);
52     unregister_code(KC_LSFT);
53     unregister_code(KC_LCTL);
54     break;
55   case UC_WIN:
56     register_code(KC_LALT);
57     register_code(KC_PPLS);
58     unregister_code(KC_PPLS);
59     break;
60   case UC_WINC:
61     register_code(KC_RALT);
62     unregister_code(KC_RALT);
63     register_code(KC_U);
64     unregister_code(KC_U);
65   }
66   wait_ms(UNICODE_TYPE_DELAY);
67 }
68
69 __attribute__((weak))
70 void unicode_input_finish (void) {
71   switch(input_mode) {
72     case UC_OSX:
73     case UC_WIN:
74       unregister_code(KC_LALT);
75       break;
76     case UC_LNX:
77       register_code(KC_SPC);
78       unregister_code(KC_SPC);
79       break;
80   }
81
82   // reregister previously set mods
83   if (mods & MOD_BIT(KC_LSFT)) register_code(KC_LSFT);
84   if (mods & MOD_BIT(KC_RSFT)) register_code(KC_RSFT);
85   if (mods & MOD_BIT(KC_LCTL)) register_code(KC_LCTL);
86   if (mods & MOD_BIT(KC_RCTL)) register_code(KC_RCTL);
87   if (mods & MOD_BIT(KC_LALT)) register_code(KC_LALT);
88   if (mods & MOD_BIT(KC_RALT)) register_code(KC_RALT);
89   if (mods & MOD_BIT(KC_LGUI)) register_code(KC_LGUI);
90   if (mods & MOD_BIT(KC_RGUI)) register_code(KC_RGUI);
91 }
92
93 void register_hex(uint16_t hex) {
94   for(int i = 3; i >= 0; i--) {
95     uint8_t digit = ((hex >> (i*4)) & 0xF);
96     register_code(hex_to_keycode(digit));
97     unregister_code(hex_to_keycode(digit));
98   }
99 }
100
101 bool process_unicode(uint16_t keycode, keyrecord_t *record) {
102   if (keycode > QK_UNICODE && record->event.pressed) {
103     uint16_t unicode = keycode & 0x7FFF;
104     unicode_input_start();
105     register_hex(unicode);
106     unicode_input_finish();
107   }
108   return true;
109 }
110
111 #ifdef UNICODEMAP_ENABLE
112 __attribute__((weak))
113 const uint32_t PROGMEM unicode_map[] = {
114 };
115
116 void register_hex32(uint32_t hex) {
117   uint8_t onzerostart = 1;
118   for(int i = 7; i >= 0; i--) {
119     if (i <= 3) {
120       onzerostart = 0;
121     }
122     uint8_t digit = ((hex >> (i*4)) & 0xF);
123     if (digit == 0) {
124       if (onzerostart == 0) {
125         register_code(hex_to_keycode(digit));
126         unregister_code(hex_to_keycode(digit));
127       }
128     } else {
129       register_code(hex_to_keycode(digit));
130       unregister_code(hex_to_keycode(digit));
131       onzerostart = 0;
132     }
133   }
134 }
135
136 __attribute__((weak))
137 void unicode_map_input_error() {}
138
139 bool process_unicode_map(uint16_t keycode, keyrecord_t *record) {
140   if ((keycode & QK_UNICODE_MAP) == QK_UNICODE_MAP && record->event.pressed) {
141     const uint32_t* map = unicode_map;
142     uint16_t index = keycode - QK_UNICODE_MAP;
143     uint32_t code = pgm_read_dword_far(&map[index]);
144     if (code > 0xFFFF && code <= 0x10ffff && input_mode == UC_OSX) {
145       // Convert to UTF-16 surrogate pair
146       code -= 0x10000;
147       uint32_t lo = code & 0x3ff;
148       uint32_t hi = (code & 0xffc00) >> 10;
149       unicode_input_start();
150       register_hex32(hi + 0xd800);
151       register_hex32(lo + 0xdc00);
152       unicode_input_finish();
153     } else if ((code > 0x10ffff && input_mode == UC_OSX) || (code > 0xFFFFF && input_mode == UC_LNX)) {
154       // when character is out of range supported by the OS
155       unicode_map_input_error();
156     } else {
157       unicode_input_start();
158       register_hex32(code);
159       unicode_input_finish();
160     }
161   }
162   return true;
163 }
164 #endif
165
166 #ifdef UCIS_ENABLE
167 qk_ucis_state_t qk_ucis_state;
168
169 void qk_ucis_start(void) {
170   qk_ucis_state.count = 0;
171   qk_ucis_state.in_progress = true;
172
173   qk_ucis_start_user();
174 }
175
176 __attribute__((weak))
177 void qk_ucis_start_user(void) {
178   unicode_input_start();
179   register_hex(0x2328);
180   unicode_input_finish();
181 }
182
183 static bool is_uni_seq(char *seq) {
184   uint8_t i;
185
186   for (i = 0; seq[i]; i++) {
187     uint16_t code;
188     if (('1' <= seq[i]) && (seq[i] <= '0'))
189       code = seq[i] - '1' + KC_1;
190     else
191       code = seq[i] - 'a' + KC_A;
192
193     if (i > qk_ucis_state.count || qk_ucis_state.codes[i] != code)
194       return false;
195   }
196
197   return (qk_ucis_state.codes[i] == KC_ENT ||
198           qk_ucis_state.codes[i] == KC_SPC);
199 }
200
201 __attribute__((weak))
202 void qk_ucis_symbol_fallback (void) {
203   for (uint8_t i = 0; i < qk_ucis_state.count - 1; i++) {
204     uint8_t code = qk_ucis_state.codes[i];
205     register_code(code);
206     unregister_code(code);
207     wait_ms(UNICODE_TYPE_DELAY);
208   }
209 }
210
211 void register_ucis(const char *hex) {
212   for(int i = 0; hex[i]; i++) {
213     uint8_t kc = 0;
214     char c = hex[i];
215
216     switch (c) {
217     case '0':
218       kc = KC_0;
219       break;
220     case '1' ... '9':
221       kc = c - '1' + KC_1;
222       break;
223     case 'a' ... 'f':
224       kc = c - 'a' + KC_A;
225       break;
226     case 'A' ... 'F':
227       kc = c - 'A' + KC_A;
228       break;
229     }
230
231     if (kc) {
232       register_code (kc);
233       unregister_code (kc);
234       wait_ms (UNICODE_TYPE_DELAY);
235     }
236   }
237 }
238
239 bool process_ucis (uint16_t keycode, keyrecord_t *record) {
240   uint8_t i;
241
242   if (!qk_ucis_state.in_progress)
243     return true;
244
245   if (qk_ucis_state.count >= UCIS_MAX_SYMBOL_LENGTH &&
246       !(keycode == KC_BSPC || keycode == KC_ESC || keycode == KC_SPC || keycode == KC_ENT)) {
247     return false;
248   }
249
250   if (!record->event.pressed)
251     return true;
252
253   qk_ucis_state.codes[qk_ucis_state.count] = keycode;
254   qk_ucis_state.count++;
255
256   if (keycode == KC_BSPC) {
257     if (qk_ucis_state.count >= 2) {
258       qk_ucis_state.count -= 2;
259       return true;
260     } else {
261       qk_ucis_state.count--;
262       return false;
263     }
264   }
265
266   if (keycode == KC_ENT || keycode == KC_SPC || keycode == KC_ESC) {
267     bool symbol_found = false;
268
269     for (i = qk_ucis_state.count; i > 0; i--) {
270       register_code (KC_BSPC);
271       unregister_code (KC_BSPC);
272       wait_ms(UNICODE_TYPE_DELAY);
273     }
274
275     if (keycode == KC_ESC) {
276       qk_ucis_state.in_progress = false;
277       return false;
278     }
279
280     unicode_input_start();
281     for (i = 0; ucis_symbol_table[i].symbol; i++) {
282       if (is_uni_seq (ucis_symbol_table[i].symbol)) {
283         symbol_found = true;
284         register_ucis(ucis_symbol_table[i].code + 2);
285         break;
286       }
287     }
288     if (!symbol_found) {
289       qk_ucis_symbol_fallback();
290     }
291     unicode_input_finish();
292
293     qk_ucis_state.in_progress = false;
294     return false;
295   }
296   return true;
297 }
298 #endif