Implemented ToUnicode() support on Windows 95/98/ME/NT/2000/XP
authorSam Lantinga <slouken@libsdl.org>
Thu, 19 Jan 2006 09:09:32 +0000
changeset 1253 7c7ddaf195bf
parent 1252 57be1c741b8b
child 1254 c2ee0f7fa711
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
src/video/wincommon/SDL_sysevents.c
src/video/windib/SDL_dibevents.c
src/video/windib/SDL_vkeys.h
src/video/windx5/SDL_dx5events.c
test/checkkeys.c
--- a/src/video/wincommon/SDL_lowvideo.h	Thu Jan 19 08:53:12 2006 +0000
+++ b/src/video/wincommon/SDL_lowvideo.h	Thu Jan 19 09:09:32 2006 +0000
@@ -109,4 +109,9 @@
    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 */
--- a/src/video/wincommon/SDL_sysevents.c	Thu Jan 19 08:53:12 2006 +0000
+++ b/src/video/wincommon/SDL_sysevents.c	Thu Jan 19 09:09:32 2006 +0000
@@ -79,6 +79,15 @@
 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 @@
 		}
 		return(0);
 
+		case WM_INPUTLANGCHANGE: {
+			codepage = GetCodePage();
+		}
+		return(TRUE);
+
 		default: {
 			/* Special handling by the video driver */
 			if (HandleMessage) {
@@ -728,6 +742,10 @@
 	/* 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 @@
 	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;
+}
+
--- a/src/video/windib/SDL_dibevents.c	Thu Jan 19 08:53:12 2006 +0000
+++ b/src/video/windib/SDL_dibevents.c	Thu Jan 19 09:09:32 2006 +0000
@@ -281,6 +281,7 @@
 	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 @@
 	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 */
 	}
--- a/src/video/windib/SDL_vkeys.h	Thu Jan 19 08:53:12 2006 +0000
+++ b/src/video/windib/SDL_vkeys.h	Thu Jan 19 09:09:32 2006 +0000
@@ -77,3 +77,4 @@
 #define VK_RBRACKET	0xDD
 #define VK_APOSTROPHE	0xDE
 #define VK_BACKTICK	0xDF
+#define VK_OEM_102	0xE2
--- a/src/video/windx5/SDL_dx5events.c	Thu Jan 19 08:53:12 2006 +0000
+++ b/src/video/windx5/SDL_dx5events.c	Thu Jan 19 09:09:32 2006 +0000
@@ -824,11 +824,11 @@
 	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 @@
 		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);
 }
--- a/test/checkkeys.c	Thu Jan 19 08:53:12 2006 +0000
+++ b/test/checkkeys.c	Thu Jan 19 09:09:32 2006 +0000
@@ -73,6 +73,8 @@
 			/* 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
 		}
 	}