From 9cae9491f064dbaa00f0dfdc61ad12fb142966ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20D=C3=BCrrenberger?= Date: Thu, 19 Sep 2024 22:06:38 +0200 Subject: [PATCH] Add CapsLock, NumLock and ScrollLock support for Events --- include/SFML/Window/Event.hpp | 30 +++++++------ src/SFML/Window/Android/WindowImplAndroid.cpp | 10 +++-- src/SFML/Window/DRM/InputImpl.cpp | 27 +++++++++--- src/SFML/Window/Unix/WindowImplX11.cpp | 30 +++++++------ src/SFML/Window/Win32/WindowImplWin32.cpp | 30 +++++++------ .../Window/macOS/SFKeyboardModifiersHelper.mm | 42 +++++++++++++------ test/Window/Event.test.cpp | 10 ++++- 7 files changed, 119 insertions(+), 60 deletions(-) diff --git a/include/SFML/Window/Event.hpp b/include/SFML/Window/Event.hpp index f68a29b47..a6c574a13 100644 --- a/include/SFML/Window/Event.hpp +++ b/include/SFML/Window/Event.hpp @@ -94,12 +94,15 @@ public: //////////////////////////////////////////////////////////// struct KeyPressed { - Keyboard::Key code{}; //!< Code of the key that has been pressed - Keyboard::Scancode scancode{}; //!< Physical code of the key that has been pressed - bool alt{}; //!< Is the Alt key pressed? - bool control{}; //!< Is the Control key pressed? - bool shift{}; //!< Is the Shift key pressed? - bool system{}; //!< Is the System key pressed? + Keyboard::Key code{}; //!< Code of the key that has been pressed + Keyboard::Scancode scancode{}; //!< Physical code of the key that has been pressed + bool alt{}; //!< Is the Alt key pressed? + bool control{}; //!< Is the Control key pressed? + bool shift{}; //!< Is the Shift key pressed? + bool system{}; //!< Is the System key pressed? + bool capsLock{}; //!< Is the CapsLock key toggled? + bool numLock{}; //!< Is the NumLock key toggled? (Not supported on macOS) + bool scrollLock{}; //!< Is the ScrollLock key toggled? }; //////////////////////////////////////////////////////////// @@ -108,12 +111,15 @@ public: //////////////////////////////////////////////////////////// struct KeyReleased { - Keyboard::Key code{}; //!< Code of the key that has been released - Keyboard::Scancode scancode{}; //!< Physical code of the key that has been released - bool alt{}; //!< Is the Alt key pressed? - bool control{}; //!< Is the Control key pressed? - bool shift{}; //!< Is the Shift key pressed? - bool system{}; //!< Is the System key pressed? + Keyboard::Key code{}; //!< Code of the key that has been released + Keyboard::Scancode scancode{}; //!< Physical code of the key that has been released + bool alt{}; //!< Is the Alt key pressed? + bool control{}; //!< Is the Control key pressed? + bool shift{}; //!< Is the Shift key pressed? + bool system{}; //!< Is the System key pressed? + bool capsLock{}; //!< Is the CapsLock key toggled? + bool numLock{}; //!< Is the NumLock key toggled? (Not supported on macOS) + bool scrollLock{}; //!< Is the ScrollLock key toggled? }; //////////////////////////////////////////////////////////// diff --git a/src/SFML/Window/Android/WindowImplAndroid.cpp b/src/SFML/Window/Android/WindowImplAndroid.cpp index 9e3f1a39a..e00b26ed4 100644 --- a/src/SFML/Window/Android/WindowImplAndroid.cpp +++ b/src/SFML/Window/Android/WindowImplAndroid.cpp @@ -416,9 +416,13 @@ int WindowImplAndroid::processKeyEvent(AInputEvent* inputEvent, ActivityStates& const auto forwardKeyEvent = [&](auto keyEvent) { - keyEvent.code = androidKeyToSF(key); - keyEvent.alt = metakey & AMETA_ALT_ON; - keyEvent.shift = metakey & AMETA_SHIFT_ON; + keyEvent.code = androidKeyToSF(key); + keyEvent.alt = metakey & AMETA_ALT_ON; + keyEvent.shift = metakey & AMETA_SHIFT_ON; + keyEvent.system = metakey & AMETA_SYM_ON; + keyEvent.capsLock = metakey & AMETA_CAPS_LOCK_ON; + keyEvent.numLock = metakey & AMETA_NUM_LOCK_ON; + keyEvent.scrollLock = metakey & AMETA_SCROLL_LOCK_ON; forwardEvent(keyEvent); }; diff --git a/src/SFML/Window/DRM/InputImpl.cpp b/src/SFML/Window/DRM/InputImpl.cpp index 4114066e6..850cc0714 100644 --- a/src/SFML/Window/DRM/InputImpl.cpp +++ b/src/SFML/Window/DRM/InputImpl.cpp @@ -91,6 +91,18 @@ bool systemDown() { return keyMap[sf::Keyboard::Key::LSystem] || keyMap[sf::Keyboard::Key::RSystem]; } +bool capsLockDown() +{ + return false; // TODO: To be implemented, potentially with scancode support +} +bool numLockDown() +{ + return false; // TODO: To be implemented, potentially with scancode support +} +bool scrollLockDown() +{ + return false; // TODO: To be implemented, potentially with scancode support +} void uninitFileDescriptors() { @@ -408,12 +420,15 @@ std::optional eventProcess() const auto makeKeyEvent = [&](auto keyEvent) { - keyEvent.code = kb; - keyEvent.scancode = sf::Keyboard::Scan::Unknown; // TODO: not implemented - keyEvent.alt = altDown(); - keyEvent.control = controlDown(); - keyEvent.shift = shiftDown(); - keyEvent.system = systemDown(); + keyEvent.code = kb; + keyEvent.scancode = sf::Keyboard::Scan::Unknown; // TODO: not implemented + keyEvent.alt = altDown(); + keyEvent.control = controlDown(); + keyEvent.shift = shiftDown(); + keyEvent.system = systemDown(); + keyEvent.capsLock = capsLockDown(); + keyEvent.numLock = numLockDown(); + keyEvent.scrollLock = scrollLockDown(); return keyEvent; }; diff --git a/src/SFML/Window/Unix/WindowImplX11.cpp b/src/SFML/Window/Unix/WindowImplX11.cpp index 69829e4f4..32089daaa 100644 --- a/src/SFML/Window/Unix/WindowImplX11.cpp +++ b/src/SFML/Window/Unix/WindowImplX11.cpp @@ -1803,12 +1803,15 @@ bool WindowImplX11::processEvent(XEvent& windowEvent) // Fill the event parameters // TODO: if modifiers are wrong, use XGetModifierMapping to retrieve the actual modifiers mapping Event::KeyPressed event; - event.code = KeyboardImpl::getKeyFromEvent(windowEvent.xkey); - event.scancode = KeyboardImpl::getScancodeFromEvent(windowEvent.xkey); - event.alt = windowEvent.xkey.state & Mod1Mask; - event.control = windowEvent.xkey.state & ControlMask; - event.shift = windowEvent.xkey.state & ShiftMask; - event.system = windowEvent.xkey.state & Mod4Mask; + event.code = KeyboardImpl::getKeyFromEvent(windowEvent.xkey); + event.scancode = KeyboardImpl::getScancodeFromEvent(windowEvent.xkey); + event.alt = windowEvent.xkey.state & Mod1Mask; + event.control = windowEvent.xkey.state & ControlMask; + event.shift = windowEvent.xkey.state & ShiftMask; + event.system = windowEvent.xkey.state & Mod4Mask; + event.capsLock = windowEvent.xkey.state & LockMask; + event.numLock = windowEvent.xkey.state & Mod2Mask; + event.scrollLock = windowEvent.xkey.state & Mod3Mask; const bool filtered = XFilterEvent(&windowEvent, None); @@ -1884,12 +1887,15 @@ bool WindowImplX11::processEvent(XEvent& windowEvent) { // Fill the event parameters Event::KeyReleased event; - event.code = KeyboardImpl::getKeyFromEvent(windowEvent.xkey); - event.scancode = KeyboardImpl::getScancodeFromEvent(windowEvent.xkey); - event.alt = windowEvent.xkey.state & Mod1Mask; - event.control = windowEvent.xkey.state & ControlMask; - event.shift = windowEvent.xkey.state & ShiftMask; - event.system = windowEvent.xkey.state & Mod4Mask; + event.code = KeyboardImpl::getKeyFromEvent(windowEvent.xkey); + event.scancode = KeyboardImpl::getScancodeFromEvent(windowEvent.xkey); + event.alt = windowEvent.xkey.state & Mod1Mask; + event.control = windowEvent.xkey.state & ControlMask; + event.shift = windowEvent.xkey.state & ShiftMask; + event.system = windowEvent.xkey.state & Mod4Mask; + event.capsLock = windowEvent.xkey.state & LockMask; + event.numLock = windowEvent.xkey.state & Mod2Mask; + event.scrollLock = windowEvent.xkey.state & Mod3Mask; pushEvent(event); break; diff --git a/src/SFML/Window/Win32/WindowImplWin32.cpp b/src/SFML/Window/Win32/WindowImplWin32.cpp index 77f847f2f..f39f582fc 100644 --- a/src/SFML/Window/Win32/WindowImplWin32.cpp +++ b/src/SFML/Window/Win32/WindowImplWin32.cpp @@ -883,12 +883,15 @@ void WindowImplWin32::processEvent(UINT message, WPARAM wParam, LPARAM lParam) if (m_keyRepeatEnabled || ((HIWORD(lParam) & KF_REPEAT) == 0)) { Event::KeyPressed event; - event.alt = HIWORD(GetKeyState(VK_MENU)) != 0; - event.control = HIWORD(GetKeyState(VK_CONTROL)) != 0; - event.shift = HIWORD(GetKeyState(VK_SHIFT)) != 0; - event.system = HIWORD(GetKeyState(VK_LWIN)) || HIWORD(GetKeyState(VK_RWIN)); - event.code = virtualKeyCodeToSF(wParam, lParam); - event.scancode = toScancode(wParam, lParam); + event.alt = GetKeyState(VK_MENU) & 0x8000; + event.control = GetKeyState(VK_CONTROL) & 0x8000; + event.shift = GetKeyState(VK_SHIFT) & 0x8000; + event.system = GetKeyState(VK_LWIN) & 0x8000 || GetKeyState(VK_RWIN) & 0x8000; + event.capsLock = GetKeyState(VK_CAPITAL) & 0x0001; + event.numLock = GetKeyState(VK_NUMLOCK) & 0x0001; + event.scrollLock = GetKeyState(VK_SCROLL) & 0x0001; + event.code = virtualKeyCodeToSF(wParam, lParam); + event.scancode = toScancode(wParam, lParam); pushEvent(event); } break; @@ -899,12 +902,15 @@ void WindowImplWin32::processEvent(UINT message, WPARAM wParam, LPARAM lParam) case WM_SYSKEYUP: { Event::KeyReleased event; - event.alt = HIWORD(GetKeyState(VK_MENU)) != 0; - event.control = HIWORD(GetKeyState(VK_CONTROL)) != 0; - event.shift = HIWORD(GetKeyState(VK_SHIFT)) != 0; - event.system = HIWORD(GetKeyState(VK_LWIN)) || HIWORD(GetKeyState(VK_RWIN)); - event.code = virtualKeyCodeToSF(wParam, lParam); - event.scancode = toScancode(wParam, lParam); + event.alt = GetKeyState(VK_MENU) & 0x8000; + event.control = GetKeyState(VK_CONTROL) & 0x8000; + event.shift = GetKeyState(VK_SHIFT) & 0x8000; + event.system = GetKeyState(VK_LWIN) & 0x8000 || GetKeyState(VK_RWIN) & 0x8000; + event.capsLock = GetKeyState(VK_CAPITAL) & 0x0001; + event.numLock = GetKeyState(VK_NUMLOCK) & 0x0001; + event.scrollLock = GetKeyState(VK_SCROLL) & 0x0001; + event.code = virtualKeyCodeToSF(wParam, lParam); + event.scancode = toScancode(wParam, lParam); pushEvent(event); break; } diff --git a/src/SFML/Window/macOS/SFKeyboardModifiersHelper.mm b/src/SFML/Window/macOS/SFKeyboardModifiersHelper.mm index 8589947a7..32b2b1220 100644 --- a/src/SFML/Window/macOS/SFKeyboardModifiersHelper.mm +++ b/src/SFML/Window/macOS/SFKeyboardModifiersHelper.mm @@ -63,6 +63,7 @@ struct ModifiersState BOOL leftControlWasDown{}; BOOL rightControlWasDown{}; BOOL capsLockWasOn{}; + BOOL numLockWasOn{}; }; @@ -151,7 +152,8 @@ void initialiseKeyboardHelper() state.rightAlternateWasDown = isKeyMaskActive(modifiers, NSRightAlternateKeyMask); state.leftControlWasDown = isKeyMaskActive(modifiers, NSLeftControlKeyMask); state.rightControlWasDown = isKeyMaskActive(modifiers, NSRightControlKeyMask); - state.capsLockWasOn = isKeyMaskActive(modifiers, NSEventModifierFlagCapsLock); + state.capsLockWasOn = isKeyMaskActive(modifiers, NSAlphaShiftKeyMask); + state.numLockWasOn = isKeyMaskActive(modifiers, NSNumericPadKeyMask); isStateInitialized = YES; } @@ -161,12 +163,15 @@ void initialiseKeyboardHelper() sf::Event::KeyPressed keyPressedEventWithModifiers(NSUInteger modifiers, sf::Keyboard::Key key, sf::Keyboard::Scancode code) { sf::Event::KeyPressed event; - event.code = key; - event.scancode = code; - event.alt = modifiers & NSAlternateKeyMask; - event.control = modifiers & NSControlKeyMask; - event.shift = modifiers & NSShiftKeyMask; - event.system = modifiers & NSCommandKeyMask; + event.code = key; + event.scancode = code; + event.alt = modifiers & NSAlternateKeyMask; + event.control = modifiers & NSControlKeyMask; + event.shift = modifiers & NSShiftKeyMask; + event.system = modifiers & NSCommandKeyMask; + event.capsLock = modifiers & NSAlphaShiftKeyMask; + event.numLock = modifiers & NSNumericPadKeyMask; + event.scrollLock = false; // Doesn't exist on macOS return event; } @@ -175,12 +180,15 @@ sf::Event::KeyPressed keyPressedEventWithModifiers(NSUInteger modifiers, sf::Key sf::Event::KeyReleased keyReleasedEventWithModifiers(NSUInteger modifiers, sf::Keyboard::Key key, sf::Keyboard::Scancode code) { sf::Event::KeyReleased event; - event.code = key; - event.scancode = code; - event.alt = modifiers & NSAlternateKeyMask; - event.control = modifiers & NSControlKeyMask; - event.shift = modifiers & NSShiftKeyMask; - event.system = modifiers & NSCommandKeyMask; + event.code = key; + event.scancode = code; + event.alt = modifiers & NSAlternateKeyMask; + event.control = modifiers & NSControlKeyMask; + event.shift = modifiers & NSShiftKeyMask; + event.system = modifiers & NSCommandKeyMask; + event.capsLock = modifiers & NSAlphaShiftKeyMask; + event.numLock = modifiers & NSNumericPadKeyMask; + event.scrollLock = false; // Doesn't exist on macOS return event; } @@ -243,4 +251,12 @@ void handleModifiersChanged(NSUInteger modifiers, sf::priv::WindowImplCocoa& req sf::Keyboard::Key::Unknown, sf::Keyboard::Scan::CapsLock, requester); + + // Handle num lock + processOneModifier(modifiers, + NSEventModifierFlagNumericPad, + state.numLockWasOn, + sf::Keyboard::Key::Unknown, + sf::Keyboard::Scan::NumLock, + requester); } diff --git a/test/Window/Event.test.cpp b/test/Window/Event.test.cpp index 11d9ee3e4..4dca6c831 100644 --- a/test/Window/Event.test.cpp +++ b/test/Window/Event.test.cpp @@ -81,7 +81,7 @@ TEST_CASE("[Window] sf::Event") const auto& textEntered = *event.getIf(); CHECK(textEntered.unicode == 123456); - event = sf::Event::KeyPressed{sf::Keyboard::Key::C, sf::Keyboard::Scan::C, true, true, true, true}; + event = sf::Event::KeyPressed{sf::Keyboard::Key::C, sf::Keyboard::Scan::C, true, true, true, true, true, true, true}; CHECK(event.is()); CHECK(event.getIf()); const auto& keyPressed = *event.getIf(); @@ -91,8 +91,11 @@ TEST_CASE("[Window] sf::Event") CHECK(keyPressed.control); CHECK(keyPressed.shift); CHECK(keyPressed.system); + CHECK(keyPressed.capsLock); + CHECK(keyPressed.numLock); + CHECK(keyPressed.scrollLock); - event = sf::Event::KeyReleased{sf::Keyboard::Key::D, sf::Keyboard::Scan::D, true, true, true, true}; + event = sf::Event::KeyReleased{sf::Keyboard::Key::D, sf::Keyboard::Scan::D, true, true, true, true, true, true, true}; CHECK(event.is()); CHECK(event.getIf()); const auto& keyReleased = *event.getIf(); @@ -102,6 +105,9 @@ TEST_CASE("[Window] sf::Event") CHECK(keyReleased.control); CHECK(keyReleased.shift); CHECK(keyReleased.system); + CHECK(keyReleased.capsLock); + CHECK(keyReleased.numLock); + CHECK(keyReleased.scrollLock); event = sf::Event::MouseWheelScrolled{sf::Mouse::Wheel::Horizontal, 3.14f, {4, 5}}; CHECK(event.is());