diff options
author | Bastien Bouclet | 2017-11-24 19:37:58 +0100 |
---|---|---|
committer | GitHub | 2017-11-24 19:37:58 +0100 |
commit | 5ed745f5329a54d33f1b1551569cf9856990bea1 (patch) | |
tree | e444facb6330945c3ee03c6252b386dc8e70acad /backends | |
parent | c5caf9825e0d02036795afa87f49b7aa274cc983 (diff) | |
parent | acf87add2751ae68298f4d5b5480635d06b0ec5e (diff) | |
download | scummvm-rg350-5ed745f5329a54d33f1b1551569cf9856990bea1.tar.gz scummvm-rg350-5ed745f5329a54d33f1b1551569cf9856990bea1.tar.bz2 scummvm-rg350-5ed745f5329a54d33f1b1551569cf9856990bea1.zip |
Merge pull request #1063 from bgK/keyboard-repeat
SDL2: Improve handling of keyboard repeat events
Diffstat (limited to 'backends')
-rw-r--r-- | backends/events/default/default-events.cpp | 289 | ||||
-rw-r--r-- | backends/events/default/default-events.h | 20 | ||||
-rw-r--r-- | backends/events/sdl/sdl-events.cpp | 4 | ||||
-rw-r--r-- | backends/platform/android/events.cpp | 2 | ||||
-rw-r--r-- | backends/platform/sdl/sdl.cpp | 11 | ||||
-rw-r--r-- | backends/platform/tizen/form.cpp | 1 | ||||
-rw-r--r-- | backends/vkeybd/virtual-keyboard.cpp | 1 |
7 files changed, 183 insertions, 145 deletions
diff --git a/backends/events/default/default-events.cpp b/backends/events/default/default-events.cpp index 667914b023..8dd9599d20 100644 --- a/backends/events/default/default-events.cpp +++ b/backends/events/default/default-events.cpp @@ -40,7 +40,8 @@ DefaultEventManager::DefaultEventManager(Common::EventSource *boss) : _modifierState(0), _shouldQuit(false), _shouldRTL(false), - _confirmExitDialogActive(false) { + _confirmExitDialogActive(false), + _shouldGenerateKeyRepeatEvents(true) { assert(boss); @@ -50,10 +51,6 @@ DefaultEventManager::DefaultEventManager(Common::EventSource *boss) : _dispatcher.registerObserver(this, kEventManPriority, false); // Reset key repeat - _currentKeyDown.keycode = 0; - _currentKeyDown.ascii = 0; - _currentKeyDown.flags = 0; - _keyRepeatTime = 0; #ifdef ENABLE_VKEYBD @@ -86,163 +83,181 @@ void DefaultEventManager::init() { } bool DefaultEventManager::pollEvent(Common::Event &event) { - // Skip recording of these events - uint32 time = g_system->getMillis(true); - bool result = false; - _dispatcher.dispatch(); - if (!_eventQueue.empty()) { - event = _eventQueue.pop(); - result = true; + + if (_shouldGenerateKeyRepeatEvents) { + handleKeyRepeat(); } - if (result) { - event.synthetic = false; - switch (event.type) { - case Common::EVENT_KEYDOWN: - _modifierState = event.kbd.flags; - // init continuous event stream - _currentKeyDown.ascii = event.kbd.ascii; - _currentKeyDown.keycode = event.kbd.keycode; - _currentKeyDown.flags = event.kbd.flags; - _keyRepeatTime = time + kKeyRepeatInitialDelay; + if (_eventQueue.empty()) { + return false; + } - if (event.kbd.keycode == Common::KEYCODE_BACKSPACE) { - // WORKAROUND: Some engines incorrectly attempt to use the - // ascii value instead of the keycode to detect the backspace - // key (a non-portable behavior). This fails at least on - // Mac OS X, possibly also on other systems. - // As a workaround, we force the ascii value for backspace - // key pressed. A better fix would be for engines to stop - // making invalid assumptions about ascii values. - event.kbd.ascii = Common::KEYCODE_BACKSPACE; - _currentKeyDown.ascii = Common::KEYCODE_BACKSPACE; + event = _eventQueue.pop(); + bool forwardEvent = true; + + switch (event.type) { + case Common::EVENT_KEYDOWN: + _modifierState = event.kbd.flags; + + if (event.kbd.keycode == Common::KEYCODE_BACKSPACE) { + // WORKAROUND: Some engines incorrectly attempt to use the + // ascii value instead of the keycode to detect the backspace + // key (a non-portable behavior). This fails at least on + // Mac OS X, possibly also on other systems. + // As a workaround, we force the ascii value for backspace + // key pressed. A better fix would be for engines to stop + // making invalid assumptions about ascii values. + event.kbd.ascii = Common::KEYCODE_BACKSPACE; + _currentKeyDown.ascii = Common::KEYCODE_BACKSPACE; + } + break; + + case Common::EVENT_KEYUP: + _modifierState = event.kbd.flags; + break; + + case Common::EVENT_MOUSEMOVE: + _mousePos = event.mouse; + break; + + case Common::EVENT_LBUTTONDOWN: + _mousePos = event.mouse; + _buttonState |= LBUTTON; + break; + + case Common::EVENT_LBUTTONUP: + _mousePos = event.mouse; + _buttonState &= ~LBUTTON; + break; + + case Common::EVENT_RBUTTONDOWN: + _mousePos = event.mouse; + _buttonState |= RBUTTON; + break; + + case Common::EVENT_RBUTTONUP: + _mousePos = event.mouse; + _buttonState &= ~RBUTTON; + break; + + case Common::EVENT_MAINMENU: + if (g_engine && !g_engine->isPaused()) + g_engine->openMainMenuDialog(); + + if (_shouldQuit) + event.type = Common::EVENT_QUIT; + else if (_shouldRTL) + event.type = Common::EVENT_RTL; + break; +#ifdef ENABLE_VKEYBD + case Common::EVENT_VIRTUAL_KEYBOARD: + if (_vk->isDisplaying()) { + _vk->close(true); + } else { + if (g_engine) + g_engine->pauseEngine(true); + _vk->show(); + if (g_engine) + g_engine->pauseEngine(false); + forwardEvent = false; + } + break; +#endif +#ifdef ENABLE_KEYMAPPER + case Common::EVENT_KEYMAPPER_REMAP: + if (!_remap) { + _remap = true; + Common::RemapDialog _remapDialog; + if (g_engine) + g_engine->pauseEngine(true); + _remapDialog.runModal(); + if (g_engine) + g_engine->pauseEngine(false); + _remap = false; + } + break; +#endif + case Common::EVENT_RTL: + if (ConfMan.getBool("confirm_exit")) { + if (g_engine) + g_engine->pauseEngine(true); + GUI::MessageDialog alert(_("Do you really want to return to the Launcher?"), _("Launcher"), _("Cancel")); + forwardEvent = _shouldRTL = (alert.runModal() == GUI::kMessageOK); + if (g_engine) + g_engine->pauseEngine(false); + } else + _shouldRTL = true; + break; + + case Common::EVENT_MUTE: + if (g_engine) + g_engine->flipMute(); + break; + + case Common::EVENT_QUIT: + if (ConfMan.getBool("confirm_exit")) { + if (_confirmExitDialogActive) { + forwardEvent = false; + break; } - break; + _confirmExitDialogActive = true; + if (g_engine) + g_engine->pauseEngine(true); + GUI::MessageDialog alert(_("Do you really want to quit?"), _("Quit"), _("Cancel")); + forwardEvent = _shouldQuit = (alert.runModal() == GUI::kMessageOK); + if (g_engine) + g_engine->pauseEngine(false); + _confirmExitDialogActive = false; + } else + _shouldQuit = true; - case Common::EVENT_KEYUP: - _modifierState = event.kbd.flags; - if (event.kbd.keycode == _currentKeyDown.keycode) { - // Only stop firing events if it's the current key - _currentKeyDown.keycode = 0; - } - break; + break; - case Common::EVENT_MOUSEMOVE: - _mousePos = event.mouse; - break; + default: + break; + } - case Common::EVENT_LBUTTONDOWN: - _mousePos = event.mouse; - _buttonState |= LBUTTON; - break; + return forwardEvent; +} - case Common::EVENT_LBUTTONUP: - _mousePos = event.mouse; - _buttonState &= ~LBUTTON; - break; +void DefaultEventManager::handleKeyRepeat() { + uint32 time = g_system->getMillis(true); - case Common::EVENT_RBUTTONDOWN: - _mousePos = event.mouse; - _buttonState |= RBUTTON; - break; + if (!_eventQueue.empty()) { + // Peek in the event queue + const Common::Event &nextEvent = _eventQueue.front(); - case Common::EVENT_RBUTTONUP: - _mousePos = event.mouse; - _buttonState &= ~RBUTTON; + switch (nextEvent.type) { + case Common::EVENT_KEYDOWN: + // init continuous event stream + _currentKeyDown = nextEvent.kbd; + _keyRepeatTime = time + kKeyRepeatInitialDelay; break; - case Common::EVENT_MAINMENU: - if (g_engine && !g_engine->isPaused()) - g_engine->openMainMenuDialog(); - - if (_shouldQuit) - event.type = Common::EVENT_QUIT; - else if (_shouldRTL) - event.type = Common::EVENT_RTL; - break; -#ifdef ENABLE_VKEYBD - case Common::EVENT_VIRTUAL_KEYBOARD: - if (_vk->isDisplaying()) { - _vk->close(true); - } else { - if (g_engine) - g_engine->pauseEngine(true); - _vk->show(); - if (g_engine) - g_engine->pauseEngine(false); - result = false; - } - break; -#endif -#ifdef ENABLE_KEYMAPPER - case Common::EVENT_KEYMAPPER_REMAP: - if (!_remap) { - _remap = true; - Common::RemapDialog _remapDialog; - if (g_engine) - g_engine->pauseEngine(true); - _remapDialog.runModal(); - if (g_engine) - g_engine->pauseEngine(false); - _remap = false; + case Common::EVENT_KEYUP: + if (nextEvent.kbd.keycode == _currentKeyDown.keycode) { + // Only stop firing events if it's the current key + _currentKeyDown.keycode = Common::KEYCODE_INVALID; } break; -#endif - case Common::EVENT_RTL: - if (ConfMan.getBool("confirm_exit")) { - if (g_engine) - g_engine->pauseEngine(true); - GUI::MessageDialog alert(_("Do you really want to return to the Launcher?"), _("Launcher"), _("Cancel")); - result = _shouldRTL = (alert.runModal() == GUI::kMessageOK); - if (g_engine) - g_engine->pauseEngine(false); - } else - _shouldRTL = true; - break; - - case Common::EVENT_MUTE: - if (g_engine) - g_engine->flipMute(); - break; - - case Common::EVENT_QUIT: - if (ConfMan.getBool("confirm_exit")) { - if (_confirmExitDialogActive) { - result = false; - break; - } - _confirmExitDialogActive = true; - if (g_engine) - g_engine->pauseEngine(true); - GUI::MessageDialog alert(_("Do you really want to quit?"), _("Quit"), _("Cancel")); - result = _shouldQuit = (alert.runModal() == GUI::kMessageOK); - if (g_engine) - g_engine->pauseEngine(false); - _confirmExitDialogActive = false; - } else - _shouldQuit = true; - - break; default: break; } } else { // Check if event should be sent again (keydown) - if (_currentKeyDown.keycode != 0 && _keyRepeatTime < time) { + if (_currentKeyDown.keycode != Common::KEYCODE_INVALID && _keyRepeatTime <= time) { // fire event - event.type = Common::EVENT_KEYDOWN; - event.synthetic = true; - event.kbd.ascii = _currentKeyDown.ascii; - event.kbd.keycode = (Common::KeyCode)_currentKeyDown.keycode; - event.kbd.flags = _currentKeyDown.flags; + Common::Event repeatEvent; + repeatEvent.type = Common::EVENT_KEYDOWN; + repeatEvent.kbdRepeat = true; + repeatEvent.kbd = _currentKeyDown; _keyRepeatTime = time + kKeyRepeatSustainDelay; - result = true; + + _eventQueue.push(repeatEvent); } } - - return result; } void DefaultEventManager::pushEvent(const Common::Event &event) { diff --git a/backends/events/default/default-events.h b/backends/events/default/default-events.h index 38406c25aa..df6ebd2f14 100644 --- a/backends/events/default/default-events.h +++ b/backends/events/default/default-events.h @@ -67,12 +67,11 @@ class DefaultEventManager : public Common::EventManager, Common::EventObserver { kKeyRepeatSustainDelay = 100 }; - struct { - uint16 ascii; - byte flags; - int keycode; - } _currentKeyDown; + bool _shouldGenerateKeyRepeatEvents; + Common::KeyState _currentKeyDown; uint32 _keyRepeatTime; + + void handleKeyRepeat(); public: DefaultEventManager(Common::EventSource *boss); ~DefaultEventManager(); @@ -97,6 +96,17 @@ public: // this, please talk to tsoliman and/or LordHoto. virtual Common::Keymapper *getKeymapper() { return _keymapper; } #endif + + /** + * Controls whether repeated key down events are generated while a key is pressed + * + * Backends that generate their own keyboard repeat events should disable this. + * + * @param generateKeyRepeatEvents + */ + void setGenerateKeyRepeatEvents(bool generateKeyRepeatEvents) { + _shouldGenerateKeyRepeatEvents = generateKeyRepeatEvents; + } }; #endif diff --git a/backends/events/sdl/sdl-events.cpp b/backends/events/sdl/sdl-events.cpp index 91ca0f5df6..d01d9c6c4a 100644 --- a/backends/events/sdl/sdl-events.cpp +++ b/backends/events/sdl/sdl-events.cpp @@ -696,6 +696,10 @@ bool SdlEventSource::handleKeyDown(SDL_Event &ev, Common::Event &event) { event.kbd.keycode = SDLToOSystemKeycode(sdlKeycode); event.kbd.ascii = mapKey(sdlKeycode, (SDLMod)ev.key.keysym.mod, obtainUnicode(ev.key.keysym)); +#if SDL_VERSION_ATLEAST(2, 0, 0) + event.kbdRepeat = ev.key.repeat; +#endif + return true; } diff --git a/backends/platform/android/events.cpp b/backends/platform/android/events.cpp index b146945a01..d13d381f95 100644 --- a/backends/platform/android/events.cpp +++ b/backends/platform/android/events.cpp @@ -443,7 +443,7 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3, } if (arg5 > 0) - e.synthetic = true; + e.kbdRepeat = true; // map special keys to 'our' ascii codes switch (e.kbd.keycode) { diff --git a/backends/platform/sdl/sdl.cpp b/backends/platform/sdl/sdl.cpp index f2bf9590c5..68a987bc61 100644 --- a/backends/platform/sdl/sdl.cpp +++ b/backends/platform/sdl/sdl.cpp @@ -43,6 +43,7 @@ #include "backends/audiocd/sdl/sdl-audiocd.h" #endif +#include "backends/events/default/default-events.h" #include "backends/events/sdl/sdl-events.h" #include "backends/mutex/sdl/sdl-mutex.h" #include "backends/timer/sdl/sdl-timer.h" @@ -207,6 +208,16 @@ void OSystem_SDL::initBackend() { if (_eventSource == 0) _eventSource = new SdlEventSource(); + if (_eventManager == nullptr) { + DefaultEventManager *eventManager = new DefaultEventManager(_eventSource); +#if SDL_VERSION_ATLEAST(2, 0, 0) + // SDL 2 generates its own keyboard repeat events. + eventManager->setGenerateKeyRepeatEvents(false); +#endif + _eventManager = eventManager; + } + + #ifdef USE_OPENGL #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_DisplayMode displayMode; diff --git a/backends/platform/tizen/form.cpp b/backends/platform/tizen/form.cpp index 2a9a3967cc..22e15f61c4 100644 --- a/backends/platform/tizen/form.cpp +++ b/backends/platform/tizen/form.cpp @@ -243,7 +243,6 @@ void TizenAppForm::pushEvent(Common::EventType type, const Point ¤tPositio void TizenAppForm::pushKey(Common::KeyCode keycode) { if (_eventQueueLock) { Common::Event e; - e.synthetic = false; e.kbd.keycode = keycode; e.kbd.ascii = keycode; e.kbd.flags = 0; diff --git a/backends/vkeybd/virtual-keyboard.cpp b/backends/vkeybd/virtual-keyboard.cpp index ce19e9d462..80d7313a8c 100644 --- a/backends/vkeybd/virtual-keyboard.cpp +++ b/backends/vkeybd/virtual-keyboard.cpp @@ -242,7 +242,6 @@ void VirtualKeyboard::show() { // push keydown & keyup events into the event manager Event evt; - evt.synthetic = false; while (!_keyQueue.empty()) { evt.kbd = _keyQueue.pop(); evt.type = EVENT_KEYDOWN; |