Skip to content

Commit f1f2f83

Browse files
committed
patch 8.0.1755: MS-Windows: high unicode char received as two utf-16 words
Problem: MS-Windows GUI: high unicode char received as two utf-16 words. Solution: Keep the first word until the second word is received. (Chris Morgan, closes #2800)
1 parent 2225ebb commit f1f2f83

2 files changed

Lines changed: 33 additions & 5 deletions

File tree

src/gui_w32.c

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -494,9 +494,11 @@ static int s_getting_focus = FALSE;
494494
static int s_x_pending;
495495
static int s_y_pending;
496496
static 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
498498
static 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
713721
char_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;

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,8 @@ static char *(features[]) =
761761

762762
static int included_patches[] =
763763
{ /* Add new patch number below this line */
764+
/**/
765+
1755,
764766
/**/
765767
1754,
766768
/**/

0 commit comments

Comments
 (0)