@@ -494,9 +494,11 @@ static int s_getting_focus = FALSE;
494494static int s_x_pending ;
495495static int s_y_pending ;
496496static UINT s_kFlags_pending ;
497- static UINT s_wait_timer = 0 ; /* Timer for get char from user */
497+ static UINT s_wait_timer = 0 ; // Timer for get char from user
498498static int s_timed_out = FALSE;
499- static int dead_key = 0 ; /* 0: no dead key, 1: dead key pressed */
499+ static int dead_key = 0 ; // 0: no dead key, 1: dead key pressed
500+ static UINT surrogate_pending_ch = 0 ; // 0: no surrogate pending,
501+ // else a high surrogate
500502
501503#ifdef FEAT_BEVAL_GUI
502504/* balloon-eval WM_NOTIFY_HANDLER */
@@ -708,6 +710,12 @@ _OnDeadChar(
708710 * Convert Unicode character "ch" to bytes in "string[slen]".
709711 * When "had_alt" is TRUE the ALT key was included in "ch".
710712 * Return the length.
713+ * Because the Windows API uses UTF-16, we have to deal with surrogate
714+ * pairs; this is where we choose to deal with them: if "ch" is a high
715+ * surrogate, it will be stored, and the length returned will be zero; the next
716+ * char_to_string call will then include the high surrogate, decoding the pair
717+ * of UTF-16 code units to a single Unicode code point, presuming it is the
718+ * matching low surrogate.
711719 */
712720 static int
713721char_to_string (int ch , char_u * string , int slen , int had_alt )
@@ -718,8 +726,27 @@ char_to_string(int ch, char_u *string, int slen, int had_alt)
718726 WCHAR wstring [2 ];
719727 char_u * ws = NULL ;
720728
721- wstring [0 ] = ch ;
722- len = 1 ;
729+ if (surrogate_pending_ch != 0 )
730+ {
731+ /* We don't guarantee ch is a low surrogate to match the high surrogate
732+ * we already have; it should be, but if it isn't, tough luck. */
733+ wstring [0 ] = surrogate_pending_ch ;
734+ wstring [1 ] = ch ;
735+ surrogate_pending_ch = 0 ;
736+ len = 2 ;
737+ }
738+ else if (ch >= 0xD800 && ch <= 0xDBFF ) /* high surrogate */
739+ {
740+ /* We don't have the entire code point yet, only the first UTF-16 code
741+ * unit; so just remember it and use it in the next call. */
742+ surrogate_pending_ch = ch ;
743+ return 0 ;
744+ }
745+ else
746+ {
747+ wstring [0 ] = ch ;
748+ len = 1 ;
749+ }
723750
724751 /* "ch" is a UTF-16 character. Convert it to a string of bytes. When
725752 * "enc_codepage" is non-zero use the standard Win32 function,
@@ -743,7 +770,6 @@ char_to_string(int ch, char_u *string, int slen, int had_alt)
743770 }
744771 else
745772 {
746- len = 1 ;
747773 ws = utf16_to_enc (wstring , & len );
748774 if (ws == NULL )
749775 len = 0 ;
0 commit comments