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 2013-08-16 15:35:10 -07:00
parent bb2671b7e7
commit b4b12d950e
1 changed files with 53 additions and 17 deletions

View File

@ -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_UNICHAR:
{
if (wParam == UNICODE_NOCHAR) {
returnCode = 1;
break;
}
}
// no break
case WM_CHAR:
{
char text[4];
char text[5];
/* 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';
}
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);
}