瀏覽代碼

Fixed bug 1876 - SDL_TEXTINPUT only returns '?' (0x3F) in event.text.text with Khmer language input

Andreas

The issue comes down to this line on MSDN:
"TranslateMessage produces WM_CHAR messages only for keys that are mapped to ASCII characters by the keyboard driver."

"WM_KEYDOWN and WM_KEYUP combinations produce a WM_CHAR or WM_DEADCHAR message. WM_SYSKEYDOWN and WM_SYSKEYUP combinations produce a WM_SYSCHAR or WM_SYSDEADCHAR message."
Except for WM_CHAR, none of these messages are used in SDL. Hence TranslateMessage should be dropped entirely and proper handling be included in the WM_KEYDOWN event.
Currently TranslateMessage is called for every message even if it must not be called in certain cases (like "An application should not call TranslateMessage if the TranslateAccelerator function returns a nonzero value.").

WM_CHAR message handling should remain for external processes posting these messages - additionally, WM_UNICHAR should be added.

I made a patch for src/video/windows/SDL_windowsevents.c that seems to work fine. It doesn't solve the "missing" composition for Khmer, but at least input for languages that cannot be mapped to ASCII characters (and for which IME is not used) will now work on Windows.
Sam Lantinga 11 年之前
父節點
當前提交
b4b12d950e
共有 1 個文件被更改,包括 54 次插入18 次删除
  1. 54 18
      src/video/windows/SDL_windowsevents.c

+ 54 - 18
src/video/windows/SDL_windowsevents.c

@@ -256,6 +256,33 @@ WIN_CheckRawMouseButtons( ULONG rawButtons, SDL_WindowData *data )
     }
 }
 
+static SDL_FORCE_INLINE BOOL
+WIN_ConvertUTF32toUTF8(UINT32 codepoint, char * text)
+{
+    if (codepoint <= 0x7F) {
+        text[0] = (char) codepoint;
+        text[1] = '\0';
+    } else if (codepoint <= 0x7FF) {
+        text[0] = 0xC0 | (char) ((codepoint >> 6) & 0x1F);
+        text[1] = 0x80 | (char) (codepoint & 0x3F);
+        text[2] = '\0';
+    } else if (codepoint <= 0xFFFF) {
+        text[0] = 0xE0 | (char) ((codepoint >> 12) & 0x0F);
+        text[1] = 0x80 | (char) ((codepoint >> 6) & 0x3F);
+        text[2] = 0x80 | (char) (codepoint & 0x3F);
+        text[3] = '\0';
+    } else if (codepoint <= 0x10FFFF) {
+        text[0] = 0xF0 | (char) ((codepoint >> 18) & 0x0F);
+        text[1] = 0x80 | (char) ((codepoint >> 12) & 0x3F);
+        text[2] = 0x80 | (char) ((codepoint >> 6) & 0x3F);
+        text[3] = 0x80 | (char) (codepoint & 0x3F);
+        text[4] = '\0';
+    } else {
+        return SDL_FALSE;
+    }
+    return SDL_TRUE;
+}
+
 LRESULT CALLBACK
 WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
@@ -459,8 +486,23 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
         break;
 #endif /* WM_MOUSELEAVE */
 
-    case WM_SYSKEYDOWN:
     case WM_KEYDOWN:
+        {
+            BYTE keyboardState[256];
+            char text[5];
+            UINT32 utf32 = 0;
+
+            GetKeyboardState(keyboardState);
+            if (ToUnicode(wParam, (lParam >> 16) & 0xff, keyboardState, (LPWSTR)&utf32, 1, 0) > 0) {
+                WORD repitition;
+                for (repitition = lParam & 0xffff; repitition > 0; repitition--) {
+                    WIN_ConvertUTF32toUTF8(utf32, text);
+                    SDL_SendKeyboardText(text);
+                }
+            }
+        }
+        // no break
+    case WM_SYSKEYDOWN:
         {
             SDL_Scancode code = WindowsScanCodeToSDLScanCode( lParam, wParam );
             if ( code != SDL_SCANCODE_UNKNOWN ) {
@@ -485,24 +527,19 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
         returnCode = 0;
         break;
 
-    case WM_CHAR:
+    case WM_UNICHAR:
         {
-            char text[4];
-
-            /* Convert to UTF-8 and send it on... */
-            if (wParam <= 0x7F) {
-                text[0] = (char) wParam;
-                text[1] = '\0';
-            } else if (wParam <= 0x7FF) {
-                text[0] = 0xC0 | (char) ((wParam >> 6) & 0x1F);
-                text[1] = 0x80 | (char) (wParam & 0x3F);
-                text[2] = '\0';
-            } else {
-                text[0] = 0xE0 | (char) ((wParam >> 12) & 0x0F);
-                text[1] = 0x80 | (char) ((wParam >> 6) & 0x3F);
-                text[2] = 0x80 | (char) (wParam & 0x3F);
-                text[3] = '\0';
+            if (wParam == UNICODE_NOCHAR) {
+                returnCode = 1;
+                break;
             }
+        }
+        // no break
+    case WM_CHAR:
+        {
+            char text[5];
+
+            WIN_ConvertUTF32toUTF8(wParam, text);
             SDL_SendKeyboardText(text);
         }
         returnCode = 0;
@@ -772,7 +809,6 @@ WIN_PumpEvents(_THIS)
     const Uint8 *keystate;
     MSG msg;
     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
-        TranslateMessage(&msg);
         DispatchMessage(&msg);
     }