aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan <fauxpark@gmail.com>2020-02-24 10:27:25 +1100
committerGitHub <noreply@github.com>2020-02-24 10:27:25 +1100
commit371ff9dd6f9c4feada34622d9a43480495b07e50 (patch)
tree785ba3038f5e431f1192c09f11d022c2c6850555
parent716c29881c0f91e3998e1fc5c49740bd6e65876f (diff)
downloadqmk_firmware-371ff9dd6f9c4feada34622d9a43480495b07e50.tar.gz
qmk_firmware-371ff9dd6f9c4feada34622d9a43480495b07e50.zip
A proper `send_string()` for the Unicode feature (#8155)
-rw-r--r--docs/feature_unicode.md22
-rw-r--r--quantum/process_keycode/process_unicode_common.c49
-rw-r--r--quantum/process_keycode/process_unicode_common.h1
3 files changed, 67 insertions, 5 deletions
diff --git a/docs/feature_unicode.md b/docs/feature_unicode.md
index bd1f4fa5a..546af2521 100644
--- a/docs/feature_unicode.md
+++ b/docs/feature_unicode.md
@@ -193,12 +193,24 @@ By default, when the keyboard boots, it will initialize the input mode to the la
193 193
194!> Using `UNICODE_SELECTED_MODES` means you don't have to initially set the input mode in `matrix_init_user()` (or a similar function); the Unicode system will do that for you on startup. This has the added benefit of avoiding unnecessary writes to EEPROM. 194!> Using `UNICODE_SELECTED_MODES` means you don't have to initially set the input mode in `matrix_init_user()` (or a similar function); the Unicode system will do that for you on startup. This has the added benefit of avoiding unnecessary writes to EEPROM.
195 195
196## `send_unicode_hex_string` 196## `send_unicode_string()`
197 197
198To type multiple characters for things like (ノಠ痊ಠ)ノ彡┻━┻, you can use `send_unicode_hex_string()` much like `SEND_STRING()` except you would use hex values separate by spaces. 198This function is much like `send_string()` but allows you to input UTF-8 characters directly, currently up to code point U+FFFF. Make sure your `keymap.c` is formatted in UTF-8 encoding.
199For example, the table flip seen above would be `send_unicode_hex_string("0028 30CE 0CA0 75CA 0CA0 0029 30CE 5F61 253B 2501 253B")`
200 199
201There are many ways to get a hex code, but an easy one is [this site](https://r12a.github.io/app-conversion/). Just make sure to convert to hexadecimal, and that is your string. 200```c
201send_unicode_string("(ノಠ痊ಠ)ノ彡┻━┻");
202```
203
204## `send_unicode_hex_string()`
205
206Similar to `send_unicode_string()`, but the characters are represented by their code point values in ASCII, separated by spaces. For example, the table flip above would be achieved with:
207
208```c
209send_unicode_hex_string("0028 30CE 0CA0 75CA 0CA0 0029 30CE 5F61 253B 2501 253B");
210```
211
212An easy way to convert your Unicode string to this format is by using [this site](https://r12a.github.io/app-conversion/), and taking the result in the "Hex/UTF-32" section.
213Unlike `send_unicode_string()` this function supports code points up to U+10FFFF.
202 214
203## Additional Language Support 215## Additional Language Support
204 216
@@ -228,6 +240,6 @@ AutoHotkey inserts the Text right of `Send, ` when this combination is pressed.
228 240
229If you enable the US International layout on the system, it will use punctuation to accent the characters. 241If you enable the US International layout on the system, it will use punctuation to accent the characters.
230 242
231For instance, typing "`a" will result in à. 243For instance, typing "\`a" will result in à.
232 244
233You can find details on how to enable this [here](https://support.microsoft.com/en-us/help/17424/windows-change-keyboard-layout). 245You can find details on how to enable this [here](https://support.microsoft.com/en-us/help/17424/windows-change-keyboard-layout).
diff --git a/quantum/process_keycode/process_unicode_common.c b/quantum/process_keycode/process_unicode_common.c
index 94383f19b..4ac305e66 100644
--- a/quantum/process_keycode/process_unicode_common.c
+++ b/quantum/process_keycode/process_unicode_common.c
@@ -178,6 +178,55 @@ void send_unicode_hex_string(const char *str) {
178 } 178 }
179} 179}
180 180
181// Borrowed from https://nullprogram.com/blog/2017/10/06/
182const char *decode_utf8(const char *str, int32_t *code_point) {
183 const char *next;
184
185 if (str[0] < 0x80) { // U+0000-007F
186 *code_point = str[0];
187 next = str + 1;
188 } else if ((str[0] & 0xE0) == 0xC0) { // U+0080-07FF
189 *code_point = ((int32_t)(str[0] & 0x1F) << 6) | ((int32_t)(str[1] & 0x3F) << 0);
190 next = str + 2;
191 } else if ((str[0] & 0xF0) == 0xE0) { // U+0800-FFFF
192 *code_point = ((int32_t)(str[0] & 0x0F) << 12) | ((int32_t)(str[1] & 0x3F) << 6) | ((int32_t)(str[2] & 0x3F) << 0);
193 next = str + 3;
194 } else if ((str[0] & 0xF8) == 0xF0 && (str[0] <= 0xF4)) { // U+10000-10FFFF
195 // Skip for now - register_hex() only takes a uint16
196 //*code_point = ((int32_t)(str[0] & 0x07) << 18) | ((int32_t)(str[1] & 0x3F) << 12) | ((int32_t)(str[2] & 0x3F) << 6) | ((int32_t)(str[3] & 0x3F) << 0);
197 *code_point = -1;
198 next = str + 4;
199 } else {
200 *code_point = -1;
201 next = str + 1;
202 }
203
204 // part of a UTF-16 surrogate pair - invalid
205 if (*code_point >= 0xD800 && *code_point <= 0xDFFF) {
206 *code_point = -1;
207 }
208
209 return next;
210}
211
212void send_unicode_string(const char *str) {
213 if (!str) {
214 return;
215 }
216
217 int32_t code_point = 0;
218
219 while (*str) {
220 str = decode_utf8(str, &code_point);
221
222 if (code_point >= 0) {
223 unicode_input_start();
224 register_hex(code_point);
225 unicode_input_finish();
226 }
227 }
228}
229
181bool process_unicode_common(uint16_t keycode, keyrecord_t *record) { 230bool process_unicode_common(uint16_t keycode, keyrecord_t *record) {
182 if (record->event.pressed) { 231 if (record->event.pressed) {
183 switch (keycode) { 232 switch (keycode) {
diff --git a/quantum/process_keycode/process_unicode_common.h b/quantum/process_keycode/process_unicode_common.h
index cab6eea6e..393db2d99 100644
--- a/quantum/process_keycode/process_unicode_common.h
+++ b/quantum/process_keycode/process_unicode_common.h
@@ -80,6 +80,7 @@ void unicode_input_cancel(void);
80 80
81void register_hex(uint16_t hex); 81void register_hex(uint16_t hex);
82void send_unicode_hex_string(const char *str); 82void send_unicode_hex_string(const char *str);
83void send_unicode_string(const char *str);
83 84
84bool process_unicode_common(uint16_t keycode, keyrecord_t *record); 85bool process_unicode_common(uint16_t keycode, keyrecord_t *record);
85 86