diff -urpN gtk+-2.24.30.orig/gdk/win32/gdkevents-win32.c gtk+-2.24.30/gdk/win32/gdkevents-win32.c
--- gtk+-2.24.30.orig/gdk/win32/gdkevents-win32.c	2016-01-19 11:03:55.000000000 -0800
+++ gtk+-2.24.30/gdk/win32/gdkevents-win32.c	2016-07-24 11:33:16.080516200 -0700
@@ -2280,7 +2280,36 @@ gdk_event_translate (MSG  *msg,
       if (GDK_WINDOW_DESTROYED (window))
 	break;
 
-      event = gdk_event_new ((msg->message == WM_KEYDOWN ||
+	  impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl);
+
+	  API_CALL (GetKeyboardState, (key_state));
+
+	  ccount = 0;
+
+	  if (msg->wParam == VK_PACKET)
+	    {
+		  ccount = ToUnicode(VK_PACKET, HIWORD(msg->lParam), key_state, wbuf, 100, 0);
+		  if (ccount == 1)
+		    {
+			  if (wbuf[0] >= 0xD800 && wbuf[0] < 0xDC00)
+			    {
+				  if (msg->message == WM_KEYDOWN)
+					impl->leading_surrogate_keydown = wbuf[0];
+				  else
+					impl->leading_surrogate_keyup = wbuf[0];
+
+				  /* don't emit an event */
+				  return_val = TRUE;
+				  break;
+			    }
+			  else
+			    {
+				  /* wait until an event is created */;
+			    }
+		  }
+	  }
+
+	  event = gdk_event_new ((msg->message == WM_KEYDOWN ||
 			      msg->message == WM_SYSKEYDOWN) ?
 			     GDK_KEY_PRESS : GDK_KEY_RELEASE);
       event->key.window = window;
@@ -2310,24 +2339,48 @@ gdk_event_translate (MSG  *msg,
 	       LOBYTE (HIWORD (msg->lParam)) == _scancode_rshift)
 	event->key.hardware_keycode = VK_RSHIFT;
 
-      API_CALL (GetKeyboardState, (key_state));
-
       /* g_print ("ctrl:%02x lctrl:%02x rctrl:%02x alt:%02x lalt:%02x ralt:%02x\n", key_state[VK_CONTROL], key_state[VK_LCONTROL], key_state[VK_RCONTROL], key_state[VK_MENU], key_state[VK_LMENU], key_state[VK_RMENU]); */
       
       build_key_event_state (event, key_state);
 
-      if (msg->wParam == VK_PACKET &&
-	  ToUnicode (VK_PACKET, HIWORD (msg->lParam), key_state, wbuf, 1, 0) == 1)
-	event->key.keyval = gdk_unicode_to_keyval (wbuf[0]);
-      else
-	gdk_keymap_translate_keyboard_state (NULL,
-					     event->key.hardware_keycode,
-					     event->key.state,
-					     event->key.group,
-					     &event->key.keyval,
-					     NULL, NULL, NULL);
+	  if (msg->wParam == VK_PACKET && ccount == 1)
+		{
+		  if (wbuf[0] >= 0xD800 && wbuf[0] < 0xDC00)
+			{
+			  g_assert_not_reached();
+			}
+		  else if (wbuf[0] >= 0xDC00 && wbuf[0] < 0xE000)
+			{
+			  wchar_t leading;
+
+			  if (msg->message == WM_KEYDOWN)
+				leading = impl->leading_surrogate_keydown;
+			  else
+				leading = impl->leading_surrogate_keyup;
+
+			  event->key.keyval = gdk_unicode_to_keyval((leading - 0xD800) * 0x400 + wbuf[0] - 0xDC00 + 0x10000);
+			}
+		  else
+			{
+			  event->key.keyval = gdk_unicode_to_keyval(wbuf[0]);
+			}
+		}
+	  else
+		{
+		  gdk_keymap_translate_keyboard_state(NULL,
+											  event->key.hardware_keycode,
+											  event->key.state,
+											  event->key.group,
+											  &event->key.keyval,
+											  NULL, NULL, NULL);
+		}
+
+	  if (msg->message == WM_KEYDOWN)
+		impl->leading_surrogate_keydown = 0;
+	  else
+		impl->leading_surrogate_keyup = 0;
 
-      fill_key_event_string (event);
+	  fill_key_event_string (event);
 
       /* Reset MOD1_MASK if it is the Alt key itself */
       if (msg->wParam == VK_MENU)
diff -urpN gtk+-2.24.30.orig/gdk/win32/gdkwindow-win32.h gtk+-2.24.30/gdk/win32/gdkwindow-win32.h
--- gtk+-2.24.30.orig/gdk/win32/gdkwindow-win32.h	2015-12-28 07:42:28.000000000 -0800
+++ gtk+-2.24.30/gdk/win32/gdkwindow-win32.h	2016-07-24 11:26:40.674306000 -0700
@@ -75,6 +75,14 @@ struct _GdkWindowImplWin32
   HCURSOR hcursor;
   HICON   hicon_big;
   HICON   hicon_small;
+
+  /* When VK_PACKET sends us a leading surrogate, it's stashed here.
+   * Later, when another VK_PACKET sends a tailing surrogate, we make up
+   * a full unicode character from them, or discard the leading surrogate,
+   * if the next key is not a tailing surrogate.
+   */
+  wchar_t leading_surrogate_keydown;
+  wchar_t leading_surrogate_keyup;
 
   /* Window size hints */
   gint hint_flags;
