The following patch against [rfe-6c0d7aec67] fixes TCL_UTF_MAX=6 and seems to work with TCL_UTF_MAX=3, too (even displaying Emojis properly).

--- 2016-08-29 10:02:57.844491784 +0200
+++ 2016-08-29 21:58:21.505193164 +0200
@@ -81,6 +81,9 @@
     TkDisplay *winDisplay;     /* TkDisplay structure that represents Windows
                                 * screen. */
     int updatingClipboard;     /* If 1, we are updating the clipboard. */
+#if TCL_UTF_MAX >= 4
+    int surrogateBuffer;       /* Buffer for first of surrogate pair. */
+#endif
 } ThreadSpecificData;
 static Tcl_ThreadDataKey dataKey;

@@ -1211,20 +1214,18 @@
                char buffer[TCL_UTF_MAX+1];

 #if TCL_UTF_MAX >= 4
-               if ((((int)wParam & 0xfc00) == 0xd800)
-                       && (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) != 0)
-                       && (msg.message == WM_CHAR)) {
-                   MSG msg;
-                   int ch2;
-
-                   GetMessage(&msg, NULL, 0, 0);
-                   ch2 = wParam & 0xffff;
-                   ch1 = ((ch1 & 0x3ff) << 10) | (ch2 & 0x3ff);
-                   ch1 += 0x10000;
-                   event.xkey.nbytes = Tcl_UniCharToUtf(ch1, buffer);
-               } else
+               if ((ch1 & 0xfc00) == 0xd800) {
+                   tsdPtr->surrogateBuffer = ch1;
+                   return;
+               }
+               if ((ch1 & 0xfc00) == 0xdc00) {
+                   ch1 = ((tsdPtr->surrogateBuffer & 0x3ff) << 10) |
+                         (ch1 & 0x3ff);
+                   ch1 += 0x10000;
+                   tsdPtr->surrogateBuffer = 0;
+               }
 #endif
-                   event.xkey.nbytes = Tcl_UniCharToUtf(ch1, buffer);
+               event.xkey.nbytes = Tcl_UniCharToUtf(ch1, buffer);
                for (i=0; i<event.xkey.nbytes && i<XMaxTransChars; ++i) {
                    event.xkey.trans_chars[i] = buffer[i];
                }