From 7236ff3973f229febfd3a5f73354d81482e82246 Mon Sep 17 00:00:00 2001 From: Joshua Koo Date: Fri, 17 Mar 2017 00:28:19 +0800 Subject: [PATCH 1/3] Support Unicode Characters for .typeString() - rudimentary UTF-8 parsing - tested with Chinese characters - doesn't work with emojis yet - tested on mac but not other platforms --- src/keypress.c | 39 +++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/src/keypress.c b/src/keypress.c index 2287a0e8..be61db79 100644 --- a/src/keypress.c +++ b/src/keypress.c @@ -191,15 +191,13 @@ void tapKey(char c, MMKeyFlags flags) } #if defined(IS_MACOSX) -void toggleUniKey(char c, const bool down) +void toggleUnicodeKey(UniChar ch, const bool down) { /* This function relies on the convenient * CGEventKeyboardSetUnicodeString(), which allows us to not have to * convert characters to a keycode, but does not support adding modifier * flags. It is therefore only used in typeString() and typeStringDelayed() * -- if you need modifier keys, use the above functions instead. */ - UniChar ch = (UniChar)c; /* Convert to unsigned char */ - CGEventRef keyEvent = CGEventCreateKeyboardEvent(NULL, 0, down); if (keyEvent == NULL) { fputs("Could not create keyboard event.\n", stderr); @@ -211,6 +209,12 @@ void toggleUniKey(char c, const bool down) CGEventPost(kCGSessionEventTap, keyEvent); CFRelease(keyEvent); } + +void toggleUniKey(char c, const bool down) +{ + UniChar ch = (UniChar)c; /* Convert to unsigned char */ + toggleUnicodeKey(ch, down); +} #else #define toggleUniKey(c, down) toggleKey(c, down, MOD_NONE) #endif @@ -223,8 +227,35 @@ static void tapUniKey(char c) void typeString(const char *str) { + uint c, c1, c2, c3, n; + while (*str != '\0') { - tapUniKey(*str++); + c = *str++; + + // warning, the following utf8 decoder + // doesn't perform validation + if (c <= 0x7F) { + // 0xxxxxxx one byte + n = c; + } else if ((c & 0xE0) == 0xC0) { + // 110xxxxx two bytes + c1 = (*str++) & 0x3F; + n = ((c & 0x1F) << 6) | c1; + } else if ((c & 0xF0) == 0xE0) { + // 1110xxxx three bytes + c1 = (*str++) & 0x3F; + c2 = (*str++) & 0x3F; + n = ((c & 0x0F) << 12) | (c1 << 6) | c2; + } else if ((c & 0xF8) == 0xF0) { + // 11110xxx four bytes + c1 = (*str++) & 0x3F; + c2 = (*str++) & 0x3F; + c3 = (*str++) & 0x3F; + n = ((c & 0x07) << 18) | (c1 << 12) | (c2 << 6) | c3; + } + + toggleUnicodeKey(n, true); + toggleUnicodeKey(n, false); } } From daadbccd6ef105c5945025b78c0e5d2422b7a5fb Mon Sep 17 00:00:00 2001 From: Joshua Koo Date: Fri, 17 Mar 2017 01:14:27 +0800 Subject: [PATCH 2/3] Fix errors reported by CI on undeclared variables - Try windows-friendly 32 unsigned integer type called unsigned long --- src/keypress.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/keypress.c b/src/keypress.c index be61db79..97c5f5a9 100644 --- a/src/keypress.c +++ b/src/keypress.c @@ -227,7 +227,11 @@ static void tapUniKey(char c) void typeString(const char *str) { - uint c, c1, c2, c3, n; + unsigned long c; + unsigned long c1; + unsigned long c2; + unsigned long c3; + unsigned long n; while (*str != '\0') { c = *str++; @@ -254,8 +258,14 @@ void typeString(const char *str) n = ((c & 0x07) << 18) | (c1 << 12) | (c2 << 6) | c3; } + #if defined(IS_MACOSX) toggleUnicodeKey(n, true); toggleUnicodeKey(n, false); + #else + toggleUniKey(n, true); + toggleUniKey(n, false); + #endif + } } From ea45808ae0b0f2633d19c96de085a953b2c48276 Mon Sep 17 00:00:00 2001 From: Joshua Koo Date: Fri, 17 Mar 2017 11:17:29 +0800 Subject: [PATCH 3/3] Encode to utf-16 for CGEventKeyboardSetUnicodeString --- src/keypress.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/keypress.c b/src/keypress.c index 97c5f5a9..6d58a2f1 100644 --- a/src/keypress.c +++ b/src/keypress.c @@ -191,7 +191,7 @@ void tapKey(char c, MMKeyFlags flags) } #if defined(IS_MACOSX) -void toggleUnicodeKey(UniChar ch, const bool down) +void toggleUnicodeKey(unsigned long ch, const bool down) { /* This function relies on the convenient * CGEventKeyboardSetUnicodeString(), which allows us to not have to @@ -204,7 +204,17 @@ void toggleUnicodeKey(UniChar ch, const bool down) return; } - CGEventKeyboardSetUnicodeString(keyEvent, 1, &ch); + if (ch > 0xFFFF) { + // encode to utf-16 if necessary + unsigned short surrogates[] = { + 0xD800 + ((ch - 0x10000) >> 10), + 0xDC00 + (ch & 0x3FF) + }; + + CGEventKeyboardSetUnicodeString(keyEvent, 2, &surrogates); + } else { + CGEventKeyboardSetUnicodeString(keyEvent, 1, &ch); + } CGEventPost(kCGSessionEventTap, keyEvent); CFRelease(keyEvent); @@ -212,8 +222,7 @@ void toggleUnicodeKey(UniChar ch, const bool down) void toggleUniKey(char c, const bool down) { - UniChar ch = (UniChar)c; /* Convert to unsigned char */ - toggleUnicodeKey(ch, down); + toggleUnicodeKey(c, down); } #else #define toggleUniKey(c, down) toggleKey(c, down, MOD_NONE) @@ -227,10 +236,10 @@ static void tapUniKey(char c) void typeString(const char *str) { - unsigned long c; - unsigned long c1; - unsigned long c2; - unsigned long c3; + unsigned short c; + unsigned short c1; + unsigned short c2; + unsigned short c3; unsigned long n; while (*str != '\0') {