diff --git a/changelog.md b/changelog.md index 7e4afabb1..166512e1f 100644 --- a/changelog.md +++ b/changelog.md @@ -5,6 +5,7 @@ TGUI 1.6 (TBD) - Added addMultipleItems to ListBox and ComboBox - Added getItemByIndex, getIndexById and getIdByIndex to ComboBox - Added setSpinButtonWidth function to SpinControl +- Numpad keys may now move the cursor in text fields when Num Lock is off - setOrientation in Slider or SpinButton will no longer flip width and height - setSize in Slider or SpinButton no longer affects orientation once setOrientation is called - Fixed crash on exit when tool tip was visible diff --git a/include/TGUI/Backend/Window/BackendGui.hpp b/include/TGUI/Backend/Window/BackendGui.hpp index 3474ff00a..81e203c12 100644 --- a/include/TGUI/Backend/Window/BackendGui.hpp +++ b/include/TGUI/Backend/Window/BackendGui.hpp @@ -648,6 +648,13 @@ TGUI_MODULE_EXPORT namespace tgui ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// virtual void updateContainerSize(); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Used when the NumLock is off to translate keypad key events to key events for text cursor navigation. + // The key parameter should be a value from Numpad0 to Numpad9 and the output is the key code that corresponds to the + // wanted functionality (e.g. for Numpad0 we return the Insert key). Unknown is returned for Numpad5. + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + Event::KeyboardKey translateKeypadKey(Event::KeyboardKey key); + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public: diff --git a/include/TGUI/extlibs/IncludeSDL.hpp b/include/TGUI/extlibs/IncludeSDL.hpp index 7f3826f9d..e2170649e 100644 --- a/include/TGUI/extlibs/IncludeSDL.hpp +++ b/include/TGUI/extlibs/IncludeSDL.hpp @@ -74,6 +74,9 @@ #define SDL_KMOD_SHIFT KMOD_SHIFT #define SDL_KMOD_LSHIFT KMOD_LSHIFT #define SDL_KMOD_RSHIFT KMOD_RSHIFT + #define SDL_KMOD_CAPS KMOD_CAPS + #define SDL_KMOD_NUM KMOD_NUM + #define SDL_KMOD_SCROLL KMOD_SCROLL #endif #if SDL_MAJOR_VERSION < 2 diff --git a/src/Backend/Window/BackendGui.cpp b/src/Backend/Window/BackendGui.cpp index 8a6857cd6..83201646d 100644 --- a/src/Backend/Window/BackendGui.cpp +++ b/src/Backend/Window/BackendGui.cpp @@ -691,6 +691,35 @@ TGUI_IGNORE_DEPRECATED_WARNINGS_END } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + Event::KeyboardKey BackendGui::translateKeypadKey(Event::KeyboardKey key) + { + switch (key) + { + case Event::KeyboardKey::Numpad0: + return Event::KeyboardKey::Insert; + case Event::KeyboardKey::Numpad1: + return Event::KeyboardKey::End; + case Event::KeyboardKey::Numpad2: + return Event::KeyboardKey::Down; + case Event::KeyboardKey::Numpad3: + return Event::KeyboardKey::PageDown; + case Event::KeyboardKey::Numpad4: + return Event::KeyboardKey::Left; + case Event::KeyboardKey::Numpad6: + return Event::KeyboardKey::Right; + case Event::KeyboardKey::Numpad7: + return Event::KeyboardKey::Home; + case Event::KeyboardKey::Numpad8: + return Event::KeyboardKey::Up; + case Event::KeyboardKey::Numpad9: + return Event::KeyboardKey::PageUp; + default: // Event::KeyboardKey::Numpad5 + return Event::KeyboardKey::Unknown; // Let's ignore this key press + }; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/Backend/Window/GLFW/BackendGuiGLFW.cpp b/src/Backend/Window/GLFW/BackendGuiGLFW.cpp index 7b6438589..74a7c89e6 100644 --- a/src/Backend/Window/GLFW/BackendGuiGLFW.cpp +++ b/src/Backend/Window/GLFW/BackendGuiGLFW.cpp @@ -317,6 +317,21 @@ namespace tgui event.key.control = ((mods & GLFW_MOD_CONTROL) != 0); event.key.shift = ((mods & GLFW_MOD_SHIFT) != 0); event.key.system = ((mods & GLFW_MOD_SUPER) != 0); + + // If the NumLock is off then we will translate keypad key events to key events for text cursor navigation. + // The state of the NumLock key is only available since GLFW 3.3 and only when the GLFW_LOCK_KEY_MODS input mode is enabled. +#if GLFW_VERSION_MAJOR > 3 || (GLFW_VERSION_MAJOR == 3 && GLFW_VERSION_MINOR >= 3) + static_assert(static_cast(Event::KeyboardKey::Numpad0) + 9 == static_cast(Event::KeyboardKey::Numpad9), "Numpad0 to Numpad9 need continous ids in KeyboardKey"); + if ((static_cast(event.key.code) >= static_cast(Event::KeyboardKey::Numpad0)) + && (static_cast(event.key.code) <= static_cast(Event::KeyboardKey::Numpad9)) + && ((mods & GLFW_MOD_NUM_LOCK) == 0) && (glfwGetInputMode(m_window, GLFW_LOCK_KEY_MODS) == GLFW_TRUE)) + { + event.key.code = translateKeypadKey(event.key.code); + if (event.key.code == Event::KeyboardKey::Unknown) // Numpad5 was pressed which has no function + return {}; // We didn't handle this key press + } +#endif + return event; } @@ -503,6 +518,11 @@ namespace tgui getBackend()->attachGui(this); std::static_pointer_cast(getBackend())->setGuiWindow(this, window); +#if GLFW_VERSION_MAJOR > 3 || (GLFW_VERSION_MAJOR == 3 && GLFW_VERSION_MINOR >= 3) + // We want to know the state of the num lock key + glfwSetInputMode(window, GLFW_LOCK_KEY_MODS, GLFW_TRUE); +#endif + updateContainerSize(); } diff --git a/src/Backend/Window/SDL/BackendGuiSDL.cpp b/src/Backend/Window/SDL/BackendGuiSDL.cpp index df3489031..7e633a229 100644 --- a/src/Backend/Window/SDL/BackendGuiSDL.cpp +++ b/src/Backend/Window/SDL/BackendGuiSDL.cpp @@ -272,27 +272,34 @@ namespace tgui case SDL_EVENT_KEY_DOWN: { #if SDL_MAJOR_VERSION >= 3 + const std::uint16_t modifiers = eventSDL.key.mod; const Event::KeyboardKey code = convertKeyCode(eventSDL.key.key); - if (code == Event::KeyboardKey::Unknown) - return false; // This key isn't handled by TGUI - - eventTGUI.type = Event::Type::KeyPressed; - eventTGUI.key.code = code; - eventTGUI.key.alt = ((eventSDL.key.mod & SDL_KMOD_ALT) != 0); - eventTGUI.key.control = ((eventSDL.key.mod & SDL_KMOD_CTRL) != 0); - eventTGUI.key.shift = ((eventSDL.key.mod & SDL_KMOD_SHIFT) != 0); - eventTGUI.key.system = ((eventSDL.key.mod & SDL_KMOD_GUI) != 0); #else + const std::uint16_t modifiers = eventSDL.key.keysym.mod; const Event::KeyboardKey code = convertKeyCode(eventSDL.key.keysym.sym); +#endif if (code == Event::KeyboardKey::Unknown) return false; // This key isn't handled by TGUI eventTGUI.type = Event::Type::KeyPressed; eventTGUI.key.code = code; - eventTGUI.key.alt = ((eventSDL.key.keysym.mod & SDL_KMOD_ALT) != 0); - eventTGUI.key.control = ((eventSDL.key.keysym.mod & SDL_KMOD_CTRL) != 0); - eventTGUI.key.shift = ((eventSDL.key.keysym.mod & SDL_KMOD_SHIFT) != 0); - eventTGUI.key.system = ((eventSDL.key.keysym.mod & SDL_KMOD_GUI) != 0); + eventTGUI.key.alt = ((modifiers & SDL_KMOD_ALT) != 0); + eventTGUI.key.control = ((modifiers & SDL_KMOD_CTRL) != 0); + eventTGUI.key.shift = ((modifiers & SDL_KMOD_SHIFT) != 0); + eventTGUI.key.system = ((modifiers & SDL_KMOD_GUI) != 0); + + // If the NumLock is off then we will translate keypad key events to key events for text cursor navigation. + // We only do this for SDL 2.0.22 or newer, because the NumLock state was incorrect on Linux prior to this version. +#if (SDL_MAJOR_VERSION > 2) || ((SDL_MAJOR_VERSION == 2) && (SDL_MINOR_VERSION > 0)) || ((SDL_MAJOR_VERSION == 2) && (SDL_MINOR_VERSION == 0) && (SDL_PATCHLEVEL >= 22)) + static_assert(static_cast(Event::KeyboardKey::Numpad0) + 9 == static_cast(Event::KeyboardKey::Numpad9), "Numpad0 to Numpad9 need continous ids in KeyboardKey"); + if (((modifiers & SDL_KMOD_NUM) == 0) + && (static_cast(eventTGUI.key.code) >= static_cast(Event::KeyboardKey::Numpad0)) + && (static_cast(eventTGUI.key.code) <= static_cast(Event::KeyboardKey::Numpad9))) + { + eventTGUI.key.code = translateKeypadKey(eventTGUI.key.code); + if (eventTGUI.key.code == Event::KeyboardKey::Unknown) // Numpad5 was pressed which has no function + return false; // We didn't handle this key press + } #endif return true; } diff --git a/src/Backend/Window/SFML/BackendGuiSFML.cpp b/src/Backend/Window/SFML/BackendGuiSFML.cpp index 9fdbf3e1f..22557aad0 100644 --- a/src/Backend/Window/SFML/BackendGuiSFML.cpp +++ b/src/Backend/Window/SFML/BackendGuiSFML.cpp @@ -406,7 +406,7 @@ namespace tgui m_modifierKeyShiftPressed = eventKeyPressed->shift; m_modifierKeyAltPressed = eventKeyPressed->alt; - // When pressing a modifier key, the modifier state in the KeyEvent is still false + // When pressing a modifier key, the modifier state in the KeyEvent may still be false if ((eventKeyPressed->code == sf::Keyboard::Key::LSystem) || (eventKeyPressed->code == sf::Keyboard::Key::RSystem)) m_modifierKeySystemPressed = true; else if ((eventKeyPressed->code == sf::Keyboard::Key::LControl) || (eventKeyPressed->code == sf::Keyboard::Key::RControl)) @@ -422,6 +422,20 @@ namespace tgui eventTGUI.key.control = eventKeyPressed->control; eventTGUI.key.shift = eventKeyPressed->shift; eventTGUI.key.system = eventKeyPressed->system; + + // If the NumLock is off then we will translate keypad key events to key events for text cursor navigation. + // This functionality is not yet part of SFML, but is available in PR #3238 (https://github.com/SFML/SFML/pull/3238) +#if 0 + static_assert(static_cast(Event::KeyboardKey::Numpad0) + 9 == static_cast(Event::KeyboardKey::Numpad9), "Numpad0 to Numpad9 need continous ids in KeyboardKey"); + if (!eventKeyPressed->numLock + && (static_cast(eventTGUI.key.code) >= static_cast(Event::KeyboardKey::Numpad0)) + && (static_cast(eventTGUI.key.code) <= static_cast(Event::KeyboardKey::Numpad9))) + { + eventTGUI.key.code = translateKeypadKey(eventTGUI.key.code); + if (eventTGUI.key.code == Event::KeyboardKey::Unknown) // Numpad5 was pressed which has no function + return false; // We didn't handle this key press + } +#endif return true; } @@ -432,7 +446,7 @@ namespace tgui m_modifierKeyShiftPressed = eventKeyReleased->shift; m_modifierKeyAltPressed = eventKeyReleased->alt; - // When releasing a modifier key, the modifier state in the KeyEvent is still true + // When releasing a modifier key, the modifier state in the KeyEvent may still be true if ((eventKeyReleased->code == sf::Keyboard::Key::LSystem) || (eventKeyReleased->code == sf::Keyboard::Key::RSystem)) m_modifierKeySystemPressed = false; else if ((eventKeyReleased->code == sf::Keyboard::Key::LControl) || (eventKeyReleased->code == sf::Keyboard::Key::RControl))