diff --git a/key/goKey.h b/key/goKey.h index 054662f..a4bce19 100644 --- a/key/goKey.h +++ b/key/goKey.h @@ -314,7 +314,7 @@ char* key_toggle(char *k, char *d, char *akey, char *keyT){ } void type_string(char *str){ - typeString(str); + typeStringDelayed(str, 0); } void type_string_delayed(char *str, size_t cpm){ diff --git a/key/keypress.h b/key/keypress.h index 2f0719e..a4aa6f8 100644 --- a/key/keypress.h +++ b/key/keypress.h @@ -68,14 +68,18 @@ void tapKey(char c, MMKeyFlags flags); /* Sends a UTF-8 string without modifiers. */ void typeString(const char *str); +/* Sends a Unicode character without modifiers. */ +void unicodeType(const unsigned value); /* Macro to convert WPM to CPM integers. * (the average English word length is 5.1 characters.) */ #define WPM_TO_CPM(WPM) (unsigned)(5.1 * WPM) -/* Sends a string with partially random delays between each letter. Note that - * deadbeef_srand() must be called before this function if you actually want - * randomness. */ +/* Sends UTF-8 string without modifiers and + * with partially random delays between each letter. + * Note that deadbeef_srand() must be called before this function + * if you actually want randomness. + * */ void typeStringDelayed(const char *str, const unsigned cpm); #ifdef __cplusplus diff --git a/key/keypress_c.h b/key/keypress_c.h index 5ed4798..e01c223 100644 --- a/key/keypress_c.h +++ b/key/keypress_c.h @@ -127,9 +127,8 @@ void toggleKeyCode(MMKeyCode code, const bool down, MMKeyFlags flags) assert(keyEvent != NULL); CGEventSetType(keyEvent, down ? kCGEventKeyDown : kCGEventKeyUp); + // CGEventSetFlags(keyEvent, flags); CGEventSetFlags(keyEvent, (int) flags); - // CGEventSetFlags(keyEvent, 0); - // CGEventSetFlags(keyEvent, kCGEventFlagMaskShift | kCGEventFlagMaskCommand); CGEventPost(kCGSessionEventTap, keyEvent); CFRelease(keyEvent); } @@ -193,15 +192,13 @@ void tapKey(char c, MMKeyFlags flags) } #if defined(IS_MACOSX) -void toggleUniKey(char c, const bool down) +void toggleUnicode(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() + * flags. It is therefore only used in 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); @@ -213,33 +210,80 @@ void toggleUniKey(char c, const bool down) CGEventPost(kCGSessionEventTap, keyEvent); CFRelease(keyEvent); } -#else +#endif + +#if defined(USE_X11) #define toggleUniKey(c, down) toggleKey(c, down, MOD_NONE) #endif -static void tapUniKey(char c) -{ - toggleUniKey(c, true); - toggleUniKey(c, false); +// unicode type +void unicodeType(const unsigned value){ + #if defined(IS_MACOSX) + UniChar ch = (UniChar)value; // Convert to unsigned char + + toggleUnicode(ch, true); + toggleUnicode(ch, false); + #elif defined(IS_WINDOWS) + INPUT ip; + + // Set up a generic keyboard event. + ip.type = INPUT_KEYBOARD; + ip.ki.wVk = 0; // Virtual-key code + ip.ki.wScan = value; // Hardware scan code for key + ip.ki.time = 0; // System will provide its own time stamp. + ip.ki.dwExtraInfo = 0; // No extra info. Use the GetMessageExtraInfo function to obtain this information if needed. + ip.ki.dwFlags = KEYEVENTF_UNICODE; // KEYEVENTF_KEYUP for key release. + + SendInput(1, &ip, sizeof(INPUT)); + #elif defined(USE_X11) + toggleUniKey(value, true); + toggleUniKey(value, false); + #endif } -void typeString(const char *str) -{ - while (*str != '\0') { - tapUniKey(*str++); - } -} - -void typeStringDelayed(const char *str, const unsigned cpm) -{ +void typeStringDelayed(const char *str, const unsigned cpm){ + /* Characters per second */ const double cps = (double)cpm / 60.0; /* Average milli-seconds per character */ const double mspc = (cps == 0.0) ? 0.0 : 1000.0 / cps; + unsigned long n; + unsigned short c; + unsigned short c1; + unsigned short c2; + unsigned short c3; + while (*str != '\0') { - tapUniKey(*str++); - microsleep(mspc + (DEADBEEF_UNIFORM(0.0, 62.5))); + 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; + } + + unicodeType(n); + + if (mspc > 0) { + microsleep(mspc + (DEADBEEF_UNIFORM(0.0, 62.5))); + } } -} +} \ No newline at end of file diff --git a/robotgo.go b/robotgo.go index 5880a91..a4e0a03 100644 --- a/robotgo.go +++ b/robotgo.go @@ -670,6 +670,33 @@ func WriteAll(text string) { clipboard.WriteAll(text) } +// CharCodeAt char code at utf-8 +func CharCodeAt(s string, n int) rune { + i := 0 + for _, r := range s { + if i == n { + return r + } + i++ + } + + return 0 +} + +// TypeStr type string, support UTF-8 +func TypeStr(str string) { + for i := 0; i < len([]rune(str)); i++ { + ustr := uint32(CharCodeAt(str, i)) + UnicodeType(ustr) + } +} + +// UnicodeType unicode tap uint32 +func UnicodeType(str uint32) { + cstr := C.uint(str) + C.unicodeType(cstr) +} + // TypeString type string func TypeString(x string) { cx := C.CString(x) @@ -677,8 +704,8 @@ func TypeString(x string) { defer C.free(unsafe.Pointer(cx)) } -// TypeStr type string, support UTF-8 -func TypeStr(str string) { +// TypeStrP paste string, support UTF-8 +func TypeStrP(str string) { clipboard.WriteAll(str) if runtime.GOOS == "darwin" { KeyTap("v", "command") @@ -688,11 +715,11 @@ func TypeStr(str string) { } // TypeStrDelay type string delayed -func TypeStrDelay(x string, y int) { - cx := C.CString(x) +func TypeStrDelay(str string, y int) { + cstr := C.CString(str) cy := C.size_t(y) - C.type_string_delayed(cx, cy) - defer C.free(unsafe.Pointer(cx)) + C.type_string_delayed(cstr, cy) + defer C.free(unsafe.Pointer(cstr)) } // TypeStringDelayed type string delayed, Wno-deprecated