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