From 0ee0d87b0af2c894c371fe13104e60b32a43becb Mon Sep 17 00:00:00 2001 From: Paul Reilly Date: Sat, 16 May 2020 00:54:44 +0100 Subject: [PATCH 1/2] Handle changed shift states on key release to fix remapping See issue #167 for discussion. When the shift state is different for a key press and release event and where keys are remapped to different physical CPC keys, the emulator can receive key up/downs on different keys which results in 'stuck', repeating keys. This fix tracks the shift states of physical PC keys to ensure the correct keys are pressed/released on the emulator. --- src/cap32.cpp | 20 ++++++++++++++++++-- src/keyboard.cpp | 12 ++++++------ src/keyboard.h | 4 ++-- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/cap32.cpp b/src/cap32.cpp index 968d9209..ccff10e2 100644 --- a/src/cap32.cpp +++ b/src/cap32.cpp @@ -120,6 +120,13 @@ byte *membank_config[8][4]; FILE *pfileObject; FILE *pfoPrinter; +// Store shifted keys for correct remapping where shift release state is +// different from shift state when pressed. SDL1 scancodes are uint8 values but +// SDL2 has extended scancodes with max value of 284. Future proof this array +// with that number. +static constexpr int kSDL2_Scancode_Max = 284; +static bool shifted_keys[kSDL2_Scancode_Max + 1] = {}; + #ifdef DEBUG dword dwDebugFlag = 0; FILE *pfoDebug = nullptr; @@ -2086,7 +2093,11 @@ int cap32_main (int argc, char **argv) switch (event.type) { case SDL_KEYDOWN: { - dword cpc_key = CPC.InputMapper->CPCkeyFromKeysym(event.key.keysym); + auto shift_state = static_cast(event.key.keysym.mod & KMOD_SHIFT); + // store shift state of physical keys for remapping if released after shift + shifted_keys[event.key.keysym.scancode] = shift_state; + + dword cpc_key = CPC.InputMapper->CPCkeyFromKeysym(event.key.keysym, shift_state); if (!(cpc_key & MOD_EMU_KEY)) { applyKeypress(cpc_key, keyboard_matrix, true); } @@ -2095,7 +2106,12 @@ int cap32_main (int argc, char **argv) case SDL_KEYUP: { - dword cpc_key = CPC.InputMapper->CPCkeyFromKeysym(event.key.keysym); + bool shift_state = static_cast(event.key.keysym.mod & KMOD_SHIFT); + auto scancode = event.key.keysym.scancode; + if (shift_state != shifted_keys[scancode]) { + shift_state = shifted_keys[scancode]; + } + dword cpc_key = CPC.InputMapper->CPCkeyFromKeysym(event.key.keysym, shift_state); if (!(cpc_key & MOD_EMU_KEY)) { applyKeypress(cpc_key, keyboard_matrix, false); } diff --git a/src/keyboard.cpp b/src/keyboard.cpp index b845318c..86e584f2 100644 --- a/src/keyboard.cpp +++ b/src/keyboard.cpp @@ -1402,14 +1402,14 @@ void InputMapper::init() } } -dword InputMapper::CPCkeyFromKeysym(SDL_keysym keysym) { +dword InputMapper::CPCkeyFromKeysym(SDL_keysym keysym, bool apply_shift /*= false*/) { dword sdl_key = keysym.sym; - if (keysym.mod & KMOD_SHIFT) sdl_key |= MOD_PC_SHIFT; - if (keysym.mod & KMOD_CTRL) sdl_key |= MOD_PC_CTRL; - if (keysym.mod & KMOD_MODE) sdl_key |= MOD_PC_MODE; - if (keysym.mod & KMOD_META) sdl_key |= MOD_PC_META; - if (keysym.mod & KMOD_ALT) sdl_key |= MOD_PC_ALT; + if (apply_shift) sdl_key |= MOD_PC_SHIFT; + if (keysym.mod & KMOD_CTRL) sdl_key |= MOD_PC_CTRL; + if (keysym.mod & KMOD_MODE) sdl_key |= MOD_PC_MODE; + if (keysym.mod & KMOD_META) sdl_key |= MOD_PC_META; + if (keysym.mod & KMOD_ALT) sdl_key |= MOD_PC_ALT; // Ignore sticky modifiers (MOD_PC_NUM and MOD_PC_CAPS) auto cpc_key = CPCkeysFromSDLkeysym.find(sdl_key); diff --git a/src/keyboard.h b/src/keyboard.h index 767cfe83..c1afbbf3 100644 --- a/src/keyboard.h +++ b/src/keyboard.h @@ -247,9 +247,9 @@ class InputMapper { public: InputMapper(t_CPC *CPC); - bool load_layout(const std::string& filename); + bool load_layout(const std::string& filename); void init(); - dword CPCkeyFromKeysym(SDL_keysym keysym); + dword CPCkeyFromKeysym(SDL_keysym keysym, bool apply_shift = false); dword CPCkeyFromJoystickButton(SDL_JoyButtonEvent jbutton); void CPCkeyFromJoystickAxis(SDL_JoyAxisEvent jaxis, dword *cpc_key, bool &release); std::list StringToEvents(std::string toTranslate); From 9d55428922ec429c35f1bccea7eb2176f604f1ef Mon Sep 17 00:00:00 2001 From: Paul Reilly Date: Sat, 16 May 2020 21:10:36 +0100 Subject: [PATCH 2/2] Update InputMapper tests InputMapper::CPCkeyFromKeysym functionality is changed by 0ee0d87b0af2 so add shift state in function calls. --- test/InputMapper.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/InputMapper.cpp b/test/InputMapper.cpp index df93ed8d..930c335a 100644 --- a/test/InputMapper.cpp +++ b/test/InputMapper.cpp @@ -106,7 +106,7 @@ TEST_F(InputMapperTest, Keymapping) // Exclaim keysym.sym = SDLK_1; keysym.mod = KMOD_LSHIFT; - ASSERT_EQ(0x80 | MOD_CPC_SHIFT, CPC.InputMapper->CPCkeyFromKeysym(keysym)); + ASSERT_EQ(0x80 | MOD_CPC_SHIFT, CPC.InputMapper->CPCkeyFromKeysym(keysym, true)); CPC.kbd_layout ="keymap_uk_linux.map"; CPC.keyboard = 0; @@ -114,7 +114,7 @@ TEST_F(InputMapperTest, Keymapping) // Pound keysym.sym = SDLK_3; keysym.mod = KMOD_RSHIFT; - ASSERT_EQ(0x30 | MOD_CPC_SHIFT, CPC.InputMapper->CPCkeyFromKeysym(keysym)); + ASSERT_EQ(0x30 | MOD_CPC_SHIFT, CPC.InputMapper->CPCkeyFromKeysym(keysym, true)); CPC.kbd_layout ="keymap_fr_win.map"; CPC.keyboard = 1; @@ -130,7 +130,7 @@ TEST_F(InputMapperTest, Keymapping) // N Tilde keysym.sym = SDLK_WORLD_81; keysym.mod = KMOD_LSHIFT; - ASSERT_EQ(0x35 | MOD_CPC_SHIFT, CPC.InputMapper->CPCkeyFromKeysym(keysym)); + ASSERT_EQ(0x35 | MOD_CPC_SHIFT, CPC.InputMapper->CPCkeyFromKeysym(keysym, true)); }