From 9d7817fa153306cdbf18d920d213e23501aca296 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Thu, 19 Jan 2006 09:09:32 +0000 Subject: [PATCH] Implemented ToUnicode() support on Windows 95/98/ME/NT/2000/XP This is a collaborative effort between Alex Volkov and John Popplewell. Thanks guys! (Fixes bug #39) --- src/video/wincommon/SDL_lowvideo.h | 5 +++ src/video/wincommon/SDL_sysevents.c | 54 +++++++++++++++++++++++++++++ src/video/windib/SDL_dibevents.c | 12 ++++--- src/video/windib/SDL_vkeys.h | 1 + src/video/windx5/SDL_dx5events.c | 13 +++---- test/checkkeys.c | 2 ++ 6 files changed, 76 insertions(+), 11 deletions(-) diff --git a/src/video/wincommon/SDL_lowvideo.h b/src/video/wincommon/SDL_lowvideo.h index b60385d36..8e5acee49 100644 --- a/src/video/wincommon/SDL_lowvideo.h +++ b/src/video/wincommon/SDL_lowvideo.h @@ -109,4 +109,9 @@ extern void DX5_SoundFocus(HWND window); GDL_CreateWindow as well */ LONG CALLBACK WinMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); +/* JFP: Implementation of ToUnicode() that works on 9x/ME/2K/XP */ +typedef int (WINAPI *ToUnicodeFN)(UINT, UINT, PBYTE, LPWSTR, int, UINT); + +extern ToUnicodeFN SDL_ToUnicode; + #endif /* SDL_lowvideo_h */ diff --git a/src/video/wincommon/SDL_sysevents.c b/src/video/wincommon/SDL_sysevents.c index ad962566d..194eeaf9a 100644 --- a/src/video/wincommon/SDL_sysevents.c +++ b/src/video/wincommon/SDL_sysevents.c @@ -79,6 +79,15 @@ void (*WIN_PaletteChanged)(_THIS, HWND window); void (*WIN_WinPAINT)(_THIS, HDC hdc); extern void DIB_SwapGamma(_THIS); +/* Variables and support functions for SDL_ToUnicode() */ +static int codepage; +static int Is9xME(); +static int GetCodePage(); +static int WINAPI ToUnicode9xME(UINT vkey, UINT scancode, BYTE *keystate, Uint16 *wchars, int wsize, UINT flags); + +ToUnicodeFN SDL_ToUnicode = ToUnicode9xME; + + #if defined(_WIN32_WCE) // dynamically load aygshell dll because we want SDL to work on HPC and be300 @@ -622,6 +631,11 @@ LONG CALLBACK WinMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) } return(0); + case WM_INPUTLANGCHANGE: { + codepage = GetCodePage(); + } + return(TRUE); + default: { /* Special handling by the video driver */ if (HandleMessage) { @@ -728,6 +742,10 @@ int SDL_RegisterApp(char *name, Uint32 style, void *hInst) /* Check for SDL_WINDOWID hack */ SDL_windowid = getenv("SDL_WINDOWID"); + /* Initialise variables for SDL_ToUnicode() */ + codepage = GetCodePage(); + SDL_ToUnicode = Is9xME() ? ToUnicode9xME : ToUnicode; + app_registered = 1; return(0); } @@ -751,3 +769,39 @@ void SDL_UnregisterApp() app_registered = 0; } +/* JFP: Implementation of ToUnicode() that works on 9x/ME/2K/XP */ + +static int Is9xME() +{ + OSVERSIONINFO info; + + memset(&info, 0, sizeof(info)); + info.dwOSVersionInfoSize = sizeof(info); + if (!GetVersionEx(&info)) { + return 0; + } + return (info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS); +} + +static int GetCodePage() +{ + char buff[8]; + int lcid = MAKELCID(LOWORD(GetKeyboardLayout(0)), SORT_DEFAULT); + int cp = GetACP(); + + if (GetLocaleInfo(lcid, LOCALE_IDEFAULTANSICODEPAGE, buff, sizeof(buff))) { + cp = atoi(buff); + } + return cp; +} + +static int WINAPI ToUnicode9xME(UINT vkey, UINT scancode, PBYTE keystate, LPWSTR wchars, int wsize, UINT flags) +{ + BYTE chars[2]; + + if (ToAsciiEx(vkey, scancode, keystate, (WORD*)chars, 0, GetKeyboardLayout(0)) == 1) { + return MultiByteToWideChar(codepage, 0, chars, 1, wchars, wsize); + } + return 0; +} + diff --git a/src/video/windib/SDL_dibevents.c b/src/video/windib/SDL_dibevents.c index 0f58c18fc..74b568ab3 100644 --- a/src/video/windib/SDL_dibevents.c +++ b/src/video/windib/SDL_dibevents.c @@ -281,6 +281,7 @@ void DIB_InitOSKeymap(_THIS) VK_keymap[VK_EQUALS] = SDLK_EQUALS; VK_keymap[VK_LBRACKET] = SDLK_LEFTBRACKET; VK_keymap[VK_BACKSLASH] = SDLK_BACKSLASH; + VK_keymap[VK_OEM_102] = SDLK_LESS; VK_keymap[VK_RBRACKET] = SDLK_RIGHTBRACKET; VK_keymap[VK_GRAVE] = SDLK_BACKQUOTE; VK_keymap[VK_BACKTICK] = SDLK_BACKQUOTE; @@ -385,17 +386,18 @@ static SDL_keysym *TranslateKey(UINT vkey, UINT scancode, SDL_keysym *keysym, in keysym->sym = VK_keymap[vkey]; keysym->mod = KMOD_NONE; keysym->unicode = 0; - if ( pressed && SDL_TranslateUNICODE ) { /* Someday use ToUnicode() */ + if ( pressed && SDL_TranslateUNICODE ) { #ifdef NO_GETKEYBOARDSTATE /* Uh oh, better hope the vkey is close enough.. */ keysym->unicode = vkey; #else - BYTE keystate[256]; - BYTE chars[2]; + BYTE keystate[256]; + Uint16 wchars[2]; GetKeyboardState(keystate); - if ( ToAscii(vkey,scancode,keystate,(WORD *)chars,0) == 1 ) { - keysym->unicode = chars[0]; + if (SDL_ToUnicode(vkey, scancode, keystate, wchars, sizeof(wchars)/sizeof(wchars[0]), 0) == 1) + { + keysym->unicode = wchars[0]; } #endif /* NO_GETKEYBOARDSTATE */ } diff --git a/src/video/windib/SDL_vkeys.h b/src/video/windib/SDL_vkeys.h index cd45faa9e..519e22b3e 100644 --- a/src/video/windib/SDL_vkeys.h +++ b/src/video/windib/SDL_vkeys.h @@ -77,3 +77,4 @@ static char rcsid = #define VK_RBRACKET 0xDD #define VK_APOSTROPHE 0xDE #define VK_BACKTICK 0xDF +#define VK_OEM_102 0xE2 diff --git a/src/video/windx5/SDL_dx5events.c b/src/video/windx5/SDL_dx5events.c index 18d83c70f..b46678805 100644 --- a/src/video/windx5/SDL_dx5events.c +++ b/src/video/windx5/SDL_dx5events.c @@ -824,11 +824,11 @@ static SDL_keysym *TranslateKey(UINT scancode, SDL_keysym *keysym, int pressed) keysym->sym = DIK_keymap[scancode]; keysym->mod = KMOD_NONE; keysym->unicode = 0; - if ( pressed && SDL_TranslateUNICODE ) { /* Someday use ToUnicode() */ + if ( pressed && SDL_TranslateUNICODE ) { UINT vkey; #ifndef NO_GETKEYBOARDSTATE - BYTE keystate[256]; - BYTE chars[2]; + BYTE keystate[256]; + Uint16 wchars[2]; #endif vkey = MapVirtualKey(scancode, 1); @@ -837,10 +837,11 @@ static SDL_keysym *TranslateKey(UINT scancode, SDL_keysym *keysym, int pressed) keysym->unicode = vkey; #else GetKeyboardState(keystate); - if ( ToAscii(vkey,scancode,keystate,(WORD *)chars,0) == 1 ) { - keysym->unicode = chars[0]; + if (SDL_ToUnicode(vkey, scancode, keystate, wchars, sizeof(wchars)/sizeof(wchars[0]), 0) == 1) + { + keysym->unicode = wchars[0]; } -#endif +#endif /* NO_GETKEYBOARDSTATE */ } return(keysym); } diff --git a/test/checkkeys.c b/test/checkkeys.c index a458ec314..8dbb24f94 100644 --- a/test/checkkeys.c +++ b/test/checkkeys.c @@ -73,6 +73,8 @@ static void PrintKey(SDL_keysym *sym, int pressed) /* This is a Latin-1 program, so only show 8-bits */ if ( !(sym->unicode & 0xFF00) ) printf(" (%c)", sym->unicode); + else + printf(" (0x%X)", sym->unicode); #endif } }