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..e1cd656 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,73 @@ void toggleUniKey(char c, const bool down)
 	CGEventPost(kCGSessionEventTap, keyEvent);
 	CFRelease(keyEvent);
 }
-#else
-	#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));
+	#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