Skip to content

Commit

Permalink
Numpad keys can now be used to move the cursor in text fields when Nu…
Browse files Browse the repository at this point in the history
…m Lock is off and when using SDL >= 2.0.22 or GLFW >= 3.3 (closes #245)
  • Loading branch information
texus committed Sep 30, 2024
1 parent d82d834 commit c963cc5
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 15 deletions.
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 7 additions & 0 deletions include/TGUI/Backend/Window/BackendGui.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down
3 changes: 3 additions & 0 deletions include/TGUI/extlibs/IncludeSDL.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
29 changes: 29 additions & 0 deletions src/Backend/Window/BackendGui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
};
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
20 changes: 20 additions & 0 deletions src/Backend/Window/GLFW/BackendGuiGLFW.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<int>(Event::KeyboardKey::Numpad0) + 9 == static_cast<int>(Event::KeyboardKey::Numpad9), "Numpad0 to Numpad9 need continous ids in KeyboardKey");
if ((static_cast<int>(event.key.code) >= static_cast<int>(Event::KeyboardKey::Numpad0))
&& (static_cast<int>(event.key.code) <= static_cast<int>(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;
}

Expand Down Expand Up @@ -503,6 +518,11 @@ namespace tgui
getBackend()->attachGui(this);
std::static_pointer_cast<BackendGLFW>(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();
}

Expand Down
33 changes: 20 additions & 13 deletions src/Backend/Window/SDL/BackendGuiSDL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<int>(Event::KeyboardKey::Numpad0) + 9 == static_cast<int>(Event::KeyboardKey::Numpad9), "Numpad0 to Numpad9 need continous ids in KeyboardKey");
if (((modifiers & SDL_KMOD_NUM) == 0)
&& (static_cast<int>(eventTGUI.key.code) >= static_cast<int>(Event::KeyboardKey::Numpad0))
&& (static_cast<int>(eventTGUI.key.code) <= static_cast<int>(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;
}
Expand Down
18 changes: 16 additions & 2 deletions src/Backend/Window/SFML/BackendGuiSFML.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand All @@ -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<int>(Event::KeyboardKey::Numpad0) + 9 == static_cast<int>(Event::KeyboardKey::Numpad9), "Numpad0 to Numpad9 need continous ids in KeyboardKey");
if (!eventKeyPressed->numLock
&& (static_cast<int>(eventTGUI.key.code) >= static_cast<int>(Event::KeyboardKey::Numpad0))
&& (static_cast<int>(eventTGUI.key.code) <= static_cast<int>(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;
}

Expand All @@ -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))
Expand Down

0 comments on commit c963cc5

Please sign in to comment.