ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

sdl-events.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "common/scummsys.h"
00024 
00025 #if defined(SDL_BACKEND)
00026 
00027 #include "backends/events/sdl/sdl-events.h"
00028 #include "backends/platform/sdl/sdl.h"
00029 #include "backends/graphics/graphics.h"
00030 #include "common/config-manager.h"
00031 #include "common/textconsole.h"
00032 #include "common/fs.h"
00033 #include "engines/engine.h"
00034 #include "gui/gui-manager.h"
00035 
00036 #if SDL_VERSION_ATLEAST(2, 0, 0)
00037 #define GAMECONTROLLERDB_FILE "gamecontrollerdb.txt"
00038 
00039 static uint32 convUTF8ToUTF32(const char *src) {
00040     uint32 utf32 = 0;
00041 
00042     char *dst = SDL_iconv_string(
00043 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
00044                                  "UTF-32BE",
00045 #else
00046                                  "UTF-32LE",
00047 #endif
00048                                  "UTF-8", src, SDL_strlen(src) + 1);
00049 
00050     if (dst) {
00051         utf32 = *((uint32 *)dst);
00052         SDL_free(dst);
00053     }
00054 
00055     return utf32;
00056 }
00057 
00058 void SdlEventSource::loadGameControllerMappingFile() {
00059     bool loaded = false;
00060     if (ConfMan.hasKey("controller_map_db")) {
00061         Common::FSNode file = Common::FSNode(ConfMan.get("controller_map_db"));
00062         if (file.exists()) {
00063             if (SDL_GameControllerAddMappingsFromFile(file.getPath().c_str()) < 0)
00064                 error("File %s not valid: %s", file.getPath().c_str(), SDL_GetError());
00065             else {
00066                 loaded = true;
00067                 debug("Game controller DB file loaded: %s", file.getPath().c_str());
00068             }
00069         } else
00070             warning("Game controller DB file not found: %s", file.getPath().c_str());
00071     }
00072     if (!loaded && ConfMan.hasKey("extrapath")) {
00073         Common::FSNode dir = Common::FSNode(ConfMan.get("extrapath"));
00074         Common::FSNode file = dir.getChild(GAMECONTROLLERDB_FILE);
00075         if (file.exists()) {
00076             if (SDL_GameControllerAddMappingsFromFile(file.getPath().c_str()) < 0)
00077                 error("File %s not valid: %s", file.getPath().c_str(), SDL_GetError());
00078             else
00079                 debug("Game controller DB file loaded: %s", file.getPath().c_str());
00080         }
00081     }
00082 }
00083 #endif
00084 
00085 SdlEventSource::SdlEventSource()
00086     : EventSource(), _scrollLock(false), _joystick(0), _lastScreenID(0), _graphicsManager(0), _queuedFakeMouseMove(false),
00087       _lastHatPosition(SDL_HAT_CENTERED), _mouseX(0), _mouseY(0), _engineRunning(false)
00088 #if SDL_VERSION_ATLEAST(2, 0, 0)
00089       , _queuedFakeKeyUp(false), _fakeKeyUp(), _controller(nullptr)
00090 #endif
00091       {
00092     int joystick_num = ConfMan.getInt("joystick_num");
00093     if (joystick_num >= 0) {
00094         // Initialize SDL joystick subsystem
00095         if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1) {
00096             error("Could not initialize SDL: %s", SDL_GetError());
00097         }
00098 
00099 #if SDL_VERSION_ATLEAST(2, 0, 0)
00100         if (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) == -1) {
00101             error("Could not initialize SDL: %s", SDL_GetError());
00102         }
00103         loadGameControllerMappingFile();
00104 #endif
00105 
00106         openJoystick(joystick_num);
00107     }
00108 }
00109 
00110 SdlEventSource::~SdlEventSource() {
00111     closeJoystick();
00112 }
00113 
00114 int SdlEventSource::mapKey(SDL_Keycode sdlKey, SDL_Keymod mod, Uint16 unicode) {
00115     Common::KeyCode key = SDLToOSystemKeycode(sdlKey);
00116 
00117     // Keep unicode in case it's regular ASCII text, Hebrew or in case we didn't get a valid keycode
00118     //
00119     // We need to use unicode in those cases, simply because SDL1.x passes us non-layout-adjusted keycodes.
00120     // So unicode is the only way to get layout-adjusted keys.
00121     if (unicode < 0x20) {
00122         // don't use unicode, in case it's control characters
00123         unicode = 0;
00124     } else {
00125         // Use unicode, in case keycode is invalid.
00126         // Umlauts and others will set KEYCODE_INVALID on SDL2, so in such a case always keep unicode.
00127         if (key != Common::KEYCODE_INVALID) {
00128             // keycode is valid, check further also depending on modifiers
00129             if (mod & (KMOD_CTRL | KMOD_ALT)) {
00130                 // Ctrl and/or Alt is active
00131                 //
00132                 // We need to restrict unicode to only up to 0x7E, because on macOS the option/alt key will switch to
00133                 // an alternate keyboard, which will cause us to receive Unicode characters for some keys, which are outside
00134                 // of the ASCII range (e.g. alt-x will get us U+2248). We need to return 'x' for alt-x, so using unicode
00135                 // in that case would break alt-shortcuts.
00136                 if (unicode > 0x7E)
00137                     unicode = 0; // do not allow any characters above 0x7E
00138             } else {
00139                 // We allow Hebrew characters
00140                 if (unicode >= 0x05D0 && unicode <= 0x05EA)
00141                     return unicode;
00142 
00143                 // We must not restrict as much as when Ctrl/Alt-modifiers are active, otherwise
00144                 // we wouldn't let umlauts through for SDL1. For SDL1 umlauts may set for example KEYCODE_QUOTE, KEYCODE_MINUS, etc.
00145                 if (unicode > 0xFF)
00146                     unicode = 0; // do not allow any characters above 0xFF
00147             }
00148         }
00149     }
00150 
00151     // Attention:
00152     // When using SDL1.x, we will get scancodes via sdlKey, that are raw scancodes, so NOT adjusted to keyboard layout/
00153     // mapping. So for example for certain locales, we will get KEYCODE_y, when 'z' is pressed and so on.
00154     // When using SDL2.x however, we will get scancodes based on the keyboard layout.
00155 
00156     if (key >= Common::KEYCODE_F1 && key <= Common::KEYCODE_F9) {
00157         return key - Common::KEYCODE_F1 + Common::ASCII_F1;
00158     } else if (key >= Common::KEYCODE_KP0 && key <= Common::KEYCODE_KP9) {
00159         // WORKAROUND:  Disable this change for AmigaOS4 as it is breaking numpad usage ("fighting") on that platform.
00160         // This fixes bug #10558.
00161         // The actual issue here is that the SCUMM engine uses ASCII codes instead of keycodes for input.
00162         // See also the relevant FIXME in SCUMM's input.cpp.
00163         #ifndef __amigaos4__
00164             if ((mod & KMOD_NUM) == 0)
00165                 return 0; // In case Num-Lock is NOT enabled, return 0 for ascii, so that directional keys on numpad work
00166         #endif
00167         return key - Common::KEYCODE_KP0 + '0';
00168     } else if (key >= Common::KEYCODE_UP && key <= Common::KEYCODE_PAGEDOWN) {
00169         return key;
00170     } else if (unicode) {
00171         // Return unicode in case it's still set and wasn't filtered.
00172         return unicode;
00173     } else if (key >= 'a' && key <= 'z' && (mod & KMOD_SHIFT)) {
00174         return key & ~0x20;
00175     } else if (key >= Common::KEYCODE_NUMLOCK && key < Common::KEYCODE_LAST) {
00176         return 0;
00177     } else {
00178         return key;
00179     }
00180 }
00181 
00182 bool SdlEventSource::processMouseEvent(Common::Event &event, int x, int y, int relx, int rely) {
00183     _mouseX = x;
00184     _mouseY = y;
00185 
00186     event.mouse.x = x;
00187     event.mouse.y = y;
00188 
00189     if (_graphicsManager) {
00190         return _graphicsManager->notifyMousePosition(event.mouse);
00191     }
00192 
00193     return true;
00194 }
00195 
00196 void SdlEventSource::SDLModToOSystemKeyFlags(SDL_Keymod mod, Common::Event &event) {
00197 
00198     event.kbd.flags = 0;
00199 
00200     if (mod & KMOD_SHIFT)
00201         event.kbd.flags |= Common::KBD_SHIFT;
00202     if (mod & KMOD_ALT)
00203         event.kbd.flags |= Common::KBD_ALT;
00204     if (mod & KMOD_CTRL)
00205         event.kbd.flags |= Common::KBD_CTRL;
00206 #if SDL_VERSION_ATLEAST(2, 0, 0)
00207     if (mod & KMOD_GUI)
00208         event.kbd.flags |= Common::KBD_META;
00209 #else
00210     if (mod & KMOD_META)
00211         event.kbd.flags |= Common::KBD_META;
00212 #endif
00213 
00214     // Sticky flags
00215     if (mod & KMOD_NUM)
00216         event.kbd.flags |= Common::KBD_NUM;
00217     if (mod & KMOD_CAPS)
00218         event.kbd.flags |= Common::KBD_CAPS;
00219 }
00220 
00221 Common::KeyCode SdlEventSource::SDLToOSystemKeycode(const SDL_Keycode key) {
00222     switch (key) {
00223     case SDLK_BACKSPACE: return Common::KEYCODE_BACKSPACE;
00224     case SDLK_TAB: return Common::KEYCODE_TAB;
00225     case SDLK_CLEAR: return Common::KEYCODE_CLEAR;
00226     case SDLK_RETURN: return Common::KEYCODE_RETURN;
00227     case SDLK_PAUSE: return Common::KEYCODE_PAUSE;
00228     case SDLK_ESCAPE: return Common::KEYCODE_ESCAPE;
00229     case SDLK_SPACE: return Common::KEYCODE_SPACE;
00230     case SDLK_EXCLAIM: return Common::KEYCODE_EXCLAIM;
00231     case SDLK_QUOTEDBL: return Common::KEYCODE_QUOTEDBL;
00232     case SDLK_HASH: return Common::KEYCODE_HASH;
00233     case SDLK_DOLLAR: return Common::KEYCODE_DOLLAR;
00234     case SDLK_AMPERSAND: return Common::KEYCODE_AMPERSAND;
00235     case SDLK_QUOTE: return Common::KEYCODE_QUOTE;
00236     case SDLK_LEFTPAREN: return Common::KEYCODE_LEFTPAREN;
00237     case SDLK_RIGHTPAREN: return Common::KEYCODE_RIGHTPAREN;
00238     case SDLK_ASTERISK: return Common::KEYCODE_ASTERISK;
00239     case SDLK_PLUS: return Common::KEYCODE_PLUS;
00240     case SDLK_COMMA: return Common::KEYCODE_COMMA;
00241     case SDLK_MINUS: return Common::KEYCODE_MINUS;
00242     case SDLK_PERIOD: return Common::KEYCODE_PERIOD;
00243     case SDLK_SLASH: return Common::KEYCODE_SLASH;
00244     case SDLK_0: return Common::KEYCODE_0;
00245     case SDLK_1: return Common::KEYCODE_1;
00246     case SDLK_2: return Common::KEYCODE_2;
00247     case SDLK_3: return Common::KEYCODE_3;
00248     case SDLK_4: return Common::KEYCODE_4;
00249     case SDLK_5: return Common::KEYCODE_5;
00250     case SDLK_6: return Common::KEYCODE_6;
00251     case SDLK_7: return Common::KEYCODE_7;
00252     case SDLK_8: return Common::KEYCODE_8;
00253     case SDLK_9: return Common::KEYCODE_9;
00254     case SDLK_COLON: return Common::KEYCODE_COLON;
00255     case SDLK_SEMICOLON: return Common::KEYCODE_SEMICOLON;
00256     case SDLK_LESS: return Common::KEYCODE_LESS;
00257     case SDLK_EQUALS: return Common::KEYCODE_EQUALS;
00258     case SDLK_GREATER: return Common::KEYCODE_GREATER;
00259     case SDLK_QUESTION: return Common::KEYCODE_QUESTION;
00260     case SDLK_AT: return Common::KEYCODE_AT;
00261     case SDLK_LEFTBRACKET: return Common::KEYCODE_LEFTBRACKET;
00262     case SDLK_BACKSLASH: return Common::KEYCODE_BACKSLASH;
00263     case SDLK_RIGHTBRACKET: return Common::KEYCODE_RIGHTBRACKET;
00264     case SDLK_CARET: return Common::KEYCODE_CARET;
00265     case SDLK_UNDERSCORE: return Common::KEYCODE_UNDERSCORE;
00266     case SDLK_BACKQUOTE: return Common::KEYCODE_BACKQUOTE;
00267     case SDLK_a: return Common::KEYCODE_a;
00268     case SDLK_b: return Common::KEYCODE_b;
00269     case SDLK_c: return Common::KEYCODE_c;
00270     case SDLK_d: return Common::KEYCODE_d;
00271     case SDLK_e: return Common::KEYCODE_e;
00272     case SDLK_f: return Common::KEYCODE_f;
00273     case SDLK_g: return Common::KEYCODE_g;
00274     case SDLK_h: return Common::KEYCODE_h;
00275     case SDLK_i: return Common::KEYCODE_i;
00276     case SDLK_j: return Common::KEYCODE_j;
00277     case SDLK_k: return Common::KEYCODE_k;
00278     case SDLK_l: return Common::KEYCODE_l;
00279     case SDLK_m: return Common::KEYCODE_m;
00280     case SDLK_n: return Common::KEYCODE_n;
00281     case SDLK_o: return Common::KEYCODE_o;
00282     case SDLK_p: return Common::KEYCODE_p;
00283     case SDLK_q: return Common::KEYCODE_q;
00284     case SDLK_r: return Common::KEYCODE_r;
00285     case SDLK_s: return Common::KEYCODE_s;
00286     case SDLK_t: return Common::KEYCODE_t;
00287     case SDLK_u: return Common::KEYCODE_u;
00288     case SDLK_v: return Common::KEYCODE_v;
00289     case SDLK_w: return Common::KEYCODE_w;
00290     case SDLK_x: return Common::KEYCODE_x;
00291     case SDLK_y: return Common::KEYCODE_y;
00292     case SDLK_z: return Common::KEYCODE_z;
00293     case SDLK_DELETE: return Common::KEYCODE_DELETE;
00294     case SDLK_KP_PERIOD: return Common::KEYCODE_KP_PERIOD;
00295     case SDLK_KP_DIVIDE: return Common::KEYCODE_KP_DIVIDE;
00296     case SDLK_KP_MULTIPLY: return Common::KEYCODE_KP_MULTIPLY;
00297     case SDLK_KP_MINUS: return Common::KEYCODE_KP_MINUS;
00298     case SDLK_KP_PLUS: return Common::KEYCODE_KP_PLUS;
00299     case SDLK_KP_ENTER: return Common::KEYCODE_KP_ENTER;
00300     case SDLK_KP_EQUALS: return Common::KEYCODE_KP_EQUALS;
00301     case SDLK_UP: return Common::KEYCODE_UP;
00302     case SDLK_DOWN: return Common::KEYCODE_DOWN;
00303     case SDLK_RIGHT: return Common::KEYCODE_RIGHT;
00304     case SDLK_LEFT: return Common::KEYCODE_LEFT;
00305     case SDLK_INSERT: return Common::KEYCODE_INSERT;
00306     case SDLK_HOME: return Common::KEYCODE_HOME;
00307     case SDLK_END: return Common::KEYCODE_END;
00308     case SDLK_PAGEUP: return Common::KEYCODE_PAGEUP;
00309     case SDLK_PAGEDOWN: return Common::KEYCODE_PAGEDOWN;
00310     case SDLK_F1: return Common::KEYCODE_F1;
00311     case SDLK_F2: return Common::KEYCODE_F2;
00312     case SDLK_F3: return Common::KEYCODE_F3;
00313     case SDLK_F4: return Common::KEYCODE_F4;
00314     case SDLK_F5: return Common::KEYCODE_F5;
00315     case SDLK_F6: return Common::KEYCODE_F6;
00316     case SDLK_F7: return Common::KEYCODE_F7;
00317     case SDLK_F8: return Common::KEYCODE_F8;
00318     case SDLK_F9: return Common::KEYCODE_F9;
00319     case SDLK_F10: return Common::KEYCODE_F10;
00320     case SDLK_F11: return Common::KEYCODE_F11;
00321     case SDLK_F12: return Common::KEYCODE_F12;
00322     case SDLK_F13: return Common::KEYCODE_F13;
00323     case SDLK_F14: return Common::KEYCODE_F14;
00324     case SDLK_F15: return Common::KEYCODE_F15;
00325     case SDLK_CAPSLOCK: return Common::KEYCODE_CAPSLOCK;
00326     case SDLK_RSHIFT: return Common::KEYCODE_RSHIFT;
00327     case SDLK_LSHIFT: return Common::KEYCODE_LSHIFT;
00328     case SDLK_RCTRL: return Common::KEYCODE_RCTRL;
00329     case SDLK_LCTRL: return Common::KEYCODE_LCTRL;
00330     case SDLK_RALT: return Common::KEYCODE_RALT;
00331     case SDLK_LALT: return Common::KEYCODE_LALT;
00332     case SDLK_MODE: return Common::KEYCODE_MODE;
00333     case SDLK_HELP: return Common::KEYCODE_HELP;
00334     case SDLK_SYSREQ: return Common::KEYCODE_SYSREQ;
00335     case SDLK_MENU: return Common::KEYCODE_MENU;
00336     case SDLK_POWER: return Common::KEYCODE_POWER;
00337     case SDLK_UNDO: return Common::KEYCODE_UNDO;
00338 #if SDL_VERSION_ATLEAST(2, 0, 0)
00339     case SDLK_SCROLLLOCK: return Common::KEYCODE_SCROLLOCK;
00340     case SDLK_NUMLOCKCLEAR: return Common::KEYCODE_NUMLOCK;
00341     case SDLK_LGUI: return Common::KEYCODE_LSUPER;
00342     case SDLK_RGUI: return Common::KEYCODE_RSUPER;
00343     case SDLK_PRINTSCREEN: return Common::KEYCODE_PRINT;
00344     case SDLK_APPLICATION: return Common::KEYCODE_COMPOSE;
00345     case SDLK_KP_0: return Common::KEYCODE_KP0;
00346     case SDLK_KP_1: return Common::KEYCODE_KP1;
00347     case SDLK_KP_2: return Common::KEYCODE_KP2;
00348     case SDLK_KP_3: return Common::KEYCODE_KP3;
00349     case SDLK_KP_4: return Common::KEYCODE_KP4;
00350     case SDLK_KP_5: return Common::KEYCODE_KP5;
00351     case SDLK_KP_6: return Common::KEYCODE_KP6;
00352     case SDLK_KP_7: return Common::KEYCODE_KP7;
00353     case SDLK_KP_8: return Common::KEYCODE_KP8;
00354     case SDLK_KP_9: return Common::KEYCODE_KP9;
00355     case SDLK_PERCENT: return Common::KEYCODE_PERCENT;
00356     case SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_GRAVE): return Common::KEYCODE_TILDE;
00357     case SDLK_F16: return Common::KEYCODE_F16;
00358     case SDLK_F17: return Common::KEYCODE_F17;
00359     case SDLK_F18: return Common::KEYCODE_F18;
00360     case SDLK_SLEEP: return Common::KEYCODE_SLEEP;
00361     case SDLK_MUTE: return Common::KEYCODE_MUTE;
00362     case SDLK_VOLUMEUP: return Common::KEYCODE_VOLUMEUP;
00363     case SDLK_VOLUMEDOWN: return Common::KEYCODE_VOLUMEDOWN;
00364     case SDLK_EJECT: return Common::KEYCODE_EJECT;
00365     case SDLK_WWW: return Common::KEYCODE_WWW;
00366     case SDLK_MAIL: return Common::KEYCODE_MAIL;
00367     case SDLK_CALCULATOR: return Common::KEYCODE_CALCULATOR;
00368     case SDLK_CUT: return Common::KEYCODE_CUT;
00369     case SDLK_COPY: return Common::KEYCODE_COPY;
00370     case SDLK_PASTE: return Common::KEYCODE_PASTE;
00371     case SDLK_SELECT: return Common::KEYCODE_SELECT;
00372     case SDLK_CANCEL: return Common::KEYCODE_CANCEL;
00373     case SDLK_AC_SEARCH: return Common::KEYCODE_AC_SEARCH;
00374     case SDLK_AC_HOME: return Common::KEYCODE_AC_HOME;
00375     case SDLK_AC_BACK: return Common::KEYCODE_AC_BACK;
00376     case SDLK_AC_FORWARD: return Common::KEYCODE_AC_FORWARD;
00377     case SDLK_AC_STOP: return Common::KEYCODE_AC_STOP;
00378     case SDLK_AC_REFRESH: return Common::KEYCODE_AC_REFRESH;
00379     case SDLK_AC_BOOKMARKS: return Common::KEYCODE_AC_BOOKMARKS;
00380     case SDLK_AUDIONEXT: return Common::KEYCODE_AUDIONEXT;
00381     case SDLK_AUDIOPREV: return Common::KEYCODE_AUDIOPREV;
00382     case SDLK_AUDIOSTOP: return Common::KEYCODE_AUDIOSTOP;
00383     case SDLK_AUDIOPLAY: return Common::KEYCODE_AUDIOPLAYPAUSE;
00384     case SDLK_AUDIOMUTE: return Common::KEYCODE_AUDIOMUTE;
00385 #if SDL_VERSION_ATLEAST(2, 0, 6)
00386     case SDLK_AUDIOREWIND: return Common::KEYCODE_AUDIOREWIND;
00387     case SDLK_AUDIOFASTFORWARD: return Common::KEYCODE_AUDIOFASTFORWARD;
00388 #endif
00389 #else
00390     case SDLK_SCROLLOCK: return Common::KEYCODE_SCROLLOCK;
00391     case SDLK_NUMLOCK: return Common::KEYCODE_NUMLOCK;
00392     case SDLK_LSUPER: return Common::KEYCODE_LSUPER;
00393     case SDLK_RSUPER: return Common::KEYCODE_RSUPER;
00394     case SDLK_PRINT: return Common::KEYCODE_PRINT;
00395     case SDLK_COMPOSE: return Common::KEYCODE_COMPOSE;
00396     case SDLK_KP0: return Common::KEYCODE_KP0;
00397     case SDLK_KP1: return Common::KEYCODE_KP1;
00398     case SDLK_KP2: return Common::KEYCODE_KP2;
00399     case SDLK_KP3: return Common::KEYCODE_KP3;
00400     case SDLK_KP4: return Common::KEYCODE_KP4;
00401     case SDLK_KP5: return Common::KEYCODE_KP5;
00402     case SDLK_KP6: return Common::KEYCODE_KP6;
00403     case SDLK_KP7: return Common::KEYCODE_KP7;
00404     case SDLK_KP8: return Common::KEYCODE_KP8;
00405     case SDLK_KP9: return Common::KEYCODE_KP9;
00406     case SDLK_WORLD_16: return Common::KEYCODE_TILDE;
00407     case SDLK_BREAK: return Common::KEYCODE_BREAK;
00408     case SDLK_LMETA: return Common::KEYCODE_LMETA;
00409     case SDLK_RMETA: return Common::KEYCODE_RMETA;
00410     case SDLK_EURO: return Common::KEYCODE_EURO;
00411 #endif
00412     default: return Common::KEYCODE_INVALID;
00413     }
00414 }
00415 
00416 bool SdlEventSource::pollEvent(Common::Event &event) {
00417 
00418 #if SDL_VERSION_ATLEAST(2, 0, 0)
00419     // In case we still need to send a key up event for a key down from a
00420     // TEXTINPUT event we do this immediately.
00421     if (_queuedFakeKeyUp) {
00422         event = _fakeKeyUp;
00423         _queuedFakeKeyUp = false;
00424         return true;
00425     }
00426 #endif
00427 
00428     // If the screen changed, send an Common::EVENT_SCREEN_CHANGED
00429     int screenID = ((OSystem_SDL *)g_system)->getGraphicsManager()->getScreenChangeID();
00430     if (screenID != _lastScreenID) {
00431         _lastScreenID = screenID;
00432         event.type = Common::EVENT_SCREEN_CHANGED;
00433         return true;
00434     }
00435 
00436     if (_queuedFakeMouseMove) {
00437         event = _fakeMouseMove;
00438         _queuedFakeMouseMove = false;
00439         return true;
00440     }
00441 
00442     SDL_Event ev;
00443     while (SDL_PollEvent(&ev)) {
00444         preprocessEvents(&ev);
00445         if (dispatchSDLEvent(ev, event))
00446             return true;
00447     }
00448 
00449     return false;
00450 }
00451 
00452 bool SdlEventSource::dispatchSDLEvent(SDL_Event &ev, Common::Event &event) {
00453     switch (ev.type) {
00454     case SDL_KEYDOWN:
00455         return handleKeyDown(ev, event);
00456     case SDL_KEYUP:
00457         return handleKeyUp(ev, event);
00458     case SDL_MOUSEMOTION:
00459         return handleMouseMotion(ev, event);
00460     case SDL_MOUSEBUTTONDOWN:
00461         return handleMouseButtonDown(ev, event);
00462     case SDL_MOUSEBUTTONUP:
00463         return handleMouseButtonUp(ev, event);
00464     case SDL_SYSWMEVENT:
00465         return handleSysWMEvent(ev, event);
00466 
00467 #if SDL_VERSION_ATLEAST(2, 0, 0)
00468     case SDL_MOUSEWHEEL: {
00469         Sint32 yDir = ev.wheel.y;
00470         // We want the mouse coordinates supplied with a mouse wheel event.
00471         // However, SDL2 does not supply these, thus we use whatever we got
00472         // last time.
00473         if (!processMouseEvent(event, _mouseX, _mouseY)) {
00474             return false;
00475         }
00476         if (yDir < 0) {
00477             event.type = Common::EVENT_WHEELDOWN;
00478             return true;
00479         } else if (yDir > 0) {
00480             event.type = Common::EVENT_WHEELUP;
00481             return true;
00482         } else {
00483             return false;
00484         }
00485         }
00486 
00487     case SDL_TEXTINPUT: {
00488         // When we get a TEXTINPUT event it means we got some user input for
00489         // which no KEYDOWN exists. SDL 1.2 introduces a "fake" key down+up
00490         // in such cases. We will do the same to mimic it's behavior.
00491         event.type = Common::EVENT_KEYDOWN;
00492 
00493         event.kbd = Common::KeyState(Common::KEYCODE_INVALID, convUTF8ToUTF32(ev.text.text), 0);
00494 
00495         SDLModToOSystemKeyFlags(SDL_GetModState(), event);
00496         // Set the scroll lock sticky flag
00497         if (_scrollLock)
00498             event.kbd.flags |= Common::KBD_SCRL;
00499 
00500         // Fake a key up when we have a proper ascii value.
00501         _queuedFakeKeyUp = (event.kbd.ascii != 0);
00502         _fakeKeyUp = event;
00503         _fakeKeyUp.type = Common::EVENT_KEYUP;
00504 
00505         return _queuedFakeKeyUp;
00506         }
00507 
00508     case SDL_WINDOWEVENT:
00509         switch (ev.window.event) {
00510         case SDL_WINDOWEVENT_EXPOSED:
00511             if (_graphicsManager)
00512                 _graphicsManager->notifyVideoExpose();
00513             return false;
00514 
00515         // SDL2 documentation indicate that SDL_WINDOWEVENT_SIZE_CHANGED is sent either as a result
00516         // of the size being changed by an external event (for example the user resizing the window
00517         // or going fullscreen) or a call to the SDL API (for example SDL_SetWindowSize). On the
00518         // other hand SDL_WINDOWEVENT_RESIZED is only sent for resize resulting from an external event,
00519         // and is always preceded by a SDL_WINDOWEVENT_SIZE_CHANGED event.
00520         // We need to handle the programmatic resize as well so that the graphics manager always know
00521         // the current size. See comments in SdlWindow::createOrUpdateWindow for details of one case
00522         // where we need to call SDL_SetWindowSize and we need the resulting event to be processed.
00523         // However if the documentation is correct we can ignore SDL_WINDOWEVENT_RESIZED since when we
00524         // get one we should always get a SDL_WINDOWEVENT_SIZE_CHANGED as well.
00525         case SDL_WINDOWEVENT_SIZE_CHANGED:
00526         //case SDL_WINDOWEVENT_RESIZED:
00527             return handleResizeEvent(event, ev.window.data1, ev.window.data2);
00528 
00529         case SDL_WINDOWEVENT_FOCUS_GAINED: {
00530             // When we gain focus, we to update whether the display can turn off
00531             // dependingif a game isn't running or not
00532             event.type = Common::EVENT_FOCUS_GAINED;
00533             if (_engineRunning) {
00534                 SDL_DisableScreenSaver();
00535             } else {
00536                 SDL_EnableScreenSaver();
00537             }
00538             return true;
00539         }
00540 
00541         case SDL_WINDOWEVENT_FOCUS_LOST: {
00542             // Always allow the display to turn off if ScummVM is out of focus
00543             event.type = Common::EVENT_FOCUS_LOST;
00544             SDL_EnableScreenSaver();
00545             return true;
00546         }
00547 
00548         default:
00549             return false;
00550         }
00551 
00552     case SDL_JOYDEVICEADDED:
00553         return handleJoystickAdded(ev.jdevice, event);
00554 
00555     case SDL_JOYDEVICEREMOVED:
00556         return handleJoystickRemoved(ev.jdevice, event);
00557 
00558     case SDL_DROPFILE:
00559         event.type = Common::EVENT_DROP_FILE;
00560         event.path = Common::String(ev.drop.file);
00561         SDL_free(ev.drop.file);
00562         return true;
00563 
00564     case SDL_CLIPBOARDUPDATE:
00565         event.type = Common::EVENT_CLIPBOARD_UPDATE;
00566         return true;
00567 #else
00568     case SDL_VIDEOEXPOSE:
00569         if (_graphicsManager)
00570             _graphicsManager->notifyVideoExpose();
00571         return false;
00572 
00573     case SDL_VIDEORESIZE:
00574         return handleResizeEvent(event, ev.resize.w, ev.resize.h);
00575 #endif
00576 
00577     case SDL_QUIT:
00578         event.type = Common::EVENT_QUIT;
00579         return true;
00580 
00581     default:
00582         break;
00583     }
00584 
00585     if (_joystick) {
00586         switch (ev.type) {
00587         case SDL_JOYBUTTONDOWN:
00588             return handleJoyButtonDown(ev, event);
00589         case SDL_JOYBUTTONUP:
00590             return handleJoyButtonUp(ev, event);
00591         case SDL_JOYAXISMOTION:
00592             return handleJoyAxisMotion(ev, event);
00593         case SDL_JOYHATMOTION:
00594             return handleJoyHatMotion(ev, event);
00595         default:
00596             break;
00597         }
00598     }
00599 
00600 #if SDL_VERSION_ATLEAST(2, 0, 0)
00601     if (_controller) {
00602         switch (ev.type) {
00603         case SDL_CONTROLLERBUTTONDOWN:
00604             return handleControllerButton(ev, event, false);
00605         case SDL_CONTROLLERBUTTONUP:
00606             return handleControllerButton(ev, event, true);
00607         case SDL_CONTROLLERAXISMOTION:
00608             return handleControllerAxisMotion(ev, event);
00609         default:
00610             break;
00611         }
00612     }
00613 #endif
00614 
00615     return false;
00616 }
00617 
00618 
00619 bool SdlEventSource::handleKeyDown(SDL_Event &ev, Common::Event &event) {
00620 
00621     SDLModToOSystemKeyFlags(SDL_GetModState(), event);
00622 
00623     SDL_Keycode sdlKeycode = obtainKeycode(ev.key.keysym);
00624     Common::KeyCode key = SDLToOSystemKeycode(sdlKeycode);
00625 
00626     // Handle scroll lock as a key modifier
00627     if (key == Common::KEYCODE_SCROLLOCK)
00628         _scrollLock = !_scrollLock;
00629 
00630     if (_scrollLock)
00631         event.kbd.flags |= Common::KBD_SCRL;
00632 
00633     if (remapKey(ev, event))
00634         return true;
00635 
00636     event.type = Common::EVENT_KEYDOWN;
00637     event.kbd.keycode = key;
00638     event.kbd.ascii = mapKey(sdlKeycode, (SDL_Keymod)ev.key.keysym.mod, obtainUnicode(ev.key.keysym));
00639 
00640 #if SDL_VERSION_ATLEAST(2, 0, 0)
00641     event.kbdRepeat = ev.key.repeat;
00642 #endif
00643 
00644     return true;
00645 }
00646 
00647 bool SdlEventSource::handleKeyUp(SDL_Event &ev, Common::Event &event) {
00648     if (remapKey(ev, event))
00649         return true;
00650 
00651     SDL_Keycode sdlKeycode = obtainKeycode(ev.key.keysym);
00652     SDL_Keymod mod = SDL_GetModState();
00653 
00654     event.type = Common::EVENT_KEYUP;
00655     event.kbd.keycode = SDLToOSystemKeycode(sdlKeycode);
00656     event.kbd.ascii = mapKey(sdlKeycode, (SDL_Keymod)ev.key.keysym.mod, 0);
00657 
00658     SDLModToOSystemKeyFlags(mod, event);
00659 
00660     // Set the scroll lock sticky flag
00661     if (_scrollLock)
00662         event.kbd.flags |= Common::KBD_SCRL;
00663 
00664     return true;
00665 }
00666 
00667 bool SdlEventSource::handleMouseMotion(SDL_Event &ev, Common::Event &event) {
00668     event.type = Common::EVENT_MOUSEMOVE;
00669 
00670     return processMouseEvent(event, ev.motion.x, ev.motion.y, ev.motion.xrel, ev.motion.yrel); // ResidualVM xrel,yrel
00671 }
00672 
00673 bool SdlEventSource::handleMouseButtonDown(SDL_Event &ev, Common::Event &event) {
00674     if (ev.button.button == SDL_BUTTON_LEFT)
00675         event.type = Common::EVENT_LBUTTONDOWN;
00676     else if (ev.button.button == SDL_BUTTON_RIGHT)
00677         event.type = Common::EVENT_RBUTTONDOWN;
00678 #if defined(SDL_BUTTON_WHEELUP) && defined(SDL_BUTTON_WHEELDOWN)
00679     else if (ev.button.button == SDL_BUTTON_WHEELUP)
00680         event.type = Common::EVENT_WHEELUP;
00681     else if (ev.button.button == SDL_BUTTON_WHEELDOWN)
00682         event.type = Common::EVENT_WHEELDOWN;
00683 #endif
00684 #if defined(SDL_BUTTON_MIDDLE)
00685     else if (ev.button.button == SDL_BUTTON_MIDDLE)
00686         event.type = Common::EVENT_MBUTTONDOWN;
00687 #endif
00688 #if defined(SDL_BUTTON_X1)
00689     else if (ev.button.button == SDL_BUTTON_X1)
00690         event.type = Common::EVENT_X1BUTTONDOWN;
00691 #endif
00692 #if defined(SDL_BUTTON_X2)
00693     else if (ev.button.button == SDL_BUTTON_X2)
00694         event.type = Common::EVENT_X2BUTTONDOWN;
00695 #endif
00696     else
00697         return false;
00698 
00699     return processMouseEvent(event, ev.button.x, ev.button.y);
00700 }
00701 
00702 bool SdlEventSource::handleMouseButtonUp(SDL_Event &ev, Common::Event &event) {
00703     if (ev.button.button == SDL_BUTTON_LEFT)
00704         event.type = Common::EVENT_LBUTTONUP;
00705     else if (ev.button.button == SDL_BUTTON_RIGHT)
00706         event.type = Common::EVENT_RBUTTONUP;
00707 #if defined(SDL_BUTTON_MIDDLE)
00708     else if (ev.button.button == SDL_BUTTON_MIDDLE)
00709         event.type = Common::EVENT_MBUTTONUP;
00710 #endif
00711 #if defined(SDL_BUTTON_X1)
00712     else if (ev.button.button == SDL_BUTTON_X1)
00713         event.type = Common::EVENT_X1BUTTONUP;
00714 #endif
00715 #if defined(SDL_BUTTON_X2)
00716     else if (ev.button.button == SDL_BUTTON_X2)
00717         event.type = Common::EVENT_X2BUTTONUP;
00718 #endif
00719     else
00720         return false;
00721 
00722     return processMouseEvent(event, ev.button.x, ev.button.y);
00723 }
00724 
00725 bool SdlEventSource::handleSysWMEvent(SDL_Event &ev, Common::Event &event) {
00726     return false;
00727 }
00728 
00729 void SdlEventSource::openJoystick(int joystickIndex) {
00730     if (SDL_NumJoysticks() > joystickIndex) {
00731 #if SDL_VERSION_ATLEAST(2, 0, 0)
00732         if (SDL_IsGameController(joystickIndex)) {
00733             _controller = SDL_GameControllerOpen(joystickIndex);
00734             debug("Using game controller: %s", SDL_GameControllerName(_controller));
00735         } else
00736 #endif
00737         {
00738             _joystick = SDL_JoystickOpen(joystickIndex);
00739             debug("Using joystick: %s",
00740 #if SDL_VERSION_ATLEAST(2, 0, 0)
00741                   SDL_JoystickName(_joystick)
00742 #else
00743                   SDL_JoystickName(joystickIndex)
00744 #endif
00745             );
00746         }
00747     } else {
00748         debug(5, "Invalid joystick: %d", joystickIndex);
00749     }
00750 }
00751 
00752 void SdlEventSource::closeJoystick() {
00753 #if SDL_VERSION_ATLEAST(2, 0, 0)
00754     if (_controller) {
00755         SDL_GameControllerClose(_controller);
00756         _controller = nullptr;
00757     }
00758 #endif
00759     if (_joystick) {
00760         SDL_JoystickClose(_joystick);
00761         _joystick = nullptr;
00762     }
00763 }
00764 
00765 int SdlEventSource::mapSDLJoystickButtonToOSystem(Uint8 sdlButton) {
00766     Common::JoystickButton osystemButtons[] = {
00767         Common::JOYSTICK_BUTTON_A,
00768         Common::JOYSTICK_BUTTON_B,
00769         Common::JOYSTICK_BUTTON_X,
00770         Common::JOYSTICK_BUTTON_Y,
00771         Common::JOYSTICK_BUTTON_LEFT_SHOULDER,
00772         Common::JOYSTICK_BUTTON_RIGHT_SHOULDER,
00773         Common::JOYSTICK_BUTTON_BACK,
00774         Common::JOYSTICK_BUTTON_START,
00775         Common::JOYSTICK_BUTTON_LEFT_STICK,
00776         Common::JOYSTICK_BUTTON_RIGHT_STICK
00777     };
00778 
00779     if (sdlButton >= ARRAYSIZE(osystemButtons)) {
00780         return -1;
00781     }
00782 
00783     return osystemButtons[sdlButton];
00784 }
00785 
00786 bool SdlEventSource::handleJoyButtonDown(SDL_Event &ev, Common::Event &event) {
00787     int button = mapSDLJoystickButtonToOSystem(ev.jbutton.button);
00788     if (button < 0) {
00789         return false;
00790     }
00791 
00792     event.type = Common::EVENT_JOYBUTTON_DOWN;
00793     event.joystick.button = button;
00794 
00795     return true;
00796 }
00797 
00798 bool SdlEventSource::handleJoyButtonUp(SDL_Event &ev, Common::Event &event) {
00799     int button = mapSDLJoystickButtonToOSystem(ev.jbutton.button);
00800     if (button < 0) {
00801         return false;
00802     }
00803 
00804     event.type = Common::EVENT_JOYBUTTON_UP;
00805     event.joystick.button = button;
00806 
00807     return true;
00808 }
00809 
00810 bool SdlEventSource::handleJoyAxisMotion(SDL_Event &ev, Common::Event &event) {
00811     event.type = Common::EVENT_JOYAXIS_MOTION;
00812     event.joystick.axis = ev.jaxis.axis;
00813     event.joystick.position = ev.jaxis.value;
00814 
00815     return true;
00816 }
00817 
00818 #define HANDLE_HAT_UP(new, old, mask, joybutton) \
00819     if ((old & mask) && !(new & mask)) { \
00820         event.joystick.button = joybutton; \
00821         g_system->getEventManager()->pushEvent(event); \
00822     }
00823 
00824 #define HANDLE_HAT_DOWN(new, old, mask, joybutton) \
00825     if ((new & mask) && !(old & mask)) { \
00826         event.joystick.button = joybutton; \
00827         g_system->getEventManager()->pushEvent(event); \
00828     }
00829 
00830 bool SdlEventSource::handleJoyHatMotion(SDL_Event &ev, Common::Event &event) {
00831     event.type = Common::EVENT_JOYBUTTON_UP;
00832     HANDLE_HAT_UP(ev.jhat.value, _lastHatPosition, SDL_HAT_UP, Common::JOYSTICK_BUTTON_DPAD_UP)
00833     HANDLE_HAT_UP(ev.jhat.value, _lastHatPosition, SDL_HAT_DOWN, Common::JOYSTICK_BUTTON_DPAD_DOWN)
00834     HANDLE_HAT_UP(ev.jhat.value, _lastHatPosition, SDL_HAT_LEFT, Common::JOYSTICK_BUTTON_DPAD_LEFT)
00835     HANDLE_HAT_UP(ev.jhat.value, _lastHatPosition, SDL_HAT_RIGHT, Common::JOYSTICK_BUTTON_DPAD_RIGHT)
00836 
00837     event.type = Common::EVENT_JOYBUTTON_DOWN;
00838     HANDLE_HAT_DOWN(ev.jhat.value, _lastHatPosition, SDL_HAT_UP, Common::JOYSTICK_BUTTON_DPAD_UP)
00839     HANDLE_HAT_DOWN(ev.jhat.value, _lastHatPosition, SDL_HAT_DOWN, Common::JOYSTICK_BUTTON_DPAD_DOWN)
00840     HANDLE_HAT_DOWN(ev.jhat.value, _lastHatPosition, SDL_HAT_LEFT, Common::JOYSTICK_BUTTON_DPAD_LEFT)
00841     HANDLE_HAT_DOWN(ev.jhat.value, _lastHatPosition, SDL_HAT_RIGHT, Common::JOYSTICK_BUTTON_DPAD_RIGHT)
00842 
00843     _lastHatPosition = ev.jhat.value;
00844 
00845     return false;
00846 }
00847 
00848 #if SDL_VERSION_ATLEAST(2, 0, 0)
00849 bool SdlEventSource::handleJoystickAdded(const SDL_JoyDeviceEvent &device, Common::Event &event) {
00850     debug(5, "SdlEventSource: Received joystick added event for index '%d'", device.which);
00851 
00852     int joystick_num = ConfMan.getInt("joystick_num");
00853     if (joystick_num != device.which) {
00854         return false;
00855     }
00856 
00857     debug(5, "SdlEventSource: Newly added joystick with index '%d' matches 'joysticky_num', trying to use it", device.which);
00858 
00859     closeJoystick();
00860     openJoystick(joystick_num);
00861 
00862     event.type = Common::EVENT_INPUT_CHANGED;
00863     return true;
00864 }
00865 
00866 bool SdlEventSource::handleJoystickRemoved(const SDL_JoyDeviceEvent &device, Common::Event &event) {
00867     debug(5, "SdlEventSource: Received joystick removed event for instance id '%d'", device.which);
00868 
00869     SDL_Joystick *joystick;
00870     if (_controller) {
00871         joystick = SDL_GameControllerGetJoystick(_controller);
00872     } else {
00873         joystick = _joystick;
00874     }
00875 
00876     if (!joystick) {
00877         return false;
00878     }
00879 
00880     if (SDL_JoystickInstanceID(joystick) != device.which) {
00881         return false;
00882     }
00883 
00884     debug(5, "SdlEventSource: Newly removed joystick with instance id '%d' matches currently used joystick, closing current joystick", device.which);
00885 
00886     closeJoystick();
00887 
00888     event.type = Common::EVENT_INPUT_CHANGED;
00889     return true;
00890 }
00891 
00892 int SdlEventSource::mapSDLControllerButtonToOSystem(Uint8 sdlButton) {
00893     Common::JoystickButton osystemButtons[] = {
00894         Common::JOYSTICK_BUTTON_A,
00895         Common::JOYSTICK_BUTTON_B,
00896         Common::JOYSTICK_BUTTON_X,
00897         Common::JOYSTICK_BUTTON_Y,
00898         Common::JOYSTICK_BUTTON_BACK,
00899         Common::JOYSTICK_BUTTON_GUIDE,
00900         Common::JOYSTICK_BUTTON_START,
00901         Common::JOYSTICK_BUTTON_LEFT_STICK,
00902         Common::JOYSTICK_BUTTON_RIGHT_STICK,
00903         Common::JOYSTICK_BUTTON_LEFT_SHOULDER,
00904         Common::JOYSTICK_BUTTON_RIGHT_SHOULDER,
00905         Common::JOYSTICK_BUTTON_DPAD_UP,
00906         Common::JOYSTICK_BUTTON_DPAD_DOWN,
00907         Common::JOYSTICK_BUTTON_DPAD_LEFT,
00908         Common::JOYSTICK_BUTTON_DPAD_RIGHT
00909     };
00910 
00911     if (sdlButton >= ARRAYSIZE(osystemButtons)) {
00912         return -1;
00913     }
00914 
00915     return osystemButtons[sdlButton];
00916 }
00917 
00918 bool SdlEventSource::handleControllerButton(const SDL_Event &ev, Common::Event &event, bool buttonUp) {
00919     int button = mapSDLControllerButtonToOSystem(ev.cbutton.button);
00920 
00921     if (button < 0)
00922         return false;
00923 
00924     event.type = buttonUp ? Common::EVENT_JOYBUTTON_UP : Common::EVENT_JOYBUTTON_DOWN;
00925     event.joystick.button = button;
00926 
00927     return true;
00928 }
00929 
00930 bool SdlEventSource::handleControllerAxisMotion(const SDL_Event &ev, Common::Event &event) {
00931     event.type = Common::EVENT_JOYAXIS_MOTION;
00932     event.joystick.axis = ev.caxis.axis;
00933     event.joystick.position = ev.caxis.value;
00934 
00935     return true;
00936 }
00937 #endif
00938 
00939 bool SdlEventSource::remapKey(SDL_Event &ev, Common::Event &event) {
00940     return false;
00941 }
00942 
00943 void SdlEventSource::fakeWarpMouse(const int x, const int y) {
00944     _queuedFakeMouseMove = true;
00945     _fakeMouseMove.type = Common::EVENT_MOUSEMOVE;
00946     _fakeMouseMove.mouse = Common::Point(x, y);
00947 }
00948 
00949 bool SdlEventSource::isJoystickConnected() const {
00950     return _joystick
00951 #if SDL_VERSION_ATLEAST(2, 0, 0)
00952             || _controller
00953 #endif
00954             ;
00955 }
00956 
00957 void SdlEventSource::setEngineRunning(const bool value) {
00958     _engineRunning = value;
00959 }
00960 
00961 bool SdlEventSource::handleResizeEvent(Common::Event &event, int w, int h) {
00962     if (_graphicsManager) {
00963         _graphicsManager->notifyResize(w, h);
00964 
00965         // If the screen changed, send an Common::EVENT_SCREEN_CHANGED
00966         int screenID = ((OSystem_SDL *)g_system)->getGraphicsManager()->getScreenChangeID();
00967         if (screenID != _lastScreenID) {
00968             _lastScreenID = screenID;
00969             event.type = Common::EVENT_SCREEN_CHANGED;
00970             return true;
00971         }
00972     }
00973 
00974     return false;
00975 }
00976 
00977 SDL_Keycode SdlEventSource::obtainKeycode(const SDL_Keysym keySym) {
00978 #if !SDL_VERSION_ATLEAST(2, 0, 0) && defined(WIN32)
00979     // WORKAROUND: SDL 1.2 on Windows does not use the user configured keyboard layout,
00980     // resulting in "keySym.sym" values to always be those expected for an US keyboard.
00981     // For example, SDL returns SDLK_Q when pressing the 'A' key on an AZERTY keyboard.
00982     // This defeats the purpose of keycodes which is to be able to refer to a key without
00983     // knowing where it is physically located.
00984     // We work around this issue by querying the currently active Windows keyboard layout
00985     // using the scancode provided by SDL.
00986 
00987     if (keySym.sym >= SDLK_0 && keySym.sym <= SDLK_9) {
00988         // The keycode returned by SDL is kept for the number keys.
00989         // Querying the keyboard layout for those would return the base key values
00990         // for AZERTY keyboards, which are not numbers. For example, SDLK_1 would
00991         // map to SDLK_AMPERSAND. This is theoretically correct but practically unhelpful,
00992         // because it makes it impossible to handle key combinations such as "ctrl-1".
00993         return keySym.sym;
00994     }
00995 
00996     int vk = MapVirtualKey(keySym.scancode, MAPVK_VSC_TO_VK);
00997     if (vk) {
00998         int ch = (MapVirtualKey(vk, MAPVK_VK_TO_CHAR) & 0x7FFF);
00999         // The top bit of the result of MapVirtualKey with MAPVK_VSC_TO_VK signals
01000         // a dead key was pressed. In that case we keep the value of the accent alone.
01001         if (ch) {
01002             if (ch >= 'A' && ch <= 'Z') {
01003                 // Windows returns uppercase ASCII whereas SDL expects lowercase
01004                 return (SDL_Keycode)(SDLK_a + (ch - 'A'));
01005             } else {
01006                 return (SDL_Keycode)ch;
01007             }
01008         }
01009     }
01010 #endif
01011 
01012     return keySym.sym;
01013 }
01014 
01015 uint32 SdlEventSource::obtainUnicode(const SDL_Keysym keySym) {
01016 #if SDL_VERSION_ATLEAST(2, 0, 0)
01017     SDL_Event events[2];
01018 
01019     // Update the event queue here to give SDL a chance to insert TEXTINPUT
01020     // events for KEYDOWN events. Otherwise we have a high chance that on
01021     // Windows the TEXTINPUT event is not in the event queue at this point.
01022     // In this case we will get two events with ascii values due to mapKey
01023     // and dispatchSDLEvent. This results in nasty double input of characters
01024     // in the GUI.
01025     //
01026     // FIXME: This is all a bit fragile because in mapKey we derive the ascii
01027     // value from the key code if no unicode value is given. This is legacy
01028     // behavior and should be removed anyway. If that is removed, we might not
01029     // even need to do this peeking here but instead can rely on the
01030     // SDL_TEXTINPUT case in dispatchSDLEvent to introduce keydown/keyup with
01031     // proper ASCII values (but with KEYCODE_INVALID as keycode).
01032     SDL_PumpEvents();
01033 
01034     // In SDL2, the unicode field has been removed from the keysym struct.
01035     // Instead a SDL_TEXTINPUT event is generated on key combinations that
01036     // generates unicode.
01037     // Here we peek into the event queue for the event to see if it exists.
01038     int n = SDL_PeepEvents(events, 2, SDL_PEEKEVENT, SDL_KEYDOWN, SDL_TEXTINPUT);
01039     // Make sure that the TEXTINPUT event belongs to this KEYDOWN
01040     // event and not another pending one.
01041     if ((n > 0 && events[0].type == SDL_TEXTINPUT)
01042         || (n > 1 && events[0].type != SDL_KEYDOWN && events[1].type == SDL_TEXTINPUT)) {
01043         // Remove the text input event we associate with the key press. This
01044         // makes sure we never get any SDL_TEXTINPUT events which do "belong"
01045         // to SDL_KEYDOWN events.
01046         n = SDL_PeepEvents(events, 1, SDL_GETEVENT, SDL_TEXTINPUT, SDL_TEXTINPUT);
01047         // This is basically a paranoia safety check because we know there
01048         // must be a text input event in the queue.
01049         if (n > 0) {
01050             return convUTF8ToUTF32(events[0].text.text);
01051         } else {
01052             return 0;
01053         }
01054     } else {
01055         return 0;
01056     }
01057 #else
01058     return keySym.unicode;
01059 #endif
01060 }
01061 
01062 #endif


Generated on Sat Aug 1 2020 05:01:03 for ResidualVM by doxygen 1.7.1
curved edge   curved edge