From 914996b5a6eeb938f63dffbaf543a7dc3173a629 Mon Sep 17 00:00:00 2001 From: Bastien Bouclet Date: Wed, 6 Jul 2016 07:03:25 +0200 Subject: SDL: Fix Windows SDL1 keycodes to use the active keyboard layout --- backends/events/sdl/sdl-events.cpp | 73 +++++++++++++++++++++++++++++--------- backends/events/sdl/sdl-events.h | 5 +++ 2 files changed, 62 insertions(+), 16 deletions(-) (limited to 'backends/events/sdl') diff --git a/backends/events/sdl/sdl-events.cpp b/backends/events/sdl/sdl-events.cpp index 00e2f25cbc..c7c717e300 100644 --- a/backends/events/sdl/sdl-events.cpp +++ b/backends/events/sdl/sdl-events.cpp @@ -517,15 +517,17 @@ bool SdlEventSource::handleKeyDown(SDL_Event &ev, Common::Event &event) { SDLModToOSystemKeyFlags(SDL_GetModState(), event); + SDLKey sdlKeycode = obtainKeycode(ev.key.keysym); + // Handle scroll lock as a key modifier - if (ev.key.keysym.sym == SDLK_SCROLLOCK) + if (sdlKeycode == SDLK_SCROLLOCK) _scrollLock = !_scrollLock; if (_scrollLock) event.kbd.flags |= Common::KBD_SCRL; // Ctrl-m toggles mouse capture - if (event.kbd.hasFlags(Common::KBD_CTRL) && ev.key.keysym.sym == 'm') { + if (event.kbd.hasFlags(Common::KBD_CTRL) && sdlKeycode == 'm') { if (_graphicsManager) { _graphicsManager->getWindow()->toggleMouseGrab(); } @@ -534,26 +536,26 @@ bool SdlEventSource::handleKeyDown(SDL_Event &ev, Common::Event &event) { #if defined(MACOSX) // On Macintosh, Cmd-Q quits - if ((ev.key.keysym.mod & KMOD_META) && ev.key.keysym.sym == 'q') { + if ((ev.key.keysym.mod & KMOD_META) && sdlKeycode == 'q') { event.type = Common::EVENT_QUIT; return true; } #elif defined(POSIX) // On other *nix systems, Control-Q quits - if ((ev.key.keysym.mod & KMOD_CTRL) && ev.key.keysym.sym == 'q') { + if ((ev.key.keysym.mod & KMOD_CTRL) && sdlKeycode == 'q') { event.type = Common::EVENT_QUIT; return true; } #else // Ctrl-z quits - if ((event.kbd.hasFlags(Common::KBD_CTRL) && ev.key.keysym.sym == 'z')) { + if ((event.kbd.hasFlags(Common::KBD_CTRL) && sdlKeycode == 'z')) { event.type = Common::EVENT_QUIT; return true; } #ifdef WIN32 // On Windows, also use the default Alt-F4 quit combination - if ((ev.key.keysym.mod & KMOD_ALT) && ev.key.keysym.sym == SDLK_F4) { + if ((ev.key.keysym.mod & KMOD_ALT) && sdlKeycode == SDLK_F4) { event.type = Common::EVENT_QUIT; return true; } @@ -561,7 +563,7 @@ bool SdlEventSource::handleKeyDown(SDL_Event &ev, Common::Event &event) { #endif // Ctrl-u toggles mute - if ((ev.key.keysym.mod & KMOD_CTRL) && ev.key.keysym.sym == 'u') { + if ((ev.key.keysym.mod & KMOD_CTRL) && sdlKeycode == 'u') { event.type = Common::EVENT_MUTE; return true; } @@ -570,8 +572,8 @@ bool SdlEventSource::handleKeyDown(SDL_Event &ev, Common::Event &event) { return true; event.type = Common::EVENT_KEYDOWN; - event.kbd.keycode = SDLToOSystemKeycode(ev.key.keysym.sym); - event.kbd.ascii = mapKey(ev.key.keysym.sym, (SDLMod)ev.key.keysym.mod, obtainUnicode(ev.key.keysym)); + event.kbd.keycode = SDLToOSystemKeycode(sdlKeycode); + event.kbd.ascii = mapKey(sdlKeycode, (SDLMod)ev.key.keysym.mod, obtainUnicode(ev.key.keysym)); return true; } @@ -580,6 +582,7 @@ bool SdlEventSource::handleKeyUp(SDL_Event &ev, Common::Event &event) { if (remapKey(ev, event)) return true; + SDLKey sdlKeycode = obtainKeycode(ev.key.keysym); SDLMod mod = SDL_GetModState(); // Check if this is an event handled by handleKeyDown(), and stop if it is @@ -587,21 +590,21 @@ bool SdlEventSource::handleKeyUp(SDL_Event &ev, Common::Event &event) { // Check if the Ctrl key is down, so that we can trap cases where the // user has the Ctrl key down, and has just released a special key if (mod & KMOD_CTRL) { - if (ev.key.keysym.sym == 'm' || // Ctrl-m toggles mouse capture + if (sdlKeycode == 'm' || // Ctrl-m toggles mouse capture #if defined(MACOSX) // Meta - Q, handled below #elif defined(POSIX) - ev.key.keysym.sym == 'q' || // On other *nix systems, Control-Q quits + sdlKeycode == 'q' || // On other *nix systems, Control-Q quits #else - ev.key.keysym.sym == 'z' || // Ctrl-z quit + sdlKeycode == 'z' || // Ctrl-z quit #endif - ev.key.keysym.sym == 'u') // Ctrl-u toggles mute + sdlKeycode == 'u') // Ctrl-u toggles mute return false; } // Same for other keys (Meta and Alt) #if defined(MACOSX) - if ((mod & KMOD_META) && ev.key.keysym.sym == 'q') + if ((mod & KMOD_META) && sdlKeycode == 'q') return false; // On Macintosh, Cmd-Q quits #endif @@ -609,8 +612,8 @@ bool SdlEventSource::handleKeyUp(SDL_Event &ev, Common::Event &event) { // continue normally event.type = Common::EVENT_KEYUP; - event.kbd.keycode = SDLToOSystemKeycode(ev.key.keysym.sym); - event.kbd.ascii = mapKey(ev.key.keysym.sym, (SDLMod)ev.key.keysym.mod, 0); + event.kbd.keycode = SDLToOSystemKeycode(sdlKeycode); + event.kbd.ascii = mapKey(sdlKeycode, (SDLMod)ev.key.keysym.mod, 0); // Ctrl-Alt- will change the GFX mode SDLModToOSystemKeyFlags(mod, event); @@ -868,6 +871,44 @@ bool SdlEventSource::handleResizeEvent(Common::Event &event, int w, int h) { return false; } +SDLKey SdlEventSource::obtainKeycode(const SDL_keysym keySym) { +#if !SDL_VERSION_ATLEAST(2, 0, 0) && defined(WIN32) + // WORKAROUND: SDL 1.2 on Windows does not use the user configured keyboard layout, + // resulting in "keySym.sym" values to always be those expected for an US keyboard. + // For example, SDL returns SDLK_Q when pressing the 'A' key on an AZERTY keyboard. + // This defeats the purpose of keycodes which is to be able to refer to a key without + // knowing where it is physically located. + // We work around this issue by querying the currently active Windows keyboard layout + // using the scancode provided by SDL. + + if (keySym.sym >= SDLK_0 && keySym.sym <= SDLK_9) { + // The keycode returned by SDL is kept for the number keys. + // Querying the keyboard layout for those would return the base key values + // for AZERTY keyboards, which are not numbers. For example, SDLK_1 would + // map to SDLK_AMPERSAND. This is theoratically correct but practically unhelpful, + // because it makes it impossible to handle key combinations such as "ctrl-1". + return keySym.sym; + } + + int vk = MapVirtualKey(keySym.scancode, MAPVK_VSC_TO_VK); + if (vk) { + int ch = (MapVirtualKey(vk, MAPVK_VK_TO_CHAR) & 0x7FFF); + // The top bit of the result of MapVirtualKey with MAPVK_VSC_TO_VK signals + // a dead key was pressed. In that case we keep the value of the accent alone. + if (ch) { + if (ch >= 'A' && ch <= 'Z') { + // Windows returns uppercase ASCII whereas SDL expects lowercase + return (SDLKey)(SDLK_a + (ch - 'A')); + } else { + return (SDLKey)ch; + } + } + } +#endif + + return keySym.sym; +} + uint32 SdlEventSource::obtainUnicode(const SDL_keysym keySym) { #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_Event events[2]; diff --git a/backends/events/sdl/sdl-events.h b/backends/events/sdl/sdl-events.h index caa60c1354..7e590aed3c 100644 --- a/backends/events/sdl/sdl-events.h +++ b/backends/events/sdl/sdl-events.h @@ -148,6 +148,11 @@ protected: */ uint32 obtainUnicode(const SDL_keysym keySym); + /** + * Extracts the keycode for the specified key sym. + */ + SDLKey obtainKeycode(const SDL_keysym keySym); + #if SDL_VERSION_ATLEAST(2, 0, 0) /** * Whether _fakeKeyUp contains an event we need to send. -- cgit v1.2.3