From a2b7e34cc3bb10008b9b810baec29d4756b053ee Mon Sep 17 00:00:00 2001 From: torcs-ng Date: Sat, 28 Mar 2020 19:00:07 +0000 Subject: [PATCH] - patch to ticket 472 git-svn-id: https://svn.code.sf.net/p/speed-dreams/code/trunk@6869 30fe4595-0a0c-4342-8851-515496e4dcbd Former-commit-id: 04a28a03b9f8d23fb0acdf8894a02c25339c7dcc Former-commit-id: 1315920c6fdf0ff6e2b492007f4c456096814ec2 --- src/libs/tgf/eventloop.cpp | 362 ++++++++++++++++++++----------------- 1 file changed, 199 insertions(+), 163 deletions(-) diff --git a/src/libs/tgf/eventloop.cpp b/src/libs/tgf/eventloop.cpp index 38f00dafe..5a8abac73 100644 --- a/src/libs/tgf/eventloop.cpp +++ b/src/libs/tgf/eventloop.cpp @@ -16,7 +16,7 @@ * * ***************************************************************************/ -/* Mimics the behavior of the GLUT callback system. +/* Mimics the behavior of the GLUT callback system. The idea was to minimize code changes when switching form GLUT to SDL */ #include @@ -31,48 +31,61 @@ class GfEventLoop::Private { public: - //! Constructor. - Private(); - - //! Translation function from SDL key to unicode if possible (or SDL key sym otherwise) - int translateKeySym(int code, int modifier, int unicode); + //! Constructor. + Private(); - //! SDL-callable wrapper for the timer callback function. - static Uint32 callTimerCB(Uint32 interval, void *pEvLoopPriv); + //! Translation function from SDL key to unicode if possible (or SDL key sym otherwise) + int translateKeySym(int code, int modifier, int unicode); + + //! SDL-callable wrapper for the timer callback function. + static Uint32 callTimerCB(Uint32 interval, void *pEvLoopPriv); public: // Public data members. - // Callback function pointers. - void (*cbKeyboardDown)(int key, int modifiers, int x, int y); - void (*cbKeyboardUp)(int key, int modifiers, int x, int y); - - void (*cbRecompute)(void); - - void (*cbTimer)(int value); - - // Variables. - bool bQuit; // Flag to go to the end of event loop. + // Callback function pointers. + void (*cbKeyboardDown)(int key, int modifiers, int x, int y); + void (*cbKeyboardUp)(int key, int modifiers, int x, int y); + + void (*cbRecompute)(void); + + void (*cbTimer)(int value); + + // Variables. + bool bQuit; // Flag to go to the end of event loop. + + //! Current "locked" key modifiers. // Caps-Lock bug + int nLockedModifiers; private: // Private data members. - //! Initialization flag for the underlying software layers. - static bool _bInitialized; + //! Initialization flag for the underlying software layers. + static bool _bInitialized; - //! Unicode for each typed SDL key sym + modifier - std::map _mapUnicodes; + //! Unicode for each typed SDL key sym + modifier + std::map _mapUnicodes; }; GfEventLoop::Private::Private() : cbKeyboardDown(0), cbKeyboardUp(0), cbRecompute(0), cbTimer(0), bQuit(false) { - static bool bInitialized = false; - if (!bInitialized) - { + static bool bInitialized = false; + if (!bInitialized) + { #if SDL_MAJOR_VERSION < 2 - SDL_EnableUNICODE(/*enable=*/1); // For keyboard "key press" event key code translation + // Enable "key press" event unicode translation. + SDL_EnableUNICODE(/*enable=*/1); + //SDL_WM_GrabInput(SDL_GRAB_ON); // Caps-Lock bug : Not better if On. + + // Caps-Lock bug + // Get initial state for locked modifiers (mainly Caps and Num-Lock). + // Note: SDL fails at taking further hits of Caps and Num-Lock keys into account, + // so we have to do it ourselves (see operator ()). + nLockedModifiers = SDL_GetModState(); + + // Done once and for all. #endif - bInitialized = true; - } + bInitialized = true; + } } // Translation function from SDL key to unicode if possible (or SDL key sym otherwise) @@ -89,219 +102,242 @@ GfEventLoop::Private::Private() int GfEventLoop::Private::translateKeySym(int code, int modifier, int unicode) { #if SDL_MAJOR_VERSION < 2 - // Generate the key Id from its code and modifier. - const Uint32 keyId = ((Uint32)code & 0x1FF) | (((Uint32)modifier) << 9); + // Generate the key Id from its code and modifier. + const Uint32 keyId = ((Uint32)code & 0x1FF) | (((Uint32)modifier) << 9); - // Search it in our unicode map. + // Search it in our unicode map. const std::map::const_iterator itUnicode = _mapUnicodes.find(keyId); - // If not found, update the map for next times. - int keyUnicode; + // If not found, update the map for next times. + int keyUnicode; if (itUnicode == _mapUnicodes.end()) - { - // Truncate unicodes above GF_MAX_KEYCODE (no need for more). - keyUnicode = unicode ? (unicode & GF_MAX_KEYCODE) : code; - _mapUnicodes[keyId] = (unsigned short)keyUnicode; - GfLogDebug("translateKeySym(c=%X, m=%X, u=%X) : '%c', id=%X, ucode=%X (nk=%d)\n", - code, modifier, unicode, // Truncate high bits for MSVC 2010 bugs. - (keyUnicode > 0 && keyUnicode < 128 && isprint(keyUnicode & 0x7F)) - ? (char)(keyUnicode & 0x7F) : ' ', - keyId, keyUnicode, _mapUnicodes.size()); - } + { + // Truncate unicodes above GF_MAX_KEYCODE (no need for more). + keyUnicode = unicode ? (unicode & GF_MAX_KEYCODE) : code; + _mapUnicodes[keyId] = (unsigned short)keyUnicode; + GfLogDebug("translateKeySym(c=%X, m=%X, u=%X) : '%c', id=%X, ucode=%X (nk=%d), ms=%X\n", + code, modifier, unicode, // Truncate high bits for MSVC 2010 bugs. + (keyUnicode > 0 && keyUnicode < 128 && isprint(keyUnicode & 0x7F)) + ? (char)(keyUnicode & 0x7F) : ' ', + keyId, keyUnicode, _mapUnicodes.size(), SDL_GetModState()); + } - // If found, get the unicode from the map. - else - keyUnicode = (*itUnicode).second; + // If found, get the unicode from the map. + else + keyUnicode = (*itUnicode).second; - // Done. - return keyUnicode; + // Done. + return keyUnicode; #else - int keyUnicode = code; //default to returning code + int keyUnicode = code; //default to returning code - // Make the Numpad key behave like the regular key - if(SDLK_KP_ENTER == code) - keyUnicode = SDLK_RETURN; + // Make the Numpad key behave like the regular key + if(SDLK_KP_ENTER == code) + keyUnicode = SDLK_RETURN; - else - { - const Uint32 keyId = ((Uint32)code & GF_MAX_KEYCODE) | (((Uint32)modifier) << 9); + else + { + const Uint32 keyId = ((Uint32)code & GF_MAX_KEYCODE) | (((Uint32)modifier) << 9); - // If unicode - add to the map... - if(unicode) - { - // Truncate unicodes above GF_MAX_KEYCODE (no need for more). - keyUnicode = (unsigned short)(unicode & GF_MAX_KEYCODE); - _mapUnicodes[keyId] = (unsigned short)keyUnicode; - GfLogDebug("translateKeySym(c=%X, m=%X, u=%X) : '%c', id=%X, ucode=%X (nk=%d)\n", - code, modifier, unicode, // Truncate high bits for MSVC 2010 bugs. - (keyUnicode > 0 && keyUnicode < 128 && isprint(keyUnicode & 0x7F)) - ? (char)(keyUnicode & 0x7F) : ' ', - keyId, keyUnicode, _mapUnicodes.size()); - } - else - { - // Search it in our unicode map. - const std::map::const_iterator itUnicode = _mapUnicodes.find(keyId); - if (itUnicode != _mapUnicodes.end()) - { - keyUnicode = (*itUnicode).second; - } - } - } + // If unicode - add to the map... + if(unicode) + { + // Truncate unicodes above GF_MAX_KEYCODE (no need for more). + keyUnicode = (unsigned short)(unicode & GF_MAX_KEYCODE); + _mapUnicodes[keyId] = (unsigned short)keyUnicode; + GfLogDebug("translateKeySym(c=%X, m=%X, u=%X) : '%c', id=%X, ucode=%X (nk=%d)\n", + code, modifier, unicode, // Truncate high bits for MSVC 2010 bugs. + (keyUnicode > 0 && keyUnicode < 128 && isprint(keyUnicode & 0x7F)) + ? (char)(keyUnicode & 0x7F) : ' ', + keyId, keyUnicode, _mapUnicodes.size()); + } + else + { + // Search it in our unicode map. + const std::map::const_iterator itUnicode = _mapUnicodes.find(keyId); + if (itUnicode != _mapUnicodes.end()) + { + keyUnicode = (*itUnicode).second; + } + } + } - return keyUnicode; + return keyUnicode; #endif } Uint32 GfEventLoop::Private::callTimerCB(Uint32 interval, void *pEvLoopPriv) { - Private* pPriv = reinterpret_cast(pEvLoopPriv); - if (pPriv->cbTimer) - pPriv->cbTimer(1); + Private* pPriv = reinterpret_cast(pEvLoopPriv); + if (pPriv->cbTimer) + pPriv->cbTimer(1); - // Returning zero will prevent the callback from being called again. - return 0; + // Returning zero will prevent the callback from being called again. + return 0; } // GfEventLoop class ============================================================ - + GfEventLoop::GfEventLoop() { - _pPrivate = new Private; + _pPrivate = new Private; } GfEventLoop::~GfEventLoop() { - delete _pPrivate; + delete _pPrivate; } void GfEventLoop::injectKeyboardEvent(int code, int modifier, int state, - int unicode, int x, int y) + int unicode, int x, int y) { - // Translate KMOD_RXX modifiers to KMOD_LXX (we make no difference) - // and ignore modifiers other than SHIFT, ALT, CTRL and META. - if (modifier) - { - if (modifier & KMOD_RSHIFT) modifier |= KMOD_LSHIFT; - if (modifier & KMOD_RCTRL) modifier |= KMOD_LCTRL; - if (modifier & KMOD_RALT) modifier |= KMOD_LALT; + // Update locked modifiers state, as SDL doesn't always do it. // Caps-Lock bug + switch (code) + { + case SDLK_CAPSLOCK: + _pPrivate->nLockedModifiers ^= KMOD_CAPS; + GfLogDebug("injectKeyboardEvent(c=%X) : lockedMod=%X (SDL says %X)\n", + code, _pPrivate->nLockedModifiers, SDL_GetModState()); + return; + case SDLK_NUMLOCKCLEAR: + _pPrivate->nLockedModifiers ^= KMOD_NUM; + GfLogDebug("injectKeyboardEvent(c=%X) : lockedMod=%X (SDL says %X)\n", + code, _pPrivate->nLockedModifiers, SDL_GetModState()); + return; + } + // Translate KMOD_RXX modifiers to KMOD_LXX (we make no difference) + // and ignore modifiers other than SHIFT, ALT, CTRL and META. + if (modifier) + { + if (modifier & KMOD_RSHIFT) modifier |= KMOD_LSHIFT; + if (modifier & KMOD_RCTRL) modifier |= KMOD_LCTRL; + if (modifier & KMOD_RALT) modifier |= KMOD_LALT; #if SDL_MAJOR_VERSION < 2 - if (modifier & KMOD_RMETA) modifier |= KMOD_LMETA; + if (modifier & KMOD_RMETA) modifier |= KMOD_LMETA; - modifier &= (KMOD_LSHIFT | KMOD_LCTRL | KMOD_LALT | KMOD_LMETA); + modifier &= (KMOD_LSHIFT | KMOD_LCTRL | KMOD_LALT | KMOD_LMETA); #else - if (modifier & KMOD_RGUI) modifier |= KMOD_LGUI; + if (modifier & KMOD_RGUI) modifier |= KMOD_LGUI; - modifier &= (KMOD_LSHIFT | KMOD_LCTRL | KMOD_LALT | KMOD_LGUI); + modifier &= (KMOD_LSHIFT | KMOD_LCTRL | KMOD_LALT | KMOD_LGUI); #endif - } + } - // Call the relevant call-back funtion if any registered. - if (state == 0) - { - if (_pPrivate->cbKeyboardDown) - _pPrivate->cbKeyboardDown(_pPrivate->translateKeySym(code, modifier, unicode), - modifier, x, y); - } - else - { - if (_pPrivate->cbKeyboardUp) - _pPrivate->cbKeyboardUp(_pPrivate->translateKeySym(code, modifier, unicode), - modifier, x, y); - } + // Toggle the Shift modifier if the Caps-Lock key is on. // Caps-Lock bug + if (_pPrivate->nLockedModifiers & KMOD_CAPS) + { + GfLogDebug("injectKeyboardEvent(c=%X, m=%X, u=%X)", + code, modifier, unicode); + modifier ^= KMOD_LSHIFT; + GfLogDebug(" => m=%X\n", modifier); + } + + // Call the relevant call-back funtion if any registered. + if (state == 0) + { + if (_pPrivate->cbKeyboardDown) + _pPrivate->cbKeyboardDown(_pPrivate->translateKeySym(code, modifier, unicode), + modifier, x, y); + } + else + { + if (_pPrivate->cbKeyboardUp) + _pPrivate->cbKeyboardUp(_pPrivate->translateKeySym(code, modifier, unicode), + modifier, x, y); + } } // The event loop itself. void GfEventLoop::operator()() { - SDL_Event event; // Event structure - - // Check for events. - while (!_pPrivate->bQuit) - { - // Loop until there are no events left in the queue. - while (!_pPrivate->bQuit && SDL_PollEvent(&event)) - { - // Process events we care about, and ignore the others. - switch(event.type) - { - case SDL_KEYDOWN: - injectKeyboardEvent(event.key.keysym.sym, event.key.keysym.mod, 0, + SDL_Event event; // Event structure + + // Check for events. + while (!_pPrivate->bQuit) + { + // Loop until there are no events left in the queue. + while (!_pPrivate->bQuit && SDL_PollEvent(&event)) + { + // Process events we care about, and ignore the others. + switch(event.type) + { + case SDL_KEYDOWN: + injectKeyboardEvent(event.key.keysym.sym, event.key.keysym.mod, 0, #if SDL_MAJOR_VERSION < 2 - event.key.keysym.unicode); + event.key.keysym.unicode); #else - 0); + 0); #endif - break; - - case SDL_KEYUP: - injectKeyboardEvent(event.key.keysym.sym, event.key.keysym.mod, 1, + break; + + case SDL_KEYUP: + injectKeyboardEvent(event.key.keysym.sym, event.key.keysym.mod, 1, #if SDL_MAJOR_VERSION < 2 - event.key.keysym.unicode); + event.key.keysym.unicode); #else - 0); + 0); #endif - break; + break; - case SDL_QUIT: - postQuit(); - break; + case SDL_QUIT: + postQuit(); + break; - default: - break; - } - } + default: + break; + } + } - if (!_pPrivate->bQuit) - { - // Recompute if anything to. - recompute(); - } - } + if (!_pPrivate->bQuit) + { + // Recompute if anything to. + recompute(); + } + } - GfLogTrace("Quitting event loop.\n"); + GfLogTrace("Quitting event loop.\n"); } void GfEventLoop::setKeyboardDownCB(void (*func)(int key, int modifiers, int x, int y)) { - _pPrivate->cbKeyboardDown = func; + _pPrivate->cbKeyboardDown = func; } void GfEventLoop::setKeyboardUpCB(void (*func)(int key, int modifiers, int x, int y)) { - _pPrivate->cbKeyboardUp = func; + _pPrivate->cbKeyboardUp = func; } void GfEventLoop::setRecomputeCB(void (*func)(void)) { - _pPrivate->cbRecompute = func; + _pPrivate->cbRecompute = func; } void GfEventLoop::setTimerCB(unsigned int millis, void (*func)(int value)) { - _pPrivate->cbTimer = func; - SDL_AddTimer(millis, Private::callTimerCB, (void*)_pPrivate); + _pPrivate->cbTimer = func; + SDL_AddTimer(millis, Private::callTimerCB, (void*)_pPrivate); } void GfEventLoop::postQuit() { - _pPrivate->bQuit = true; + _pPrivate->bQuit = true; } bool GfEventLoop::quitRequested() const { - return _pPrivate->bQuit; + return _pPrivate->bQuit; } void GfEventLoop::recompute() { - // Call the 'recompute' callback if any. - if (_pPrivate->cbRecompute) - _pPrivate->cbRecompute(); - - // ... otherwise let the CPU take breath (and fans stay at low and quiet speed, - // which would not be the case if really doing nothing). - else - SDL_Delay(1); // ms. + // Call the 'recompute' callback if any. + if (_pPrivate->cbRecompute) + _pPrivate->cbRecompute(); + + // ... otherwise let the CPU take breath (and fans stay at low and quiet speed, + // which would not be the case if really doing nothing). + else + SDL_Delay(1); // ms. }