summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan <fauxpark@gmail.com>2022-09-13 01:49:04 +1000
committerGitHub <noreply@github.com>2022-09-12 08:49:04 -0700
commit3d667f09705fa780bd5881cfa3b3cb10fa41b1fe (patch)
treeb05d0a4cd413947c1ae09fc08c33f2411029d29e
parent4087251da6ffcbfd16a9b655b7816803a565f0a6 (diff)
Refactor Unicode feature (#18333)
-rw-r--r--builddefs/common_features.mk4
-rw-r--r--quantum/painter/rules.mk5
-rw-r--r--quantum/process_keycode/process_ucis.c17
-rw-r--r--quantum/process_keycode/process_ucis.h6
-rw-r--r--quantum/process_keycode/process_unicode.c12
-rw-r--r--quantum/process_keycode/process_unicode.h5
-rw-r--r--quantum/process_keycode/process_unicode_common.c315
-rw-r--r--quantum/process_keycode/process_unicode_common.h178
-rw-r--r--quantum/process_keycode/process_unicodemap.c5
-rw-r--r--quantum/process_keycode/process_unicodemap.h6
-rw-r--r--quantum/quantum.h1
-rw-r--r--quantum/unicode/unicode.c376
-rw-r--r--quantum/unicode/unicode.h165
-rw-r--r--quantum/unicode/utf8.c (renamed from quantum/utf8.c)0
-rw-r--r--quantum/unicode/utf8.h (renamed from quantum/utf8.h)2
15 files changed, 591 insertions, 506 deletions
diff --git a/builddefs/common_features.mk b/builddefs/common_features.mk
index f9618709c9..3d34c673d3 100644
--- a/builddefs/common_features.mk
+++ b/builddefs/common_features.mk
@@ -773,8 +773,10 @@ endif
773 773
774ifeq ($(strip $(UNICODE_COMMON)), yes) 774ifeq ($(strip $(UNICODE_COMMON)), yes)
775 OPT_DEFS += -DUNICODE_COMMON_ENABLE 775 OPT_DEFS += -DUNICODE_COMMON_ENABLE
776 COMMON_VPATH += $(QUANTUM_DIR)/unicode
776 SRC += $(QUANTUM_DIR)/process_keycode/process_unicode_common.c \ 777 SRC += $(QUANTUM_DIR)/process_keycode/process_unicode_common.c \
777 $(QUANTUM_DIR)/utf8.c 778 $(QUANTUM_DIR)/unicode/unicode.c \
779 $(QUANTUM_DIR)/unicode/utf8.c
778endif 780endif
779 781
780MAGIC_ENABLE ?= yes 782MAGIC_ENABLE ?= yes
diff --git a/quantum/painter/rules.mk b/quantum/painter/rules.mk
index 91787dfe0e..4420bccf63 100644
--- a/quantum/painter/rules.mk
+++ b/quantum/painter/rules.mk
@@ -8,9 +8,10 @@ VALID_QUANTUM_PAINTER_DRIVERS := ili9163_spi ili9341_spi ili9488_spi st7789_spi
8#------------------------------------------------------------------------------- 8#-------------------------------------------------------------------------------
9 9
10OPT_DEFS += -DQUANTUM_PAINTER_ENABLE 10OPT_DEFS += -DQUANTUM_PAINTER_ENABLE
11COMMON_VPATH += $(QUANTUM_DIR)/painter 11COMMON_VPATH += $(QUANTUM_DIR)/painter \
12 $(QUANTUM_DIR)/unicode
12SRC += \ 13SRC += \
13 $(QUANTUM_DIR)/utf8.c \ 14 $(QUANTUM_DIR)/unicode/utf8.c \
14 $(QUANTUM_DIR)/color.c \ 15 $(QUANTUM_DIR)/color.c \
15 $(QUANTUM_DIR)/painter/qp.c \ 16 $(QUANTUM_DIR)/painter/qp.c \
16 $(QUANTUM_DIR)/painter/qp_stream.c \ 17 $(QUANTUM_DIR)/painter/qp_stream.c \
diff --git a/quantum/process_keycode/process_ucis.c b/quantum/process_keycode/process_ucis.c
index 6a8d8f0ff6..646471bc4d 100644
--- a/quantum/process_keycode/process_ucis.c
+++ b/quantum/process_keycode/process_ucis.c
@@ -15,6 +15,9 @@
15 */ 15 */
16 16
17#include "process_ucis.h" 17#include "process_ucis.h"
18#include "unicode.h"
19#include "keycode.h"
20#include "wait.h"
18 21
19qk_ucis_state_t qk_ucis_state; 22qk_ucis_state_t qk_ucis_state;
20 23
@@ -26,9 +29,7 @@ void qk_ucis_start(void) {
26} 29}
27 30
28__attribute__((weak)) void qk_ucis_start_user(void) { 31__attribute__((weak)) void qk_ucis_start_user(void) {
29 unicode_input_start(); 32 register_unicode(0x2328); // ⌨
30 register_hex(0x2328); // ⌨
31 unicode_input_finish();
32} 33}
33 34
34__attribute__((weak)) void qk_ucis_success(uint8_t symbol_index) {} 35__attribute__((weak)) void qk_ucis_success(uint8_t symbol_index) {}
@@ -51,10 +52,7 @@ static bool is_uni_seq(char *seq) {
51 52
52__attribute__((weak)) void qk_ucis_symbol_fallback(void) { 53__attribute__((weak)) void qk_ucis_symbol_fallback(void) {
53 for (uint8_t i = 0; i < qk_ucis_state.count - 1; i++) { 54 for (uint8_t i = 0; i < qk_ucis_state.count - 1; i++) {
54 uint8_t keycode = qk_ucis_state.codes[i]; 55 tap_code(qk_ucis_state.codes[i]);
55 register_code(keycode);
56 unregister_code(keycode);
57 wait_ms(UNICODE_TYPE_DELAY);
58 } 56 }
59} 57}
60 58
@@ -63,7 +61,6 @@ __attribute__((weak)) void qk_ucis_cancel(void) {}
63void register_ucis(const uint32_t *code_points) { 61void register_ucis(const uint32_t *code_points) {
64 for (int i = 0; i < UCIS_MAX_CODE_POINTS && code_points[i]; i++) { 62 for (int i = 0; i < UCIS_MAX_CODE_POINTS && code_points[i]; i++) {
65 register_unicode(code_points[i]); 63 register_unicode(code_points[i]);
66 wait_ms(UNICODE_TYPE_DELAY);
67 } 64 }
68} 65}
69 66
@@ -94,9 +91,7 @@ bool process_ucis(uint16_t keycode, keyrecord_t *record) {
94 case KC_ENTER: 91 case KC_ENTER:
95 case KC_ESCAPE: 92 case KC_ESCAPE:
96 for (uint8_t i = 0; i < qk_ucis_state.count; i++) { 93 for (uint8_t i = 0; i < qk_ucis_state.count; i++) {
97 register_code(KC_BACKSPACE); 94 tap_code(KC_BACKSPACE);
98 unregister_code(KC_BACKSPACE);
99 wait_ms(UNICODE_TYPE_DELAY);
100 } 95 }
101 96
102 if (keycode == KC_ESCAPE) { 97 if (keycode == KC_ESCAPE) {
diff --git a/quantum/process_keycode/process_ucis.h b/quantum/process_keycode/process_ucis.h
index a667430bda..3de0707762 100644
--- a/quantum/process_keycode/process_ucis.h
+++ b/quantum/process_keycode/process_ucis.h
@@ -16,8 +16,10 @@
16 16
17#pragma once 17#pragma once
18 18
19#include "quantum.h" 19#include <stdbool.h>
20#include "process_unicode_common.h" 20#include <stdint.h>
21
22#include "action.h"
21 23
22#ifndef UCIS_MAX_SYMBOL_LENGTH 24#ifndef UCIS_MAX_SYMBOL_LENGTH
23# define UCIS_MAX_SYMBOL_LENGTH 32 25# define UCIS_MAX_SYMBOL_LENGTH 32
diff --git a/quantum/process_keycode/process_unicode.c b/quantum/process_keycode/process_unicode.c
index 18a1d8bc1f..99cc2f5f26 100644
--- a/quantum/process_keycode/process_unicode.c
+++ b/quantum/process_keycode/process_unicode.c
@@ -15,14 +15,14 @@
15 */ 15 */
16 16
17#include "process_unicode.h" 17#include "process_unicode.h"
18#include "action_util.h" 18#include "unicode.h"
19#include "eeprom.h" 19#include "quantum_keycodes.h"
20 20
21bool process_unicode(uint16_t keycode, keyrecord_t *record) { 21bool process_unicode(uint16_t keycode, keyrecord_t *record) {
22 if (keycode >= QK_UNICODE && keycode <= QK_UNICODE_MAX && record->event.pressed) { 22 if (record->event.pressed) {
23 unicode_input_start(); 23 if (keycode >= QK_UNICODE && keycode <= QK_UNICODE_MAX) {
24 register_hex(keycode & 0x7FFF); 24 register_unicode(keycode & 0x7FFF);
25 unicode_input_finish(); 25 }
26 } 26 }
27 return true; 27 return true;
28} 28}
diff --git a/quantum/process_keycode/process_unicode.h b/quantum/process_keycode/process_unicode.h
index 22765ad560..341bc8d861 100644
--- a/quantum/process_keycode/process_unicode.h
+++ b/quantum/process_keycode/process_unicode.h
@@ -16,6 +16,9 @@
16 16
17#pragma once 17#pragma once
18 18
19#include "process_unicode_common.h" 19#include <stdbool.h>
20#include <stdint.h>
21
22#include "action.h"
20 23
21bool process_unicode(uint16_t keycode, keyrecord_t *record); 24bool process_unicode(uint16_t keycode, keyrecord_t *record);
diff --git a/quantum/process_keycode/process_unicode_common.c b/quantum/process_keycode/process_unicode_common.c
index 94809cf029..bd5fc560f3 100644
--- a/quantum/process_keycode/process_unicode_common.c
+++ b/quantum/process_keycode/process_unicode_common.c
@@ -15,306 +15,17 @@
15 */ 15 */
16 16
17#include "process_unicode_common.h" 17#include "process_unicode_common.h"
18#include "eeprom.h" 18#include "unicode.h"
19#include "utf8.h" 19#include "action_util.h"
20#include "keycode.h"
20 21
21unicode_config_t unicode_config; 22#if defined(UNICODE_ENABLE)
22uint8_t unicode_saved_mods; 23# include "process_unicode.h"
23bool unicode_saved_caps_lock; 24#elif defined(UNICODEMAP_ENABLE)
24bool unicode_saved_num_lock; 25# include "process_unicodemap.h"
25 26#elif defined(UCIS_ENABLE)
26#if UNICODE_SELECTED_MODES != -1 27# include "process_ucis.h"
27static uint8_t selected[] = {UNICODE_SELECTED_MODES};
28static int8_t selected_count = ARRAY_SIZE(selected);
29static int8_t selected_index;
30#endif
31
32/** \brief Uunicode input mode set at user level
33 *
34 * Run user code on unicode input mode change
35 */
36__attribute__((weak)) void unicode_input_mode_set_user(uint8_t input_mode) {}
37
38/** \brief unicode input mode set at keyboard level
39 *
40 * Run keyboard code on unicode input mode change
41 */
42__attribute__((weak)) void unicode_input_mode_set_kb(uint8_t input_mode) {
43 unicode_input_mode_set_user(input_mode);
44}
45
46void unicode_input_mode_init(void) {
47 unicode_config.raw = eeprom_read_byte(EECONFIG_UNICODEMODE);
48#if UNICODE_SELECTED_MODES != -1
49# if UNICODE_CYCLE_PERSIST
50 // Find input_mode in selected modes
51 int8_t i;
52 for (i = 0; i < selected_count; i++) {
53 if (selected[i] == unicode_config.input_mode) {
54 selected_index = i;
55 break;
56 }
57 }
58 if (i == selected_count) {
59 // Not found: input_mode isn't selected, change to one that is
60 unicode_config.input_mode = selected[selected_index = 0];
61 }
62# else
63 // Always change to the first selected input mode
64 unicode_config.input_mode = selected[selected_index = 0];
65# endif
66#endif
67 unicode_input_mode_set_kb(unicode_config.input_mode);
68 dprintf("Unicode input mode init to: %u\n", unicode_config.input_mode);
69}
70
71uint8_t get_unicode_input_mode(void) {
72 return unicode_config.input_mode;
73}
74
75void set_unicode_input_mode(uint8_t mode) {
76 unicode_config.input_mode = mode;
77 persist_unicode_input_mode();
78 unicode_input_mode_set_kb(mode);
79 dprintf("Unicode input mode set to: %u\n", unicode_config.input_mode);
80}
81
82void cycle_unicode_input_mode(int8_t offset) {
83#if UNICODE_SELECTED_MODES != -1
84 selected_index = (selected_index + offset) % selected_count;
85 if (selected_index < 0) {
86 selected_index += selected_count;
87 }
88 unicode_config.input_mode = selected[selected_index];
89# if UNICODE_CYCLE_PERSIST
90 persist_unicode_input_mode();
91# endif
92 unicode_input_mode_set_kb(unicode_config.input_mode);
93 dprintf("Unicode input mode cycle to: %u\n", unicode_config.input_mode);
94#endif
95}
96
97void persist_unicode_input_mode(void) {
98 eeprom_update_byte(EECONFIG_UNICODEMODE, unicode_config.input_mode);
99}
100
101__attribute__((weak)) void unicode_input_start(void) {
102 unicode_saved_caps_lock = host_keyboard_led_state().caps_lock;
103 unicode_saved_num_lock = host_keyboard_led_state().num_lock;
104
105 // Note the order matters here!
106 // Need to do this before we mess around with the mods, or else
107 // UNICODE_KEY_LNX (which is usually Ctrl-Shift-U) might not work
108 // correctly in the shifted case.
109 if (unicode_config.input_mode == UC_LNX && unicode_saved_caps_lock) {
110 tap_code(KC_CAPS_LOCK);
111 }
112
113 unicode_saved_mods = get_mods(); // Save current mods
114 clear_mods(); // Unregister mods to start from a clean state
115 clear_weak_mods();
116
117 switch (unicode_config.input_mode) {
118 case UC_MAC:
119 register_code(UNICODE_KEY_MAC);
120 break;
121 case UC_LNX:
122 tap_code16(UNICODE_KEY_LNX);
123 break;
124 case UC_WIN:
125 // For increased reliability, use numpad keys for inputting digits
126 if (!unicode_saved_num_lock) {
127 tap_code(KC_NUM_LOCK);
128 }
129 register_code(KC_LEFT_ALT);
130 wait_ms(UNICODE_TYPE_DELAY);
131 tap_code(KC_KP_PLUS);
132 break;
133 case UC_WINC:
134 tap_code(UNICODE_KEY_WINC);
135 tap_code(KC_U);
136 break;
137 case UC_EMACS:
138 // The usual way to type unicode in emacs is C-x-8 <RET> then the unicode number in hex
139 tap_code16(LCTL(KC_X));
140 tap_code16(KC_8);
141 tap_code16(KC_ENTER);
142 break;
143 }
144
145 wait_ms(UNICODE_TYPE_DELAY);
146}
147
148__attribute__((weak)) void unicode_input_finish(void) {
149 switch (unicode_config.input_mode) {
150 case UC_MAC:
151 unregister_code(UNICODE_KEY_MAC);
152 break;
153 case UC_LNX:
154 tap_code(KC_SPACE);
155 if (unicode_saved_caps_lock) {
156 tap_code(KC_CAPS_LOCK);
157 }
158 break;
159 case UC_WIN:
160 unregister_code(KC_LEFT_ALT);
161 if (!unicode_saved_num_lock) {
162 tap_code(KC_NUM_LOCK);
163 }
164 break;
165 case UC_WINC:
166 tap_code(KC_ENTER);
167 break;
168 case UC_EMACS:
169 tap_code16(KC_ENTER);
170 break;
171 }
172
173 set_mods(unicode_saved_mods); // Reregister previously set mods
174}
175
176__attribute__((weak)) void unicode_input_cancel(void) {
177 switch (unicode_config.input_mode) {
178 case UC_MAC:
179 unregister_code(UNICODE_KEY_MAC);
180 break;
181 case UC_LNX:
182 tap_code(KC_ESCAPE);
183 if (unicode_saved_caps_lock) {
184 tap_code(KC_CAPS_LOCK);
185 }
186 break;
187 case UC_WINC:
188 tap_code(KC_ESCAPE);
189 break;
190 case UC_WIN:
191 unregister_code(KC_LEFT_ALT);
192 if (!unicode_saved_num_lock) {
193 tap_code(KC_NUM_LOCK);
194 }
195 break;
196 case UC_EMACS:
197 tap_code16(LCTL(KC_G)); // C-g cancels
198 break;
199 }
200
201 set_mods(unicode_saved_mods); // Reregister previously set mods
202}
203
204// clang-format off
205
206static void send_nibble_wrapper(uint8_t digit) {
207 if (unicode_config.input_mode == UC_WIN) {
208 uint8_t kc = digit < 10
209 ? KC_KP_1 + (10 + digit - 1) % 10
210 : KC_A + (digit - 10);
211 tap_code(kc);
212 return;
213 }
214 send_nibble(digit);
215}
216
217// clang-format on
218
219void register_hex(uint16_t hex) {
220 for (int i = 3; i >= 0; i--) {
221 uint8_t digit = ((hex >> (i * 4)) & 0xF);
222 send_nibble_wrapper(digit);
223 }
224}
225
226void register_hex32(uint32_t hex) {
227 bool onzerostart = true;
228 for (int i = 7; i >= 0; i--) {
229 if (i <= 3) {
230 onzerostart = false;
231 }
232 uint8_t digit = ((hex >> (i * 4)) & 0xF);
233 if (digit == 0) {
234 if (!onzerostart) {
235 send_nibble_wrapper(digit);
236 }
237 } else {
238 send_nibble_wrapper(digit);
239 onzerostart = false;
240 }
241 }
242}
243
244void register_unicode(uint32_t code_point) {
245 if (code_point > 0x10FFFF || (code_point > 0xFFFF && unicode_config.input_mode == UC_WIN)) {
246 // Code point out of range, do nothing
247 return;
248 }
249
250 unicode_input_start();
251 if (code_point > 0xFFFF && unicode_config.input_mode == UC_MAC) {
252 // Convert code point to UTF-16 surrogate pair on macOS
253 code_point -= 0x10000;
254 uint32_t lo = code_point & 0x3FF, hi = (code_point & 0xFFC00) >> 10;
255 register_hex32(hi + 0xD800);
256 register_hex32(lo + 0xDC00);
257 } else {
258 register_hex32(code_point);
259 }
260 unicode_input_finish();
261}
262
263void send_unicode_string(const char *str) {
264 if (!str) {
265 return;
266 }
267
268 while (*str) {
269 int32_t code_point = 0;
270 str = decode_utf8(str, &code_point);
271
272 if (code_point >= 0) {
273 register_unicode(code_point);
274 }
275 }
276}
277
278// clang-format off
279
280static void audio_helper(void) {
281#ifdef AUDIO_ENABLE
282 switch (get_unicode_input_mode()) {
283# ifdef UNICODE_SONG_MAC
284 static float song_mac[][2] = UNICODE_SONG_MAC;
285 case UC_MAC:
286 PLAY_SONG(song_mac);
287 break;
288# endif
289# ifdef UNICODE_SONG_LNX
290 static float song_lnx[][2] = UNICODE_SONG_LNX;
291 case UC_LNX:
292 PLAY_SONG(song_lnx);
293 break;
294# endif
295# ifdef UNICODE_SONG_WIN
296 static float song_win[][2] = UNICODE_SONG_WIN;
297 case UC_WIN:
298 PLAY_SONG(song_win);
299 break;
300# endif
301# ifdef UNICODE_SONG_BSD
302 static float song_bsd[][2] = UNICODE_SONG_BSD;
303 case UC_BSD:
304 PLAY_SONG(song_bsd);
305 break;
306# endif
307# ifdef UNICODE_SONG_WINC
308 static float song_winc[][2] = UNICODE_SONG_WINC;
309 case UC_WINC:
310 PLAY_SONG(song_winc);
311 break;
312# endif
313 }
314#endif 28#endif
315}
316
317// clang-format on
318 29
319bool process_unicode_common(uint16_t keycode, keyrecord_t *record) { 30bool process_unicode_common(uint16_t keycode, keyrecord_t *record) {
320 if (record->event.pressed) { 31 if (record->event.pressed) {
@@ -322,35 +33,27 @@ bool process_unicode_common(uint16_t keycode, keyrecord_t *record) {
322 switch (keycode) { 33 switch (keycode) {
323 case UNICODE_MODE_FORWARD: 34 case UNICODE_MODE_FORWARD:
324 cycle_unicode_input_mode(shifted ? -1 : +1); 35 cycle_unicode_input_mode(shifted ? -1 : +1);
325 audio_helper();
326 break; 36 break;
327 case UNICODE_MODE_REVERSE: 37 case UNICODE_MODE_REVERSE:
328 cycle_unicode_input_mode(shifted ? +1 : -1); 38 cycle_unicode_input_mode(shifted ? +1 : -1);
329 audio_helper();
330 break; 39 break;
331 case UNICODE_MODE_MAC: 40 case UNICODE_MODE_MAC:
332 set_unicode_input_mode(UC_MAC); 41 set_unicode_input_mode(UC_MAC);
333 audio_helper();
334 break; 42 break;
335 case UNICODE_MODE_LNX: 43 case UNICODE_MODE_LNX:
336 set_unicode_input_mode(UC_LNX); 44 set_unicode_input_mode(UC_LNX);
337 audio_helper();
338 break; 45 break;
339 case UNICODE_MODE_WIN: 46 case UNICODE_MODE_WIN:
340 set_unicode_input_mode(UC_WIN); 47 set_unicode_input_mode(UC_WIN);
341 audio_helper();
342 break; 48 break;
343 case UNICODE_MODE_BSD: 49 case UNICODE_MODE_BSD:
344 set_unicode_input_mode(UC_BSD); 50 set_unicode_input_mode(UC_BSD);
345 audio_helper();
346 break; 51 break;
347 case UNICODE_MODE_WINC: 52 case UNICODE_MODE_WINC:
348 set_unicode_input_mode(UC_WINC); 53 set_unicode_input_mode(UC_WINC);
349 audio_helper();
350 break; 54 break;
351 case UNICODE_MODE_EMACS: 55 case UNICODE_MODE_EMACS:
352 set_unicode_input_mode(UC_EMACS); 56 set_unicode_input_mode(UC_EMACS);
353 audio_helper();
354 break; 57 break;
355 } 58 }
356 } 59 }
diff --git a/quantum/process_keycode/process_unicode_common.h b/quantum/process_keycode/process_unicode_common.h
index 0fe672d26a..fd09a41818 100644
--- a/quantum/process_keycode/process_unicode_common.h
+++ b/quantum/process_keycode/process_unicode_common.h
@@ -16,181 +16,9 @@
16 16
17#pragma once 17#pragma once
18 18
19#include "quantum.h" 19#include <stdbool.h>
20#include <stdint.h>
20 21
21#if defined(UNICODE_ENABLE) + defined(UNICODEMAP_ENABLE) + defined(UCIS_ENABLE) > 1 22#include "action.h"
22# error "Cannot enable more than one Unicode method (UNICODE, UNICODEMAP, UCIS) at the same time"
23#endif
24
25// Keycodes used for starting Unicode input on different platforms
26#ifndef UNICODE_KEY_MAC
27# define UNICODE_KEY_MAC KC_LEFT_ALT
28#endif
29#ifndef UNICODE_KEY_LNX
30# define UNICODE_KEY_LNX LCTL(LSFT(KC_U))
31#endif
32#ifndef UNICODE_KEY_WINC
33# define UNICODE_KEY_WINC KC_RIGHT_ALT
34#endif
35
36// Comma-delimited, ordered list of input modes selected for use (e.g. in cycle)
37// Example: #define UNICODE_SELECTED_MODES UC_WINC, UC_LNX
38#ifndef UNICODE_SELECTED_MODES
39# define UNICODE_SELECTED_MODES -1
40#endif
41
42// Whether input mode changes in cycle should be written to EEPROM
43#ifndef UNICODE_CYCLE_PERSIST
44# define UNICODE_CYCLE_PERSIST true
45#endif
46
47// Delay between starting Unicode input and sending a sequence, in ms
48#ifndef UNICODE_TYPE_DELAY
49# define UNICODE_TYPE_DELAY 10
50#endif
51
52enum unicode_input_modes {
53 UC_MAC, // macOS using Unicode Hex Input
54 UC_LNX, // Linux using IBus
55 UC_WIN, // Windows using EnableHexNumpad
56 UC_BSD, // BSD (not implemented)
57 UC_WINC, // Windows using WinCompose (https://github.com/samhocevar/wincompose)
58 UC_EMACS, // Emacs is an operating system in search of a good text editor
59 UC__COUNT // Number of available input modes (always leave at the end)
60};
61
62typedef union {
63 uint32_t raw;
64 struct {
65 uint8_t input_mode : 8;
66 };
67} unicode_config_t;
68
69extern unicode_config_t unicode_config;
70
71void unicode_input_mode_init(void);
72uint8_t get_unicode_input_mode(void);
73void set_unicode_input_mode(uint8_t mode);
74void cycle_unicode_input_mode(int8_t offset);
75void persist_unicode_input_mode(void);
76
77void unicode_input_start(void);
78void unicode_input_finish(void);
79void unicode_input_cancel(void);
80
81void unicode_input_mode_set_user(uint8_t input_mode);
82void unicode_input_mode_set_kb(uint8_t input_mode);
83
84void register_hex(uint16_t hex);
85void register_hex32(uint32_t hex);
86void register_unicode(uint32_t code_point);
87
88void send_unicode_string(const char *str);
89 23
90bool process_unicode_common(uint16_t keycode, keyrecord_t *record); 24bool process_unicode_common(uint16_t keycode, keyrecord_t *record);
91
92#define UC_BSPC UC(0x0008)
93#define UC_SPC UC(0x0020)
94
95#define UC_EXLM UC(0x0021)
96#define UC_DQUT UC(0x0022)
97#define UC_HASH UC(0x0023)
98#define UC_DLR UC(0x0024)
99#define UC_PERC UC(0x0025)
100#define UC_AMPR UC(0x0026)
101#define UC_QUOT UC(0x0027)
102#define UC_LPRN UC(0x0028)
103#define UC_RPRN UC(0x0029)
104#define UC_ASTR UC(0x002A)
105#define UC_PLUS UC(0x002B)
106#define UC_COMM UC(0x002C)
107#define UC_DASH UC(0x002D)
108#define UC_DOT UC(0x002E)
109#define UC_SLSH UC(0x002F)
110
111#define UC_0 UC(0x0030)
112#define UC_1 UC(0x0031)
113#define UC_2 UC(0x0032)
114#define UC_3 UC(0x0033)
115#define UC_4 UC(0x0034)
116#define UC_5 UC(0x0035)
117#define UC_6 UC(0x0036)
118#define UC_7 UC(0x0037)
119#define UC_8 UC(0x0038)
120#define UC_9 UC(0x0039)
121
122#define UC_COLN UC(0x003A)
123#define UC_SCLN UC(0x003B)
124#define UC_LT UC(0x003C)
125#define UC_EQL UC(0x003D)
126#define UC_GT UC(0x003E)
127#define UC_QUES UC(0x003F)
128#define UC_AT UC(0x0040)
129
130#define UC_A UC(0x0041)
131#define UC_B UC(0x0042)
132#define UC_C UC(0x0043)
133#define UC_D UC(0x0044)
134#define UC_E UC(0x0045)
135#define UC_F UC(0x0046)
136#define UC_G UC(0x0047)
137#define UC_H UC(0x0048)
138#define UC_I UC(0x0049)
139#define UC_J UC(0x004A)
140#define UC_K UC(0x004B)
141#define UC_L UC(0x004C)
142#define UC_M UC(0x004D)
143#define UC_N UC(0x004E)
144#define UC_O UC(0x004F)
145#define UC_P UC(0x0050)
146#define UC_Q UC(0x0051)
147#define UC_R UC(0x0052)
148#define UC_S UC(0x0053)
149#define UC_T UC(0x0054)
150#define UC_U UC(0x0055)
151#define UC_V UC(0x0056)
152#define UC_W UC(0x0057)
153#define UC_X UC(0x0058)
154#define UC_Y UC(0x0059)
155#define UC_Z UC(0x005A)
156
157#define UC_LBRC UC(0x005B)
158#define UC_BSLS UC(0x005C)
159#define UC_RBRC UC(0x005D)
160#define UC_CIRM UC(0x005E)
161#define UC_UNDR UC(0x005F)
162
163#define UC_GRV UC(0x0060)
164
165#define UC_a UC(0x0061)
166#define UC_b UC(0x0062)
167#define UC_c UC(0x0063)
168#define UC_d UC(0x0064)
169#define UC_e UC(0x0065)
170#define UC_f UC(0x0066)
171#define UC_g UC(0x0067)
172#define UC_h UC(0x0068)
173#define UC_i UC(0x0069)
174#define UC_j UC(0x006A)
175#define UC_k UC(0x006B)
176#define UC_l UC(0x006C)
177#define UC_m UC(0x006D)
178#define UC_n UC(0x006E)
179#define UC_o UC(0x006F)
180#define UC_p UC(0x0070)
181#define UC_q UC(0x0071)
182#define UC_r UC(0x0072)
183#define UC_s UC(0x0073)
184#define UC_t UC(0x0074)
185#define UC_u UC(0x0075)
186#define UC_v UC(0x0076)
187#define UC_w UC(0x0077)
188#define UC_x UC(0x0078)
189#define UC_y UC(0x0079)
190#define UC_z UC(0x007A)
191
192#define UC_LCBR UC(0x007B)
193#define UC_PIPE UC(0x007C)
194#define UC_RCBR UC(0x007D)
195#define UC_TILD UC(0x007E)
196#define UC_DEL UC(0x007F)
diff --git a/quantum/process_keycode/process_unicodemap.c b/quantum/process_keycode/process_unicodemap.c
index 459397014d..979d773b05 100644
--- a/quantum/process_keycode/process_unicodemap.c
+++ b/quantum/process_keycode/process_unicodemap.c
@@ -15,6 +15,11 @@
15 */ 15 */
16 16
17#include "process_unicodemap.h" 17#include "process_unicodemap.h"
18#include "unicode.h"
19#include "quantum_keycodes.h"
20#include "keycode.h"
21#include "action_util.h"
22#include "host.h"
18 23
19__attribute__((weak)) uint16_t unicodemap_index(uint16_t keycode) { 24__attribute__((weak)) uint16_t unicodemap_index(uint16_t keycode) {
20 if (keycode >= QK_UNICODEMAP_PAIR) { 25 if (keycode >= QK_UNICODEMAP_PAIR) {
diff --git a/quantum/process_keycode/process_unicodemap.h b/quantum/process_keycode/process_unicodemap.h
index c429859bbb..73f5449864 100644
--- a/quantum/process_keycode/process_unicodemap.h
+++ b/quantum/process_keycode/process_unicodemap.h
@@ -16,7 +16,11 @@
16 16
17#pragma once 17#pragma once
18 18
19#include "process_unicode_common.h" 19#include <stdbool.h>
20#include <stdint.h>
21
22#include "action.h"
23#include "progmem.h"
20 24
21extern const uint32_t PROGMEM unicode_map[]; 25extern const uint32_t PROGMEM unicode_map[];
22 26
diff --git a/quantum/quantum.h b/quantum/quantum.h
index 8d74f2be38..51360c3d2a 100644
--- a/quantum/quantum.h
+++ b/quantum/quantum.h
@@ -109,6 +109,7 @@ extern layer_state_t layer_state;
109#endif 109#endif
110 110
111#ifdef UNICODE_COMMON_ENABLE 111#ifdef UNICODE_COMMON_ENABLE
112# include "unicode.h"
112# include "process_unicode_common.h" 113# include "process_unicode_common.h"
113#endif 114#endif
114 115
diff --git a/quantum/unicode/unicode.c b/quantum/unicode/unicode.c
new file mode 100644
index 0000000000..f9f429e7af
--- /dev/null
+++ b/quantum/unicode/unicode.c
@@ -0,0 +1,376 @@
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
17#include "unicode.h"
18
19#include "eeprom.h"
20#include "eeconfig.h"
21#include "action.h"
22#include "action_util.h"
23#include "host.h"
24#include "keycode.h"
25#include "wait.h"
26#include "audio.h"
27#include "send_string.h"
28#include "utf8.h"
29
30#if defined(UNICODE_ENABLE) + defined(UNICODEMAP_ENABLE) + defined(UCIS_ENABLE) > 1
31# error "Cannot enable more than one Unicode method (UNICODE, UNICODEMAP, UCIS) at the same time"
32#endif
33
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
45// Comma-delimited, ordered list of input modes selected for use (e.g. in cycle)
46// Example: #define UNICODE_SELECTED_MODES UC_WINC, UC_LNX
47#ifndef UNICODE_SELECTED_MODES
48# define UNICODE_SELECTED_MODES -1
49#endif
50
51// Whether input mode changes in cycle should be written to EEPROM
52#ifndef UNICODE_CYCLE_PERSIST
53# define UNICODE_CYCLE_PERSIST true
54#endif
55
56// Delay between starting Unicode input and sending a sequence, in ms
57#ifndef UNICODE_TYPE_DELAY
58# define UNICODE_TYPE_DELAY 10
59#endif
60
61unicode_config_t unicode_config;
62uint8_t unicode_saved_mods;
63led_t unicode_saved_led_state;
64
65#if UNICODE_SELECTED_MODES != -1
66static uint8_t selected[] = {UNICODE_SELECTED_MODES};
67static int8_t selected_count = ARRAY_SIZE(selected);
68static int8_t selected_index;
69#endif
70
71/** \brief unicode input mode set at user level
72 *
73 * Run user code on unicode input mode change
74 */
75__attribute__((weak)) void unicode_input_mode_set_user(uint8_t input_mode) {}
76
77/** \brief unicode input mode set at keyboard level
78 *
79 * Run keyboard code on unicode input mode change
80 */
81__attribute__((weak)) void unicode_input_mode_set_kb(uint8_t input_mode) {
82 unicode_input_mode_set_user(input_mode);
83}
84
85#ifdef AUDIO_ENABLE
86# ifdef UNICODE_SONG_MAC
87static float song_mac[][2] = UNICODE_SONG_MAC;
88# endif
89# ifdef UNICODE_SONG_LNX
90static float song_lnx[][2] = UNICODE_SONG_LNX;
91# endif
92# ifdef UNICODE_SONG_WIN
93static float song_win[][2] = UNICODE_SONG_WIN;
94# endif
95# ifdef UNICODE_SONG_BSD
96static float song_bsd[][2] = UNICODE_SONG_BSD;
97# endif
98# ifdef UNICODE_SONG_WINC
99static float song_winc[][2] = UNICODE_SONG_WINC;
100# endif
101# ifdef UNICODE_SONG_EMACS
102static float song_emacs[][2] = UNICODE_SONG_EMACS;
103# endif
104
105static void unicode_play_song(uint8_t mode) {
106 switch (mode) {
107# ifdef UNICODE_SONG_MAC
108 case UC_MAC:
109 PLAY_SONG(song_mac);
110 break;
111# endif
112# ifdef UNICODE_SONG_LNX
113 case UC_LNX:
114 PLAY_SONG(song_lnx);
115 break;
116# endif
117# ifdef UNICODE_SONG_WIN
118 case UC_WIN:
119 PLAY_SONG(song_win);
120 break;
121# endif
122# ifdef UNICODE_SONG_BSD
123 case UC_BSD:
124 PLAY_SONG(song_bsd);
125 break;
126# endif
127# ifdef UNICODE_SONG_WINC
128 case UC_WINC:
129 PLAY_SONG(song_winc);
130 break;
131# endif
132# ifdef UNICODE_SONG_EMACS
133 case UC_EMACS:
134 PLAY_SONG(song_emacs);
135 break;
136# endif
137 }
138}
139#endif
140
141void unicode_input_mode_init(void) {
142 unicode_config.raw = eeprom_read_byte(EECONFIG_UNICODEMODE);
143#if UNICODE_SELECTED_MODES != -1
144# if UNICODE_CYCLE_PERSIST
145 // Find input_mode in selected modes
146 int8_t i;
147 for (i = 0; i < selected_count; i++) {
148 if (selected[i] == unicode_config.input_mode) {
149 selected_index = i;
150 break;
151 }
152 }
153 if (i == selected_count) {
154 // Not found: input_mode isn't selected, change to one that is
155 unicode_config.input_mode = selected[selected_index = 0];
156 }
157# else
158 // Always change to the first selected input mode
159 unicode_config.input_mode = selected[selected_index = 0];
160# endif
161#endif
162 unicode_input_mode_set_kb(unicode_config.input_mode);
163 dprintf("Unicode input mode init to: %u\n", unicode_config.input_mode);
164}
165
166uint8_t get_unicode_input_mode(void) {
167 return unicode_config.input_mode;
168}
169
170void set_unicode_input_mode(uint8_t mode) {
171 unicode_config.input_mode = mode;
172 persist_unicode_input_mode();
173#ifdef AUDIO_ENABLE
174 unicode_play_song(mode);
175#endif
176 unicode_input_mode_set_kb(mode);
177 dprintf("Unicode input mode set to: %u\n", unicode_config.input_mode);
178}
179
180void cycle_unicode_input_mode(int8_t offset) {
181#if UNICODE_SELECTED_MODES != -1
182 selected_index = (selected_index + offset) % selected_count;
183 if (selected_index < 0) {
184 selected_index += selected_count;
185 }
186 unicode_config.input_mode = selected[selected_index];
187# if UNICODE_CYCLE_PERSIST
188 persist_unicode_input_mode();
189# endif
190# ifdef AUDIO_ENABLE
191 unicode_play_song(unicode_config.input_mode);
192# endif
193 unicode_input_mode_set_kb(unicode_config.input_mode);
194 dprintf("Unicode input mode cycle to: %u\n", unicode_config.input_mode);
195#endif
196}
197
198void persist_unicode_input_mode(void) {
199 eeprom_update_byte(EECONFIG_UNICODEMODE, unicode_config.input_mode);
200}
201
202__attribute__((weak)) void unicode_input_start(void) {
203 unicode_saved_led_state = host_keyboard_led_state();
204
205 // Note the order matters here!
206 // Need to do this before we mess around with the mods, or else
207 // UNICODE_KEY_LNX (which is usually Ctrl-Shift-U) might not work
208 // correctly in the shifted case.
209 if (unicode_config.input_mode == UC_LNX && unicode_saved_led_state.caps_lock) {
210 tap_code(KC_CAPS_LOCK);
211 }
212
213 unicode_saved_mods = get_mods(); // Save current mods
214 clear_mods(); // Unregister mods to start from a clean state
215 clear_weak_mods();
216
217 switch (unicode_config.input_mode) {
218 case UC_MAC:
219 register_code(UNICODE_KEY_MAC);
220 break;
221 case UC_LNX:
222 tap_code16(UNICODE_KEY_LNX);
223 break;
224 case UC_WIN:
225 // For increased reliability, use numpad keys for inputting digits
226 if (!unicode_saved_led_state.num_lock) {
227 tap_code(KC_NUM_LOCK);
228 }
229 register_code(KC_LEFT_ALT);
230 wait_ms(UNICODE_TYPE_DELAY);
231 tap_code(KC_KP_PLUS);
232 break;
233 case UC_WINC:
234 tap_code(UNICODE_KEY_WINC);
235 tap_code(KC_U);
236 break;
237 case UC_EMACS:
238 // The usual way to type unicode in emacs is C-x-8 <RET> then the unicode number in hex
239 tap_code16(LCTL(KC_X));
240 tap_code16(KC_8);
241 tap_code16(KC_ENTER);
242 break;
243 }
244
245 wait_ms(UNICODE_TYPE_DELAY);
246}
247
248__attribute__((weak)) void unicode_input_finish(void) {
249 switch (unicode_config.input_mode) {
250 case UC_MAC:
251 unregister_code(UNICODE_KEY_MAC);
252 break;
253 case UC_LNX:
254 tap_code(KC_SPACE);
255 if (unicode_saved_led_state.caps_lock) {
256 tap_code(KC_CAPS_LOCK);
257 }
258 break;
259 case UC_WIN:
260 unregister_code(KC_LEFT_ALT);
261 if (!unicode_saved_led_state.num_lock) {
262 tap_code(KC_NUM_LOCK);
263 }
264 break;
265 case UC_WINC:
266 tap_code(KC_ENTER);
267 break;
268 case UC_EMACS:
269 tap_code16(KC_ENTER);
270 break;
271 }
272
273 set_mods(unicode_saved_mods); // Reregister previously set mods
274}
275
276__attribute__((weak)) void unicode_input_cancel(void) {
277 switch (unicode_config.input_mode) {
278 case UC_MAC:
279 unregister_code(UNICODE_KEY_MAC);
280 break;
281 case UC_LNX:
282 tap_code(KC_ESCAPE);
283 if (unicode_saved_led_state.caps_lock) {
284 tap_code(KC_CAPS_LOCK);
285 }
286 break;
287 case UC_WINC:
288 tap_code(KC_ESCAPE);
289 break;
290 case UC_WIN:
291 unregister_code(KC_LEFT_ALT);
292 if (!unicode_saved_led_state.num_lock) {
293 tap_code(KC_NUM_LOCK);
294 }
295 break;
296 case UC_EMACS:
297 tap_code16(LCTL(KC_G)); // C-g cancels
298 break;
299 }
300
301 set_mods(unicode_saved_mods); // Reregister previously set mods
302}
303
304// clang-format off
305
306static void send_nibble_wrapper(uint8_t digit) {
307 if (unicode_config.input_mode == UC_WIN) {
308 uint8_t kc = digit < 10
309 ? KC_KP_1 + (10 + digit - 1) % 10
310 : KC_A + (digit - 10);
311 tap_code(kc);
312 return;
313 }
314 send_nibble(digit);
315}
316
317// clang-format on
318
319void register_hex(uint16_t hex) {
320 for (int i = 3; i >= 0; i--) {
321 uint8_t digit = ((hex >> (i * 4)) & 0xF);
322 send_nibble_wrapper(digit);
323 }
324}
325
326void register_hex32(uint32_t hex) {
327 bool onzerostart = true;
328 for (int i = 7; i >= 0; i--) {
329 if (i <= 3) {
330 onzerostart = false;
331 }
332 uint8_t digit = ((hex >> (i * 4)) & 0xF);
333 if (digit == 0) {
334 if (!onzerostart) {
335 send_nibble_wrapper(digit);
336 }
337 } else {
338 send_nibble_wrapper(digit);
339 onzerostart = false;
340 }
341 }
342}
343
344void register_unicode(uint32_t code_point) {
345 if (code_point > 0x10FFFF || (code_point > 0xFFFF && unicode_config.input_mode == UC_WIN)) {
346 // Code point out of range, do nothing
347 return;
348 }
349
350 unicode_input_start();
351 if (code_point > 0xFFFF && unicode_config.input_mode == UC_MAC) {
352 // Convert code point to UTF-16 surrogate pair on macOS
353 code_point -= 0x10000;
354 uint32_t lo = code_point & 0x3FF, hi = (code_point & 0xFFC00) >> 10;
355 register_hex32(hi + 0xD800);
356 register_hex32(lo + 0xDC00);
357 } else {
358 register_hex32(code_point);
359 }
360 unicode_input_finish();
361}
362
363void send_unicode_string(const char *str) {
364 if (!str) {
365 return;
366 }
367
368 while (*str) {
369 int32_t code_point = 0;
370 str = decode_utf8(str, &code_point);
371
372 if (code_point >= 0) {
373 register_unicode(code_point);
374 }
375 }
376}
diff --git a/quantum/unicode/unicode.h b/quantum/unicode/unicode.h
new file mode 100644
index 0000000000..b3e43799ff
--- /dev/null
+++ b/quantum/unicode/unicode.h
@@ -0,0 +1,165 @@
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
17#pragma once
18
19#include <stdint.h>
20
21#include "quantum.h"
22
23typedef union {
24 uint32_t raw;
25 struct {
26 uint8_t input_mode : 8;
27 };
28} unicode_config_t;
29
30extern unicode_config_t unicode_config;
31
32enum unicode_input_modes {
33 UC_MAC, // macOS using Unicode Hex Input
34 UC_LNX, // Linux using IBus
35 UC_WIN, // Windows using EnableHexNumpad
36 UC_BSD, // BSD (not implemented)
37 UC_WINC, // Windows using WinCompose (https://github.com/samhocevar/wincompose)
38 UC_EMACS, // Emacs is an operating system in search of a good text editor
39 UC__COUNT // Number of available input modes (always leave at the end)
40};
41
42void unicode_input_mode_init(void);
43uint8_t get_unicode_input_mode(void);
44void set_unicode_input_mode(uint8_t mode);
45void cycle_unicode_input_mode(int8_t offset);
46void persist_unicode_input_mode(void);
47
48void unicode_input_mode_set_user(uint8_t input_mode);
49void unicode_input_mode_set_kb(uint8_t input_mode);
50
51void unicode_input_start(void);
52void unicode_input_finish(void);
53void unicode_input_cancel(void);
54
55void register_hex(uint16_t hex);
56void register_hex32(uint32_t hex);
57void register_unicode(uint32_t code_point);
58
59void send_unicode_string(const char *str);
60
61// clang-format off
62
63#define UC_BSPC UC(0x0008) // (backspace)
64
65#define UC_SPC UC(0x0020) // (space)
66#define UC_EXLM UC(0x0021) // !
67#define UC_DQUT UC(0x0022) // "
68#define UC_HASH UC(0x0023) // #
69#define UC_DLR UC(0x0024) // $
70#define UC_PERC UC(0x0025) // %
71#define UC_AMPR UC(0x0026) // &
72#define UC_QUOT UC(0x0027) // '
73#define UC_LPRN UC(0x0028) // (
74#define UC_RPRN UC(0x0029) // )
75#define UC_ASTR UC(0x002A) // *
76#define UC_PLUS UC(0x002B) // +
77#define UC_COMM UC(0x002C) // ,
78#define UC_DASH UC(0x002D) // -
79#define UC_DOT UC(0x002E) // .
80#define UC_SLSH UC(0x002F) // /
81
82#define UC_0 UC(0x0030) // 0
83#define UC_1 UC(0x0031) // 1
84#define UC_2 UC(0x0032) // 2
85#define UC_3 UC(0x0033) // 3
86#define UC_4 UC(0x0034) // 4
87#define UC_5 UC(0x0035) // 5
88#define UC_6 UC(0x0036) // 6
89#define UC_7 UC(0x0037) // 7
90#define UC_8 UC(0x0038) // 8
91#define UC_9 UC(0x0039) // 9
92#define UC_COLN UC(0x003A) // :
93#define UC_SCLN UC(0x003B) // ;
94#define UC_LT UC(0x003C) // <
95#define UC_EQL UC(0x003D) // =
96#define UC_GT UC(0x003E) // >
97#define UC_QUES UC(0x003F) // ?
98
99#define UC_AT UC(0x0040) // @
100#define UC_A UC(0x0041) // A
101#define UC_B UC(0x0042) // B
102#define UC_C UC(0x0043) // C
103#define UC_D UC(0x0044) // D
104#define UC_E UC(0x0045) // E
105#define UC_F UC(0x0046) // F
106#define UC_G UC(0x0047) // G
107#define UC_H UC(0x0048) // H
108#define UC_I UC(0x0049) // I
109#define UC_J UC(0x004A) // J
110#define UC_K UC(0x004B) // K
111#define UC_L UC(0x004C) // L
112#define UC_M UC(0x004D) // M
113#define UC_N UC(0x004E) // N
114#define UC_O UC(0x004F) // O
115
116#define UC_P UC(0x0050) // P
117#define UC_Q UC(0x0051) // Q
118#define UC_R UC(0x0052) // R
119#define UC_S UC(0x0053) // S
120#define UC_T UC(0x0054) // T
121#define UC_U UC(0x0055) // U
122#define UC_V UC(0x0056) // V
123#define UC_W UC(0x0057) // W
124#define UC_X UC(0x0058) // X
125#define UC_Y UC(0x0059) // Y
126#define UC_Z UC(0x005A) // Z
127#define UC_LBRC UC(0x005B) // [
128#define UC_BSLS UC(0x005C) // (backslash)
129#define UC_RBRC UC(0x005D) // ]
130#define UC_CIRM UC(0x005E) // ^
131#define UC_UNDR UC(0x005F) // _
132
133#define UC_GRV UC(0x0060) // `
134#define UC_a UC(0x0061) // a
135#define UC_b UC(0x0062) // b
136#define UC_c UC(0x0063) // c
137#define UC_d UC(0x0064) // d
138#define UC_e UC(0x0065) // e
139#define UC_f UC(0x0066) // f
140#define UC_g UC(0x0067) // g
141#define UC_h UC(0x0068) // h
142#define UC_i UC(0x0069) // i
143#define UC_j UC(0x006A) // j
144#define UC_k UC(0x006B) // k
145#define UC_l UC(0x006C) // l
146#define UC_m UC(0x006D) // m
147#define UC_n UC(0x006E) // n
148#define UC_o UC(0x006F) // o
149
150#define UC_p UC(0x0070) // p
151#define UC_q UC(0x0071) // q
152#define UC_r UC(0x0072) // r
153#define UC_s UC(0x0073) // s
154#define UC_t UC(0x0074) // t
155#define UC_u UC(0x0075) // u
156#define UC_v UC(0x0076) // v
157#define UC_w UC(0x0077) // w
158#define UC_x UC(0x0078) // x
159#define UC_y UC(0x0079) // y
160#define UC_z UC(0x007A) // z
161#define UC_LCBR UC(0x007B) // {
162#define UC_PIPE UC(0x007C) // |
163#define UC_RCBR UC(0x007D) // }
164#define UC_TILD UC(0x007E) // ~
165#define UC_DEL UC(0x007F) // (delete)
diff --git a/quantum/utf8.c b/quantum/unicode/utf8.c
index 4b2cd4d8d4..4b2cd4d8d4 100644
--- a/quantum/utf8.c
+++ b/quantum/unicode/utf8.c
diff --git a/quantum/utf8.h b/quantum/unicode/utf8.h
index fb10910944..521dd1918c 100644
--- a/quantum/utf8.h
+++ b/quantum/unicode/utf8.h
@@ -18,4 +18,4 @@
18 18
19#include <stdint.h> 19#include <stdint.h>
20 20
21const char *decode_utf8(const char *str, int32_t *code_point); \ No newline at end of file 21const char *decode_utf8(const char *str, int32_t *code_point);