Browse Source

Win32: Fix non-BMP Unicode codepoint input

Supplementary Plane codepoints from WM_CHAR and WM_SYSCHAR messages were
reported as UTF-16 surrogate pairs.

Related to #1635.
Camilla Löwy 5 years ago
parent
commit
6ce2070392
3 changed files with 34 additions and 8 deletions
  1. 1 0
      README.md
  2. 2 0
      src/win32_platform.h
  3. 31 8
      src/win32_window.c

+ 1 - 0
README.md

@@ -152,6 +152,7 @@ information on what to include when reporting a bug.
    invalid pointer
  - [Win32] Bugfix: Some synthetic key events were reported as `GLFW_KEY_UNKNOWN`
    (#1623)
+ - [Win32] Bugfix: Non-BMP Unicode codepoint input was reported as UTF-16
  - [Cocoa] Added support for `VK_EXT_metal_surface` (#1619)
  - [Cocoa] Added locating the Vulkan loader at runtime in an application bundle
  - [Cocoa] Moved main menu creation to GLFW initialization time (#1649)

+ 2 - 0
src/win32_platform.h

@@ -311,6 +311,8 @@ typedef struct _GLFWwindowWin32
 
     // The last received cursor position, regardless of source
     int                 lastCursorPosX, lastCursorPosY;
+    // The last recevied high surrogate when decoding pairs of UTF-16 messages
+    WCHAR               highSurrogate;
 
 } _GLFWwindowWin32;
 

+ 31 - 8
src/win32_window.c

@@ -646,11 +646,38 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
 
         case WM_CHAR:
         case WM_SYSCHAR:
-        case WM_UNICHAR:
         {
-            const GLFWbool plain = (uMsg != WM_SYSCHAR);
+            if (wParam >= 0xd800 && wParam <= 0xdbff)
+                window->win32.highSurrogate = (WCHAR) wParam;
+            else
+            {
+                unsigned int codepoint = 0;
+
+                if (wParam >= 0xdc00 && wParam <= 0xdfff)
+                {
+                    if (window->win32.highSurrogate)
+                    {
+                        codepoint += (window->win32.highSurrogate - 0xd800) << 10;
+                        codepoint += (WCHAR) wParam - 0xdc00;
+                        codepoint += 0x10000;
+                    }
+                }
+                else
+                    codepoint = (WCHAR) wParam;
 
-            if (uMsg == WM_UNICHAR && wParam == UNICODE_NOCHAR)
+                window->win32.highSurrogate = 0;
+                _glfwInputChar(window, codepoint, getKeyMods(), uMsg != WM_SYSCHAR);
+            }
+
+            if (uMsg == WM_SYSCHAR && window->win32.keymenu)
+                break;
+
+            return 0;
+        }
+
+        case WM_UNICHAR:
+        {
+            if (wParam == UNICODE_NOCHAR)
             {
                 // WM_UNICHAR is not sent by Windows, but is sent by some
                 // third-party input method engine
@@ -658,11 +685,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
                 return TRUE;
             }
 
-            _glfwInputChar(window, (unsigned int) wParam, getKeyMods(), plain);
-
-            if (uMsg == WM_SYSCHAR && window->win32.keymenu)
-                break;
-
+            _glfwInputChar(window, (unsigned int) wParam, getKeyMods(), GLFW_TRUE);
             return 0;
         }