Fixed bug 2834 - Patch to support dead keys on Windows
authorSam Lantinga <slouken@libsdl.org>
Thu, 25 Jun 2015 11:49:48 -0700
changeset 978102273530b7bf
parent 9780 7f9b74280df6
child 9782 fcf237e5e834
Fixed bug 2834 - Patch to support dead keys on Windows

Elise Maurer

When inputting text, dead-keys are currently not handled correctly on Windows with the latest SDL2 tip as well as the 2.0.3 release.

Using a French AZERTY keyboard, when I type the `^` key followed by `e` key to compose the `` character, I erroneously get two SDL_TEXTINPUT events, one with the `^` character and one with the `e` character.

I've looked at the history for SDL_windowsevents.c and there's been some back-and-forth with several methods for handling text input:

* r8142 removed any handling of WM_CHAR because keyboard input was being handled through WM_KEYDOWN along with ToUnicode since r7645.

* But using ToUnicode actually breaks dead-keys (googling for "ToUnicode dead keys" reports many horror stories of people trying to work around that and failing).

* It seems like r7645 introduced a double-fix: it fixed WM_CHAR to properly handle Unicode, and also (unnecessarily?) added text input handling to WM_KEYDOWN. Later, r8142 removed the WM_CHAR stuff instead of the WM_KEYDOWN stuff.

The attached patch restores handling of text input through WM_CHAR and removes it from WM_KEYDOWN. I've tested it with French, English and Russian layouts and it seems to do its job. Obviously, with such matters, it's still a risky change.
src/video/windows/SDL_windowsevents.c
     1.1 --- a/src/video/windows/SDL_windowsevents.c	Wed Jun 24 17:55:38 2015 -0700
     1.2 +++ b/src/video/windows/SDL_windowsevents.c	Thu Jun 25 11:49:48 2015 -0700
     1.3 @@ -295,7 +295,7 @@
     1.4      data->mouse_button_flags = 0;
     1.5  }
     1.6  
     1.7 -SDL_FORCE_INLINE BOOL
     1.8 +BOOL 
     1.9  WIN_ConvertUTF32toUTF8(UINT32 codepoint, char * text)
    1.10  {
    1.11      if (codepoint <= 0x7F) {
    1.12 @@ -568,21 +568,7 @@
    1.13                  SDL_SendKeyboardKey(SDL_PRESSED, code);
    1.14              }
    1.15          }
    1.16 -        if (msg == WM_KEYDOWN) {
    1.17 -            BYTE keyboardState[256];
    1.18 -            char text[5];
    1.19 -            UINT32 utf32 = 0;
    1.20 -
    1.21 -            GetKeyboardState(keyboardState);
    1.22 -            if (ToUnicode(wParam, (lParam >> 16) & 0xff, keyboardState, (LPWSTR)&utf32, 1, 0) > 0) {
    1.23 -                if (WIN_ConvertUTF32toUTF8(utf32, text)) {
    1.24 -                    WORD repetition;
    1.25 -                    for (repetition = lParam & 0xffff; repetition > 0; repetition--) {
    1.26 -                        SDL_SendKeyboardText(text);
    1.27 -                    }
    1.28 -                }
    1.29 -            }
    1.30 -        }
    1.31 + 
    1.32          returnCode = 0;
    1.33          break;
    1.34  
    1.35 @@ -604,9 +590,19 @@
    1.36          break;
    1.37  
    1.38      case WM_UNICHAR:
    1.39 -    case WM_CHAR:
    1.40 -        /* Ignore WM_CHAR messages that come from TranslateMessage(), since we handle WM_KEY* messages directly */
    1.41 -        returnCode = 0;
    1.42 +		if ( wParam == UNICODE_NOCHAR ) {
    1.43 +			returnCode = 1;
    1.44 +			break;
    1.45 +		}
    1.46 +		/* otherwise fall through to below */
    1.47 +	case WM_CHAR:
    1.48 +		{
    1.49 +			char text[5];
    1.50 +			if ( WIN_ConvertUTF32toUTF8( wParam, text ) ) {
    1.51 +				SDL_SendKeyboardText( text );
    1.52 +			}
    1.53 +		}
    1.54 +		returnCode = 0;
    1.55          break;
    1.56  
    1.57  #ifdef WM_INPUTLANGCHANGE