From 1f9bc0d42bc53fd04cc848da1da52635dcf7a2c0 Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Fri, 20 Nov 2015 10:43:26 +1100 Subject: Bug [#1779]. Better Unicode input support on Windows systems. - support surrogate pairs in WM_CHAR messages - support characters from supplementary planes in WM_UNICHAR messages - support WM_UNICHAR messages in non-Unicode mode - fix some code duplication Also, do not return FALSE upon receiving a WM_UNICHAR message with a UNICODE_NOCHAR parameter, since WM_UNICHAR can actually be handled just fine (at least with the exact same level of support as WM_CHAR). --- win32/ScintillaWin.cxx | 73 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 48 insertions(+), 25 deletions(-) (limited to 'win32') diff --git a/win32/ScintillaWin.cxx b/win32/ScintillaWin.cxx index d0ea62a31..92df2aad6 100644 --- a/win32/ScintillaWin.cxx +++ b/win32/ScintillaWin.cxx @@ -100,6 +100,14 @@ #define UNICODE_NOCHAR 0xFFFF #endif +#ifndef IS_HIGH_SURROGATE +#define IS_HIGH_SURROGATE(x) ((x) >= SURROGATE_LEAD_FIRST && (x) <= SURROGATE_LEAD_LAST) +#endif + +#ifndef IS_LOW_SURROGATE +#define IS_LOW_SURROGATE(x) ((x) >= SURROGATE_TRAIL_FIRST && (x) <= SURROGATE_TRAIL_LAST) +#endif + #ifndef MK_ALT #define MK_ALT 32 #endif @@ -212,6 +220,7 @@ class ScintillaWin : public ScintillaBase { bool lastKeyDownConsumed; + wchar_t lastHighSurrogateChar; bool capturedMouse; bool trackedMouseLeave; @@ -269,6 +278,7 @@ class ScintillaWin : virtual bool DragThreshold(Point ptStart, Point ptNow); virtual void StartDrag(); int TargetAsUTF8(char *text); + void AddCharUTF16(wchar_t const *wcs, unsigned int wclen); int EncodedFromUTF8(char *utf8, char *encoded) const; sptr_t WndPaint(uptr_t wParam); @@ -383,6 +393,7 @@ ATOM ScintillaWin::callClassAtom = 0; ScintillaWin::ScintillaWin(HWND hwnd) { lastKeyDownConsumed = false; + lastHighSurrogateChar = 0; capturedMouse = false; trackedMouseLeave = false; @@ -729,6 +740,26 @@ int ScintillaWin::EncodedFromUTF8(char *utf8, char *encoded) const { } } +// Add one character from a UTF-16 string, by converting to either UTF-8 or +// the current codepage. Code is similar to HandleCompositionWindowed(). +void ScintillaWin::AddCharUTF16(wchar_t const *wcs, unsigned int wclen) { + if (IsUnicodeMode()) { + char utfval[maxLenInputIME * 3]; + unsigned int len = UTF8Length(wcs, wclen); + UTF8FromUTF16(wcs, wclen, utfval, len); + utfval[len] = '\0'; + AddCharUTF(utfval, len); + } else { + UINT cpDest = CodePageOfDocument(); + char inBufferCP[maxLenInputIME * 2]; + int size = ::WideCharToMultiByte(cpDest, + 0, wcs, wclen, inBufferCP, sizeof(inBufferCP) - 1, 0, 0); + for (int i=0; i= 128) || !iscntrl(static_cast(wParam))) || !lastKeyDownConsumed) { - wchar_t wcs[2] = {static_cast(wParam), 0}; - if (IsUnicodeMode()) { - // For a wide character version of the window: - char utfval[UTF8MaxBytes]; - unsigned int len = UTF8Length(wcs, 1); - UTF8FromUTF16(wcs, 1, utfval, len); - AddCharUTF(utfval, len); - } else { - UINT cpDest = CodePageOfDocument(); - char inBufferCP[20]; - int size = ::WideCharToMultiByte(cpDest, - 0, wcs, 1, inBufferCP, sizeof(inBufferCP) - 1, 0, 0); - inBufferCP[size] = '\0'; - AddCharUTF(inBufferCP, size); + wchar_t wcs[3] = {static_cast(wParam), 0}; + unsigned int wclen = 1; + if (IS_HIGH_SURROGATE(wcs[0])) { + // If this is a high surrogate character, we need a second one + lastHighSurrogateChar = wcs[0]; + return 0; + } else if (IS_LOW_SURROGATE(wcs[0])) { + wcs[1] = wcs[0]; + wcs[0] = lastHighSurrogateChar; + lastHighSurrogateChar = 0; + wclen = 2; } + AddCharUTF16(wcs, wclen); } return 0; case WM_UNICHAR: if (wParam == UNICODE_NOCHAR) { - return IsUnicodeMode() ? 1 : 0; + return TRUE; } else if (lastKeyDownConsumed) { return 1; } else { - if (IsUnicodeMode()) { - char utfval[UTF8MaxBytes]; - wchar_t wcs[2] = {static_cast(wParam), 0}; - unsigned int len = UTF8Length(wcs, 1); - UTF8FromUTF16(wcs, 1, utfval, len); - AddCharUTF(utfval, len); - return 1; - } else { - return 0; - } + wchar_t wcs[3] = {0}; + unsigned int wclen = UTF16FromUTF32Character(wParam, wcs); + AddCharUTF16(wcs, wclen); + return FALSE; } case WM_SYSKEYDOWN: -- cgit v1.2.3