aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Laqua <jlaqua118@gmail.com>2020-06-18 02:07:34 -0500
committerGitHub <noreply@github.com>2020-06-18 08:07:34 +0100
commitf7eb030e917a8fa360ad7cc7bb26d804cf4c5f6c (patch)
tree8415ddb70ed9fa1cfea2651a6ef950483648d851
parentaae1814319c4992471d074ed18b8b7b4842b0a66 (diff)
downloadqmk_firmware-f7eb030e917a8fa360ad7cc7bb26d804cf4c5f6c.tar.gz
qmk_firmware-f7eb030e917a8fa360ad7cc7bb26d804cf4c5f6c.zip
Standardize how unicode is processed (fixes #8768) (#8770)
Co-authored-by: Konstantin Đorđević <vomindoraan@gmail.com>
-rw-r--r--docs/feature_unicode.md13
-rw-r--r--quantum/process_keycode/process_ucis.c97
-rw-r--r--quantum/process_keycode/process_ucis.h26
-rw-r--r--quantum/process_keycode/process_unicode_common.c25
-rw-r--r--quantum/process_keycode/process_unicode_common.h2
-rw-r--r--quantum/process_keycode/process_unicodemap.c21
6 files changed, 89 insertions, 95 deletions
diff --git a/docs/feature_unicode.md b/docs/feature_unicode.md
index a6f2cb4d0..aedffe4ea 100644
--- a/docs/feature_unicode.md
+++ b/docs/feature_unicode.md
@@ -66,13 +66,16 @@ Then define a table like this in your keymap file:
66 66
67```c 67```c
68const qk_ucis_symbol_t ucis_symbol_table[] = UCIS_TABLE( 68const qk_ucis_symbol_t ucis_symbol_table[] = UCIS_TABLE(
69 UCIS_SYM("poop", 0x1F4A9), // 💩 69 UCIS_SYM("poop", 0x1F4A9), // 💩
70 UCIS_SYM("rofl", 0x1F923), // 🤣 70 UCIS_SYM("rofl", 0x1F923), // 🤣
71 UCIS_SYM("kiss", 0x1F619) // 😙 71 UCIS_SYM("cuba", 0x1F1E8, 0x1F1FA), // 🇨🇺
72 UCIS_SYM("look", 0x0CA0, 0x005F, 0x0CA0), // ಠ_ಠ
72); 73);
73``` 74```
74 75
75To use it, call `qk_ucis_start()`. Then, type the mnemonic for the character (such as "rofl"), and hit Space or Enter. QMK should erase the "rofl" text and insert the laughing emoji. 76By default, each table entry may be up to 3 code points long. This number can be changed by adding `#define UCIS_MAX_CODE_POINTS n` to your `config.h` file.
77
78To use UCIS input, call `qk_ucis_start()`. Then, type the mnemonic for the character (such as "rofl") and hit Space, Enter or Esc. QMK should erase the "rofl" text and insert the laughing emoji.
76 79
77### Customization 80### Customization
78 81
@@ -90,7 +93,7 @@ Unicode input in QMK works by inputting a sequence of characters to the OS, sort
90 93
91The following input modes are available: 94The following input modes are available:
92 95
93* **`UC_MAC`**: macOS built-in Unicode hex input. Supports code points up to `0xFFFF` (`0x10FFFF` with Unicode Map). 96* **`UC_MAC`**: macOS built-in Unicode hex input. Supports code points up to `0x10FFFF` (all possible code points).
94 97
95 To enable, go to _System Preferences > Keyboard > Input Sources_, add _Unicode Hex Input_ to the list (it's under _Other_), then activate it from the input dropdown in the Menu Bar. 98 To enable, go to _System Preferences > Keyboard > Input Sources_, add _Unicode Hex Input_ to the list (it's under _Other_), then activate it from the input dropdown in the Menu Bar.
96 By default, this mode uses the left Option key (`KC_LALT`) for Unicode input, but this can be changed by defining [`UNICODE_KEY_MAC`](#input-key-configuration) with another keycode. 99 By default, this mode uses the left Option key (`KC_LALT`) for Unicode input, but this can be changed by defining [`UNICODE_KEY_MAC`](#input-key-configuration) with another keycode.
diff --git a/quantum/process_keycode/process_ucis.c b/quantum/process_keycode/process_ucis.c
index 024077317..2541d6eb2 100644
--- a/quantum/process_keycode/process_ucis.c
+++ b/quantum/process_keycode/process_ucis.c
@@ -27,7 +27,7 @@ void qk_ucis_start(void) {
27 27
28__attribute__((weak)) void qk_ucis_start_user(void) { 28__attribute__((weak)) void qk_ucis_start_user(void) {
29 unicode_input_start(); 29 unicode_input_start();
30 register_hex(0x2328); 30 register_hex(0x2328); // ⌨
31 unicode_input_finish(); 31 unicode_input_finish();
32} 32}
33 33
@@ -35,74 +35,54 @@ __attribute__((weak)) void qk_ucis_success(uint8_t symbol_index) {}
35 35
36static bool is_uni_seq(char *seq) { 36static bool is_uni_seq(char *seq) {
37 uint8_t i; 37 uint8_t i;
38
39 for (i = 0; seq[i]; i++) { 38 for (i = 0; seq[i]; i++) {
40 uint16_t code; 39 uint16_t keycode;
41 if (('1' <= seq[i]) && (seq[i] <= '0')) 40 if ('1' <= seq[i] && seq[i] <= '0') {
42 code = seq[i] - '1' + KC_1; 41 keycode = seq[i] - '1' + KC_1;
43 else 42 } else {
44 code = seq[i] - 'a' + KC_A; 43 keycode = seq[i] - 'a' + KC_A;
45 44 }
46 if (i > qk_ucis_state.count || qk_ucis_state.codes[i] != code) return false; 45 if (i > qk_ucis_state.count || qk_ucis_state.codes[i] != keycode) {
46 return false;
47 }
47 } 48 }
48 49 return qk_ucis_state.codes[i] == KC_ENT || qk_ucis_state.codes[i] == KC_SPC;
49 return (qk_ucis_state.codes[i] == KC_ENT || qk_ucis_state.codes[i] == KC_SPC);
50} 50}
51 51
52__attribute__((weak)) void qk_ucis_symbol_fallback(void) { 52__attribute__((weak)) void qk_ucis_symbol_fallback(void) {
53 for (uint8_t i = 0; i < qk_ucis_state.count - 1; i++) { 53 for (uint8_t i = 0; i < qk_ucis_state.count - 1; i++) {
54 uint8_t code = qk_ucis_state.codes[i]; 54 uint8_t keycode = qk_ucis_state.codes[i];
55 register_code(code); 55 register_code(keycode);
56 unregister_code(code); 56 unregister_code(keycode);
57 wait_ms(UNICODE_TYPE_DELAY); 57 wait_ms(UNICODE_TYPE_DELAY);
58 } 58 }
59} 59}
60 60
61__attribute__((weak)) void qk_ucis_cancel(void) {} 61__attribute__((weak)) void qk_ucis_cancel(void) {}
62 62
63void register_ucis(const char *hex) { 63void register_ucis(const uint32_t *code_points) {
64 for (int i = 0; hex[i]; i++) { 64 for (int i = 0; i < UCIS_MAX_CODE_POINTS && code_points[i]; i++) {
65 uint8_t kc = 0; 65 register_unicode(code_points[i]);
66 char c = hex[i]; 66 wait_ms(UNICODE_TYPE_DELAY);
67
68 switch (c) {
69 case '0':
70 kc = KC_0;
71 break;
72 case '1' ... '9':
73 kc = c - '1' + KC_1;
74 break;
75 case 'a' ... 'f':
76 kc = c - 'a' + KC_A;
77 break;
78 case 'A' ... 'F':
79 kc = c - 'A' + KC_A;
80 break;
81 }
82
83 if (kc) {
84 register_code(kc);
85 unregister_code(kc);
86 wait_ms(UNICODE_TYPE_DELAY);
87 }
88 } 67 }
89} 68}
90 69
91bool process_ucis(uint16_t keycode, keyrecord_t *record) { 70bool process_ucis(uint16_t keycode, keyrecord_t *record) {
92 uint8_t i; 71 if (!qk_ucis_state.in_progress || !record->event.pressed) {
93 72 return true;
94 if (!qk_ucis_state.in_progress) return true; 73 }
95 74
96 if (qk_ucis_state.count >= UCIS_MAX_SYMBOL_LENGTH && !(keycode == KC_BSPC || keycode == KC_ESC || keycode == KC_SPC || keycode == KC_ENT)) { 75 bool special = keycode == KC_SPC || keycode == KC_ENT ||
76 keycode == KC_ESC || keycode == KC_BSPC;
77 if (qk_ucis_state.count >= UCIS_MAX_SYMBOL_LENGTH && !special) {
97 return false; 78 return false;
98 } 79 }
99 80
100 if (!record->event.pressed) return true;
101
102 qk_ucis_state.codes[qk_ucis_state.count] = keycode; 81 qk_ucis_state.codes[qk_ucis_state.count] = keycode;
103 qk_ucis_state.count++; 82 qk_ucis_state.count++;
104 83
105 if (keycode == KC_BSPC) { 84 switch (keycode) {
85 case KC_BSPC:
106 if (qk_ucis_state.count >= 2) { 86 if (qk_ucis_state.count >= 2) {
107 qk_ucis_state.count -= 2; 87 qk_ucis_state.count -= 2;
108 return true; 88 return true;
@@ -110,12 +90,11 @@ bool process_ucis(uint16_t keycode, keyrecord_t *record) {
110 qk_ucis_state.count--; 90 qk_ucis_state.count--;
111 return false; 91 return false;
112 } 92 }
113 }
114 93
115 if (keycode == KC_ENT || keycode == KC_SPC || keycode == KC_ESC) { 94 case KC_SPC:
116 bool symbol_found = false; 95 case KC_ENT:
117 96 case KC_ESC:
118 for (i = qk_ucis_state.count; i > 0; i--) { 97 for (uint8_t i = 0; i < qk_ucis_state.count; i++) {
119 register_code(KC_BSPC); 98 register_code(KC_BSPC);
120 unregister_code(KC_BSPC); 99 unregister_code(KC_BSPC);
121 wait_ms(UNICODE_TYPE_DELAY); 100 wait_ms(UNICODE_TYPE_DELAY);
@@ -127,25 +106,25 @@ bool process_ucis(uint16_t keycode, keyrecord_t *record) {
127 return false; 106 return false;
128 } 107 }
129 108
130 unicode_input_start(); 109 uint8_t i;
110 bool symbol_found = false;
131 for (i = 0; ucis_symbol_table[i].symbol; i++) { 111 for (i = 0; ucis_symbol_table[i].symbol; i++) {
132 if (is_uni_seq(ucis_symbol_table[i].symbol)) { 112 if (is_uni_seq(ucis_symbol_table[i].symbol)) {
133 symbol_found = true; 113 symbol_found = true;
134 register_ucis(ucis_symbol_table[i].code + 2); 114 register_ucis(ucis_symbol_table[i].code_points);
135 break; 115 break;
136 } 116 }
137 } 117 }
138 if (!symbol_found) {
139 qk_ucis_symbol_fallback();
140 }
141 unicode_input_finish();
142
143 if (symbol_found) { 118 if (symbol_found) {
144 qk_ucis_success(i); 119 qk_ucis_success(i);
120 } else {
121 qk_ucis_symbol_fallback();
145 } 122 }
146 123
147 qk_ucis_state.in_progress = false; 124 qk_ucis_state.in_progress = false;
148 return false; 125 return false;
126
127 default:
128 return true;
149 } 129 }
150 return true;
151} 130}
diff --git a/quantum/process_keycode/process_ucis.h b/quantum/process_keycode/process_ucis.h
index 0f93a198b..a667430bd 100644
--- a/quantum/process_keycode/process_ucis.h
+++ b/quantum/process_keycode/process_ucis.h
@@ -22,10 +22,13 @@
22#ifndef UCIS_MAX_SYMBOL_LENGTH 22#ifndef UCIS_MAX_SYMBOL_LENGTH
23# define UCIS_MAX_SYMBOL_LENGTH 32 23# define UCIS_MAX_SYMBOL_LENGTH 32
24#endif 24#endif
25#ifndef UCIS_MAX_CODE_POINTS
26# define UCIS_MAX_CODE_POINTS 3
27#endif
25 28
26typedef struct { 29typedef struct {
27 char *symbol; 30 char * symbol;
28 char *code; 31 uint32_t code_points[UCIS_MAX_CODE_POINTS];
29} qk_ucis_symbol_t; 32} qk_ucis_symbol_t;
30 33
31typedef struct { 34typedef struct {
@@ -36,12 +39,17 @@ typedef struct {
36 39
37extern qk_ucis_state_t qk_ucis_state; 40extern qk_ucis_state_t qk_ucis_state;
38 41
39#define UCIS_TABLE(...) \ 42// clang-format off
40 { \ 43
41 __VA_ARGS__, { NULL, NULL } \ 44#define UCIS_TABLE(...) \
45 { \
46 __VA_ARGS__, \
47 { NULL, {} } \
42 } 48 }
43#define UCIS_SYM(name, code) \ 49#define UCIS_SYM(name, ...) \
44 { name, #code } 50 { name, {__VA_ARGS__} }
51
52// clang-format on
45 53
46extern const qk_ucis_symbol_t ucis_symbol_table[]; 54extern const qk_ucis_symbol_t ucis_symbol_table[];
47 55
@@ -49,5 +57,7 @@ void qk_ucis_start(void);
49void qk_ucis_start_user(void); 57void qk_ucis_start_user(void);
50void qk_ucis_symbol_fallback(void); 58void qk_ucis_symbol_fallback(void);
51void qk_ucis_success(uint8_t symbol_index); 59void qk_ucis_success(uint8_t symbol_index);
52void register_ucis(const char *hex); 60
61void register_ucis(const uint32_t *code_points);
62
53bool process_ucis(uint16_t keycode, keyrecord_t *record); 63bool process_ucis(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 fb5021501..bea34c31e 100644
--- a/quantum/process_keycode/process_unicode_common.c
+++ b/quantum/process_keycode/process_unicode_common.c
@@ -171,6 +171,25 @@ void register_hex32(uint32_t hex) {
171 } 171 }
172} 172}
173 173
174void register_unicode(uint32_t code_point) {
175 if (code_point > 0x10FFFF || (code_point > 0xFFFF && unicode_config.input_mode == UC_WIN)) {
176 // Code point out of range, do nothing
177 return;
178 }
179
180 unicode_input_start();
181 if (code_point > 0xFFFF && unicode_config.input_mode == UC_MAC) {
182 // Convert code point to UTF-16 surrogate pair on macOS
183 code_point -= 0x10000;
184 uint32_t lo = code_point & 0x3FF, hi = (code_point & 0xFFC00) >> 10;
185 register_hex32(hi + 0xD800);
186 register_hex32(lo + 0xDC00);
187 } else {
188 register_hex32(code_point);
189 }
190 unicode_input_finish();
191}
192
174// clang-format off 193// clang-format off
175 194
176void send_unicode_hex_string(const char *str) { 195void send_unicode_hex_string(const char *str) {
@@ -236,14 +255,12 @@ void send_unicode_string(const char *str) {
236 return; 255 return;
237 } 256 }
238 257
239 int32_t code_point = 0;
240 while (*str) { 258 while (*str) {
259 int32_t code_point = 0;
241 str = decode_utf8(str, &code_point); 260 str = decode_utf8(str, &code_point);
242 261
243 if (code_point >= 0) { 262 if (code_point >= 0) {
244 unicode_input_start(); 263 register_unicode(code_point);
245 register_hex32(code_point);
246 unicode_input_finish();
247 } 264 }
248 } 265 }
249} 266}
diff --git a/quantum/process_keycode/process_unicode_common.h b/quantum/process_keycode/process_unicode_common.h
index 4579fde8d..3082fbb5f 100644
--- a/quantum/process_keycode/process_unicode_common.h
+++ b/quantum/process_keycode/process_unicode_common.h
@@ -89,6 +89,8 @@ void unicode_input_cancel(void);
89 89
90void register_hex(uint16_t hex); 90void register_hex(uint16_t hex);
91void register_hex32(uint32_t hex); 91void register_hex32(uint32_t hex);
92void register_unicode(uint32_t code_point);
93
92void send_unicode_hex_string(const char *str); 94void send_unicode_hex_string(const char *str);
93void send_unicode_string(const char *str); 95void send_unicode_string(const char *str);
94 96
diff --git a/quantum/process_keycode/process_unicodemap.c b/quantum/process_keycode/process_unicodemap.c
index 2f402a2fd..789a90445 100644
--- a/quantum/process_keycode/process_unicodemap.c
+++ b/quantum/process_keycode/process_unicodemap.c
@@ -36,25 +36,8 @@ __attribute__((weak)) uint16_t unicodemap_index(uint16_t keycode) {
36 36
37bool process_unicodemap(uint16_t keycode, keyrecord_t *record) { 37bool process_unicodemap(uint16_t keycode, keyrecord_t *record) {
38 if (keycode >= QK_UNICODEMAP && keycode <= QK_UNICODEMAP_PAIR_MAX && record->event.pressed) { 38 if (keycode >= QK_UNICODEMAP && keycode <= QK_UNICODEMAP_PAIR_MAX && record->event.pressed) {
39 unicode_input_start(); 39 uint32_t code_point = pgm_read_dword(unicode_map + unicodemap_index(keycode));
40 40 register_unicode(code_point);
41 uint32_t code = pgm_read_dword(unicode_map + unicodemap_index(keycode));
42 uint8_t input_mode = get_unicode_input_mode();
43
44 if (code > 0x10FFFF || (code > 0xFFFF && input_mode == UC_WIN)) {
45 // Character is out of range supported by the platform
46 unicode_input_cancel();
47 } else if (code > 0xFFFF && input_mode == UC_MAC) {
48 // Convert to UTF-16 surrogate pair on Mac
49 code -= 0x10000;
50 uint32_t lo = code & 0x3FF, hi = (code & 0xFFC00) >> 10;
51 register_hex32(hi + 0xD800);
52 register_hex32(lo + 0xDC00);
53 unicode_input_finish();
54 } else {
55 register_hex32(code);
56 unicode_input_finish();
57 }
58 } 41 }
59 return true; 42 return true;
60} 43}