The SDL forums have moved to discourse.libsdl.org.
This is just a read-only archive of the previous forums, to keep old links working.


SDL Forum Index
SDL
Simple Directmedia Layer Forums
Patch: Implements ToUnicode() on 9x/ME/2K/XP for windib and
John Popplewell
Guest

Hi,

I've been working on the Windows port for Tux Paint.

It was pointed out recently that simple keyboard composition doesn't
work properly using SDL on the Windows or X11 back-ends.

Simple composition is where a 'dead' key like an acute/grave accent is
followed by an e,a,o etc. resulting in a single character.

This means that users of languages other than English have problems with
general text entry in applications that use SDL e.g. Tux Paint and
probably most of the GUIs.

Rather than trying to implement a complete solution using IM/IME (which
would allow support of Chinese, Korean, Japanese and other languages), I
thought it would be useful to fix what are effectively bugs in the
current 'windib' and 'directx' back-ends.

Many of you will be familiar with the SDL_keysym 'unicode' field which
is supposed to contain a 16-bit Unicode character, but on the current
Windows back-ends is actually a code-page relative 8-bit number.

This patch fixes that and shouldn't affect existing applications too
much as they mostly use values < 128, which are unchanged.

The patch also fixes a couple of 'windib' problems: identifying the left
and right shift keys on Windows 9x/ME, and a problem with a missing
less-than/greater-than key found on international keyboards.

The patch is against current CVS, but would be easy to apply to the
current SDL-1.2.9.

I've tested it on a couple of Win98 systems (I don't have 95 or ME), 2K
and XP. I've tried with UK, US, Spanish, German, and Polish keyboard
layouts.

I'm hoping that it's possible for this to be applied to CVS,

best regards,
John Popplewell.
P.S. I'm looking at a patch for X11 and have something that nearly works :-)

-------------- next part --------------
Index: wincommon/SDL_lowvideo.h

===================================================================

RCS file: /home/sdlweb/libsdl.org/cvs/SDL12/src/video/wincommon/SDL_lowvideo.h,v

retrieving revision 1.14

diff -c -r1.14 SDL_lowvideo.h

*** wincommon/SDL_lowvideo.h 16 Feb 2004 21:09:23 -0000 1.14

--- wincommon/SDL_lowvideo.h 13 Jan 2006 21:57:37 -0000

***************

*** 108,111 ****

--- 108,114 ----

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 */

+ extern int SDL_ToUnicode(UINT vkey, UINT scancode, BYTE *keystate, Uint16 *wchars, int wsize, UINT flags);

+

#endif /* SDL_lowvideo_h */

Index: wincommon/SDL_sysevents.c

===================================================================

RCS file: /home/sdlweb/libsdl.org/cvs/SDL12/src/video/wincommon/SDL_sysevents.c,v

retrieving revision 1.28

diff -c -r1.28 SDL_sysevents.c

*** wincommon/SDL_sysevents.c 29 Sep 2005 09:43:00 -0000 1.28

--- wincommon/SDL_sysevents.c 13 Jan 2006 21:57:37 -0000

***************

*** 710,712 ****

--- 710,753 ----

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;

+ }

+

+ int SDL_ToUnicode(UINT vkey, UINT scancode, BYTE *keystate, Uint16 *wchars, int wsize, UINT flags)

+ {

+ if (Is9xME()) {

+ BYTE chars[2];

+

+ if (ToAsciiEx(vkey, scancode, keystate, (WORD*)chars, 0, GetKeyboardLayout(0)) == 1) {

+ return MultiByteToWideChar(GetCodePage(), 0, chars, 1, wchars, wsize);

+ }

+ }

+ else {

+ return ToUnicode(vkey, scancode, keystate, wchars, wsize, flags);

+ }

+ return 0;

+ }

+

Index: windib/SDL_dibevents.c

===================================================================

RCS file: /home/sdlweb/libsdl.org/cvs/SDL12/src/video/windib/SDL_dibevents.c,v

retrieving revision 1.25

diff -c -r1.25 SDL_dibevents.c

*** windib/SDL_dibevents.c 29 Sep 2005 09:43:00 -0000 1.25

--- windib/SDL_dibevents.c 13 Jan 2006 21:57:38 -0000

***************

*** 55,60 ****

--- 55,64 ----

#define REPEATED_KEYMASK (1<<30)

#define EXTENDED_KEYMASK (1<<24)



+ /* Scancodes for LSHIFT and RSHIFT keys */

+ #define SC_LSHIFT 42

+ #define SC_RSHIFT 54

+

/* DJM: If the user setup the window for us, we want to save his window proc,

and give him a chance to handle some messages. */

static WNDPROC userWindowProc = NULL;

***************

*** 90,96 ****

wParam = VK_RSHIFT;

prev_shiftstates[1] = TRUE;

} else {

! /* Huh? */

}

break;

case VK_MENU:

--- 94,110 ----

wParam = VK_RSHIFT;

prev_shiftstates[1] = TRUE;

} else {

! /* On Win98 GetKeyState() doesn't distinguish shift-keys,

! * so try using scancode */

! Uint8 scancode = HIWORD(lParam) & 0xFF;

!

! if (!prev_shiftstates[0] && scancode == SC_LSHIFT) {

! wParam = VK_LSHIFT;

! prev_shiftstates[0] = TRUE;

! } else if (!prev_shiftstates[1] && scancode == SC_RSHIFT) {

! wParam = VK_RSHIFT;

! prev_shiftstates[1] = TRUE;

! }

}

break;

case VK_MENU:

***************

*** 143,149 ****

wParam = VK_RSHIFT;

prev_shiftstates[1] = FALSE;

} else {

! /* Huh? */

}

break;

case VK_MENU:

--- 157,173 ----

wParam = VK_RSHIFT;

prev_shiftstates[1] = FALSE;

} else {

! /* On Win98 GetKeyState() doesn't distinguish shift-keys,

! * so try using scancode */

! Uint8 scancode = HIWORD(lParam) & 0xFF;

!

! if (prev_shiftstates[0] && scancode == SC_LSHIFT) {

! wParam = VK_LSHIFT;

! prev_shiftstates[0] = FALSE;

! } else if (prev_shiftstates[1] && scancode == SC_RSHIFT) {

! wParam = VK_RSHIFT;

! prev_shiftstates[1] = FALSE;

! }

}

break;

case VK_MENU:

***************

*** 237,242 ****

--- 261,267 ----

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;

***************

*** 341,357 ****

keysym->sym = VK_keymap[vkey];

keysym->mod = KMOD_NONE;

keysym->unicode = 0;

! if ( pressed && SDL_TranslateUNICODE ) { /* Someday use ToUnicode() */

#ifdef NO_GETKEYBOARDSTATE

/* Uh oh, better hope the vkey is close enough.. */

keysym->unicode = vkey;

#else

! BYTE keystate[256];

! BYTE chars[2];



GetKeyboardState(keystate);

! if ( ToAscii(vkey,scancode,keystate,(WORD *)chars,0) == 1 ) {

! keysym->unicode = chars[0];

}

#endif /* NO_GETKEYBOARDSTATE */

}

--- 366,383 ----

keysym->sym = VK_keymap[vkey];

keysym->mod = KMOD_NONE;

keysym->unicode = 0;

! if ( pressed && SDL_TranslateUNICODE ) {

#ifdef NO_GETKEYBOARDSTATE

/* Uh oh, better hope the vkey is close enough.. */

keysym->unicode = vkey;

#else

! BYTE keystate[256];

! Uint16 wchars[2];



GetKeyboardState(keystate);

! if (SDL_ToUnicode(vkey, scancode, keystate, wchars, sizeof(wchars)/sizeof(wchars[0]), 0) == 1)

! {

! keysym->unicode = wchars[0];

}

#endif /* NO_GETKEYBOARDSTATE */

}

Index: windib/SDL_vkeys.h

===================================================================

RCS file: /home/sdlweb/libsdl.org/cvs/SDL12/src/video/windib/SDL_vkeys.h,v

retrieving revision 1.6

diff -c -r1.6 SDL_vkeys.h

*** windib/SDL_vkeys.h 4 Jan 2004 16:49:27 -0000 1.6

--- windib/SDL_vkeys.h 13 Jan 2006 21:57:38 -0000

***************

*** 77,79 ****

--- 77,80 ----

#define VK_RBRACKET 0xDD

#define VK_APOSTROPHE 0xDE

#define VK_BACKTICK 0xDF

+ #define VK_OEM_102 0xE2

Index: windx5/SDL_dx5events.c

===================================================================

RCS file: /home/sdlweb/libsdl.org/cvs/SDL12/src/video/windx5/SDL_dx5events.c,v

retrieving revision 1.25

diff -c -r1.25 SDL_dx5events.c

*** windx5/SDL_dx5events.c 11 Aug 2005 05:08:28 -0000 1.25

--- windx5/SDL_dx5events.c 13 Jan 2006 21:57:39 -0000

***************

*** 824,846 ****

keysym->sym = DIK_keymap[scancode];

keysym->mod = KMOD_NONE;

keysym->unicode = 0;

! if ( pressed && SDL_TranslateUNICODE ) { /* Someday use ToUnicode() */

UINT vkey;

- #ifndef NO_GETKEYBOARDSTATE

- BYTE keystate[256];

- BYTE chars[2];

- #endif



vkey = MapVirtualKey(scancode, 1);

#ifdef NO_GETKEYBOARDSTATE

/* Uh oh, better hope the vkey is close enough.. */

keysym->unicode = vkey;

#else

GetKeyboardState(keystate);

! if ( ToAscii(vkey,scancode,keystate,(WORD *)chars,0) == 1 ) {

! keysym->unicode = chars[0];

}

! #endif

}

return(keysym);

}

--- 824,846 ----

keysym->sym = DIK_keymap[scancode];

keysym->mod = KMOD_NONE;

keysym->unicode = 0;

! if ( pressed && SDL_TranslateUNICODE ) {

UINT vkey;



vkey = MapVirtualKey(scancode, 1);

#ifdef NO_GETKEYBOARDSTATE

/* Uh oh, better hope the vkey is close enough.. */

keysym->unicode = vkey;

#else

+ BYTE keystate[256];

+ Uint16 wchars[2];

+

GetKeyboardState(keystate);

! if (SDL_ToUnicode(vkey, scancode, keystate, wchars, sizeof(wchars)/sizeof(wchars[0]), 0) == 1)

! {

! keysym->unicode = wchars[0];

}

! #endif /* NO_GETKEYBOARDSTATE */

}

return(keysym);

}