From 9a1501ae89ffe79c38dbd6756c9e7ed647dd7dc1 Mon Sep 17 00:00:00 2001 From: grorp Date: Thu, 27 Jun 2024 14:44:44 +0200 Subject: [PATCH] CIrrDeviceSDL: Fix numpad key events not having correct KeyInput.Char (#14780) Allows you to change viewing range using numpad +/- again. This fix also works with the current unreleased version of SDL 3. The keycodes for numpad keys (both SDL keycodes and Irrlicht keycodes) are not the same as the keycodes for the equivalent non-numpad keys and don't correspond to chars, so I mapped them to chars manually. Since I think the resolution of https://github.com/minetest/minetest/issues/13770 was "just disable numlock", I made sure to only do this for the numpad number keys if numlock is enabled. --- irr/src/CIrrDeviceSDL.cpp | 63 +++++++++++++++++++++++++++++++++------ irr/src/CIrrDeviceSDL.h | 4 +-- 2 files changed, 56 insertions(+), 11 deletions(-) diff --git a/irr/src/CIrrDeviceSDL.cpp b/irr/src/CIrrDeviceSDL.cpp index f8fb66da3..a930bec39 100644 --- a/irr/src/CIrrDeviceSDL.cpp +++ b/irr/src/CIrrDeviceSDL.cpp @@ -129,9 +129,9 @@ EM_BOOL CIrrDeviceSDL::MouseLeaveCallback(int eventType, const EmscriptenMouseEv } #endif -bool CIrrDeviceSDL::keyIsKnownSpecial(EKEY_CODE key) +bool CIrrDeviceSDL::keyIsKnownSpecial(EKEY_CODE irrlichtKey) { - switch (key) { + switch (irrlichtKey) { // keys which are known to have safe special character interpretation // could need changes over time (removals and additions!) case KEY_RETURN: @@ -189,24 +189,68 @@ bool CIrrDeviceSDL::keyIsKnownSpecial(EKEY_CODE key) } } -int CIrrDeviceSDL::findCharToPassToIrrlicht(int assumedChar, EKEY_CODE key) +int CIrrDeviceSDL::findCharToPassToIrrlicht(uint32_t sdlKey, EKEY_CODE irrlichtKey, bool numlock) { + switch (irrlichtKey) { // special cases that always return a char regardless of how the SDL keycode // looks - switch (key) { case KEY_RETURN: case KEY_ESCAPE: - return (int)key; + return (int)irrlichtKey; + + // This is necessary for keys on the numpad because they don't use the same + // keycodes as their non-numpad versions (whose keycodes correspond to chars), + // but have their own SDL keycodes and their own Irrlicht keycodes (which + // don't correspond to chars). + case KEY_MULTIPLY: + return '*'; + case KEY_ADD: + return '+'; + case KEY_SUBTRACT: + return '-'; + case KEY_DIVIDE: + return '/'; + default: break; } + if (numlock) { + // Number keys on the numpad are also affected, but we only want them + // to produce number chars when numlock is enabled. + switch (irrlichtKey) { + case KEY_NUMPAD0: + return '0'; + case KEY_NUMPAD1: + return '1'; + case KEY_NUMPAD2: + return '2'; + case KEY_NUMPAD3: + return '3'; + case KEY_NUMPAD4: + return '4'; + case KEY_NUMPAD5: + return '5'; + case KEY_NUMPAD6: + return '6'; + case KEY_NUMPAD7: + return '7'; + case KEY_NUMPAD8: + return '8'; + case KEY_NUMPAD9: + return '9'; + default: + break; + } + } + // SDL in-place ORs values with no character representation with 1<<30 // https://wiki.libsdl.org/SDL2/SDLKeycodeLookup - if (assumedChar & (1 << 30)) + // This also affects the numpad keys btw. + if (sdlKey & (1 << 30)) return 0; - switch (key) { + switch (irrlichtKey) { case KEY_PRIOR: case KEY_NEXT: case KEY_HOME: @@ -218,7 +262,7 @@ int CIrrDeviceSDL::findCharToPassToIrrlicht(int assumedChar, EKEY_CODE key) case KEY_NUMLOCK: return 0; default: - return assumedChar; + return sdlKey; } } @@ -825,7 +869,8 @@ bool CIrrDeviceSDL::run() irrevent.KeyInput.PressedDown = (SDL_event.type == SDL_KEYDOWN); irrevent.KeyInput.Shift = (SDL_event.key.keysym.mod & KMOD_SHIFT) != 0; irrevent.KeyInput.Control = (SDL_event.key.keysym.mod & KMOD_CTRL) != 0; - irrevent.KeyInput.Char = findCharToPassToIrrlicht(mp.SDLKey, key); + irrevent.KeyInput.Char = findCharToPassToIrrlicht(mp.SDLKey, key, + (SDL_event.key.keysym.mod & KMOD_NUM) != 0); postEventFromUser(irrevent); } break; diff --git a/irr/src/CIrrDeviceSDL.h b/irr/src/CIrrDeviceSDL.h index 8c7c7c3e1..1f91cbceb 100644 --- a/irr/src/CIrrDeviceSDL.h +++ b/irr/src/CIrrDeviceSDL.h @@ -273,10 +273,10 @@ class CIrrDeviceSDL : public CIrrDeviceStub #endif // Check if a key is a known special character with no side effects on text boxes. - static bool keyIsKnownSpecial(EKEY_CODE key); + static bool keyIsKnownSpecial(EKEY_CODE irrlichtKey); // Return the Char that should be sent to Irrlicht for the given key (either the one passed in or 0). - static int findCharToPassToIrrlicht(int assumedChar, EKEY_CODE key); + static int findCharToPassToIrrlicht(uint32_t sdlKey, EKEY_CODE irrlichtKey, bool numlock); // Check if a text box is in focus. Enable or disable SDL_TEXTINPUT events only if in focus. void resetReceiveTextInputEvents();