Prechádzať zdrojové kódy

Add lock key modifier bits input mode

This adds the GLFW_MOD_CAPS_LOCK and GLFW_MOD_NUM_LOCK modifier bits.
Set the GLFW_LOCK_KEY_MODS input mode to enable these for all callbacks
that receive modifier bits.

Fixes #946.
Camilla Löwy 7 rokov pred
rodič
commit
0e8c4ea7ce
12 zmenil súbory, kde vykonal 107 pridanie a 10 odobranie
  1. 1 0
      README.md
  2. 13 0
      docs/input.dox
  3. 35 8
      include/GLFW/glfw3.h
  4. 3 0
      src/cocoa_window.m
  5. 15 2
      src/input.c
  6. 1 0
      src/internal.h
  7. 4 0
      src/mir_window.c
  8. 8 0
      src/win32_window.c
  9. 8 0
      src/wl_init.c
  10. 2 0
      src/wl_platform.h
  11. 4 0
      src/x11_window.c
  12. 13 0
      tests/events.c

+ 1 - 0
README.md

@@ -159,6 +159,7 @@ information on what to include when reporting a bug.
 - Added `GLFW_CENTER_CURSOR` window hint for controlling cursor centering
 - Added `GLFW_CENTER_CURSOR` window hint for controlling cursor centering
   (#749,#842)
   (#749,#842)
 - Added `GLFW_JOYSTICK_HAT_BUTTONS` init hint (#889)
 - Added `GLFW_JOYSTICK_HAT_BUTTONS` init hint (#889)
+- Added `GLFW_LOCK_KEY_MODS` input mode and `GLFW_MOD_*_LOCK` mod bits (#946)
 - Added macOS specific `GLFW_COCOA_RETINA_FRAMEBUFFER` window hint
 - Added macOS specific `GLFW_COCOA_RETINA_FRAMEBUFFER` window hint
 - Added macOS specific `GLFW_COCOA_FRAME_AUTOSAVE` window hint (#195)
 - Added macOS specific `GLFW_COCOA_FRAME_AUTOSAVE` window hint (#195)
 - Added macOS specific `GLFW_COCOA_GRAPHICS_SWITCHING` window hint (#377,#935)
 - Added macOS specific `GLFW_COCOA_GRAPHICS_SWITCHING` window hint (#377,#935)

+ 13 - 0
docs/input.dox

@@ -170,6 +170,19 @@ When sticky keys mode is enabled, the pollable state of a key will remain
 it has been polled, if a key release event had been processed in the meantime,
 it has been polled, if a key release event had been processed in the meantime,
 the state will reset to `GLFW_RELEASE`, otherwise it will remain `GLFW_PRESS`.
 the state will reset to `GLFW_RELEASE`, otherwise it will remain `GLFW_PRESS`.
 
 
+@anchor GLFW_LOCK_KEY_MODS
+If you wish to know what the state of the Caps Lock and Num Lock keys was when
+input events were generated, set the `GLFW_LOCK_KEY_MODS` input mode.
+
+@code
+glfwSetInputMode(window, GLFW_LOCK_KEY_MODS, 1);
+@endcode
+
+When this input mode is enabled, any callback that receives
+[modifier bits](@ref mods) will have the @ref GLFW_MOD_CAPS_LOCK bit set if Caps
+Lock was on when the event occurred and the @ref GLFW_MOD_NUM_LOCK bit set if
+Num Lock was on.
+
 The `GLFW_KEY_LAST` constant holds the highest value of any
 The `GLFW_KEY_LAST` constant holds the highest value of any
 [named key](@ref keys).
 [named key](@ref keys).
 
 

+ 35 - 8
include/GLFW/glfw3.h

@@ -493,17 +493,37 @@ extern "C" {
  *  @{ */
  *  @{ */
 
 
 /*! @brief If this bit is set one or more Shift keys were held down.
 /*! @brief If this bit is set one or more Shift keys were held down.
+ *
+ *  If this bit is set one or more Shift keys were held down.
  */
  */
 #define GLFW_MOD_SHIFT           0x0001
 #define GLFW_MOD_SHIFT           0x0001
 /*! @brief If this bit is set one or more Control keys were held down.
 /*! @brief If this bit is set one or more Control keys were held down.
+ *
+ *  If this bit is set one or more Control keys were held down.
  */
  */
 #define GLFW_MOD_CONTROL         0x0002
 #define GLFW_MOD_CONTROL         0x0002
 /*! @brief If this bit is set one or more Alt keys were held down.
 /*! @brief If this bit is set one or more Alt keys were held down.
+ *
+ *  If this bit is set one or more Alt keys were held down.
  */
  */
 #define GLFW_MOD_ALT             0x0004
 #define GLFW_MOD_ALT             0x0004
 /*! @brief If this bit is set one or more Super keys were held down.
 /*! @brief If this bit is set one or more Super keys were held down.
+ *
+ *  If this bit is set one or more Super keys were held down.
  */
  */
 #define GLFW_MOD_SUPER           0x0008
 #define GLFW_MOD_SUPER           0x0008
+/*! @brief If this bit is set the Caps Lock key is enabled.
+ *
+ *  If this bit is set the Caps Lock key is enabled and the @ref
+ *  GLFW_LOCK_KEY_MODS input mode is set.
+ */
+#define GLFW_MOD_CAPS_LOCK       0x0010
+/*! @brief If this bit is set the Num Lock key is enabled.
+ *
+ *  If this bit is set the Num Lock key is enabled and the @ref
+ *  GLFW_LOCK_KEY_MODS input mode is set.
+ */
+#define GLFW_MOD_NUM_LOCK        0x0020
 
 
 /*! @} */
 /*! @} */
 
 
@@ -963,6 +983,7 @@ extern "C" {
 #define GLFW_CURSOR                 0x00033001
 #define GLFW_CURSOR                 0x00033001
 #define GLFW_STICKY_KEYS            0x00033002
 #define GLFW_STICKY_KEYS            0x00033002
 #define GLFW_STICKY_MOUSE_BUTTONS   0x00033003
 #define GLFW_STICKY_MOUSE_BUTTONS   0x00033003
+#define GLFW_LOCK_KEY_MODS          0x00033004
 
 
 #define GLFW_CURSOR_NORMAL          0x00034001
 #define GLFW_CURSOR_NORMAL          0x00034001
 #define GLFW_CURSOR_HIDDEN          0x00034002
 #define GLFW_CURSOR_HIDDEN          0x00034002
@@ -3657,12 +3678,12 @@ GLFWAPI void glfwPostEmptyEvent(void);
 /*! @brief Returns the value of an input option for the specified window.
 /*! @brief Returns the value of an input option for the specified window.
  *
  *
  *  This function returns the value of an input option for the specified window.
  *  This function returns the value of an input option for the specified window.
- *  The mode must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS or
- *  @ref GLFW_STICKY_MOUSE_BUTTONS.
+ *  The mode must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS,
+ *  @ref GLFW_STICKY_MOUSE_BUTTONS or @ref GLFW_LOCK_KEY_MODS.
  *
  *
  *  @param[in] window The window to query.
  *  @param[in] window The window to query.
- *  @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or
- *  `GLFW_STICKY_MOUSE_BUTTONS`.
+ *  @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS`,
+ *  `GLFW_STICKY_MOUSE_BUTTONS` or `GLFW_LOCK_KEY_MODS`.
  *
  *
  *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
  *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
  *  GLFW_INVALID_ENUM.
  *  GLFW_INVALID_ENUM.
@@ -3680,8 +3701,8 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode);
 /*! @brief Sets an input option for the specified window.
 /*! @brief Sets an input option for the specified window.
  *
  *
  *  This function sets an input mode option for the specified window.  The mode
  *  This function sets an input mode option for the specified window.  The mode
- *  must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS or
- *  @ref GLFW_STICKY_MOUSE_BUTTONS.
+ *  must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS,
+ *  @ref GLFW_STICKY_MOUSE_BUTTONS or @ref GLFW_LOCK_KEY_MODS.
  *
  *
  *  If the mode is `GLFW_CURSOR`, the value must be one of the following cursor
  *  If the mode is `GLFW_CURSOR`, the value must be one of the following cursor
  *  modes:
  *  modes:
@@ -3707,9 +3728,15 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode);
  *  you are only interested in whether mouse buttons have been pressed but not
  *  you are only interested in whether mouse buttons have been pressed but not
  *  when or in which order.
  *  when or in which order.
  *
  *
+ *  If the mode is `GLFW_LOCK_KEY_MODS`, the value must be either `GLFW_TRUE` to
+ *  enable lock key modifier bits, or `GLFW_FALSE` to disable them.  If enabled,
+ *  callbacks that receive modifier bits will also have the @ref
+ *  GLFW_MOD_CAPS_LOCK bit set when the event was generated with Caps Lock on,
+ *  and the @ref GLFW_MOD_NUM_LOCK bit when Num Lock was on.
+ *
  *  @param[in] window The window whose input mode to set.
  *  @param[in] window The window whose input mode to set.
- *  @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or
- *  `GLFW_STICKY_MOUSE_BUTTONS`.
+ *  @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS`,
+ *  `GLFW_STICKY_MOUSE_BUTTONS` or `GLFW_LOCK_KEY_MODS`.
  *  @param[in] value The new value of the specified input mode.
  *  @param[in] value The new value of the specified input mode.
  *
  *
  *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
  *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref

+ 3 - 0
src/cocoa_window.m

@@ -43,6 +43,7 @@
  #define NSEventModifierFlagControl NSControlKeyMask
  #define NSEventModifierFlagControl NSControlKeyMask
  #define NSEventModifierFlagOption NSAlternateKeyMask
  #define NSEventModifierFlagOption NSAlternateKeyMask
  #define NSEventModifierFlagShift NSShiftKeyMask
  #define NSEventModifierFlagShift NSShiftKeyMask
+ #define NSEventModifierFlagCapsLock NSAlphaShiftKeyMask
  #define NSEventModifierFlagDeviceIndependentFlagsMask NSDeviceIndependentModifierFlagsMask
  #define NSEventModifierFlagDeviceIndependentFlagsMask NSDeviceIndependentModifierFlagsMask
  #define NSEventMaskAny NSAnyEventMask
  #define NSEventMaskAny NSAnyEventMask
  #define NSEventTypeApplicationDefined NSApplicationDefined
  #define NSEventTypeApplicationDefined NSApplicationDefined
@@ -177,6 +178,8 @@ static int translateFlags(NSUInteger flags)
         mods |= GLFW_MOD_ALT;
         mods |= GLFW_MOD_ALT;
     if (flags & NSEventModifierFlagCommand)
     if (flags & NSEventModifierFlagCommand)
         mods |= GLFW_MOD_SUPER;
         mods |= GLFW_MOD_SUPER;
+    if (flags & NSEventModifierFlagCapsLock)
+        mods |= GLFW_MOD_CAPS_LOCK;
 
 
     return mods;
     return mods;
 }
 }

+ 15 - 2
src/input.c

@@ -245,6 +245,9 @@ void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int m
             action = GLFW_REPEAT;
             action = GLFW_REPEAT;
     }
     }
 
 
+    if (!window->lockKeyMods)
+        mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK);
+
     if (window->callbacks.key)
     if (window->callbacks.key)
         window->callbacks.key((GLFWwindow*) window, key, scancode, action, mods);
         window->callbacks.key((GLFWwindow*) window, key, scancode, action, mods);
 }
 }
@@ -254,6 +257,9 @@ void _glfwInputChar(_GLFWwindow* window, unsigned int codepoint, int mods, GLFWb
     if (codepoint < 32 || (codepoint > 126 && codepoint < 160))
     if (codepoint < 32 || (codepoint > 126 && codepoint < 160))
         return;
         return;
 
 
+    if (!window->lockKeyMods)
+        mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK);
+
     if (window->callbacks.charmods)
     if (window->callbacks.charmods)
         window->callbacks.charmods((GLFWwindow*) window, codepoint, mods);
         window->callbacks.charmods((GLFWwindow*) window, codepoint, mods);
 
 
@@ -275,6 +281,9 @@ void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods)
     if (button < 0 || button > GLFW_MOUSE_BUTTON_LAST)
     if (button < 0 || button > GLFW_MOUSE_BUTTON_LAST)
         return;
         return;
 
 
+    if (!window->lockKeyMods)
+        mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK);
+
     if (action == GLFW_RELEASE && window->stickyMouseButtons)
     if (action == GLFW_RELEASE && window->stickyMouseButtons)
         window->mouseButtons[button] = _GLFW_STICK;
         window->mouseButtons[button] = _GLFW_STICK;
     else
     else
@@ -406,6 +415,8 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* handle, int mode)
             return window->stickyKeys;
             return window->stickyKeys;
         case GLFW_STICKY_MOUSE_BUTTONS:
         case GLFW_STICKY_MOUSE_BUTTONS:
             return window->stickyMouseButtons;
             return window->stickyMouseButtons;
+        case GLFW_LOCK_KEY_MODS:
+            return window->lockKeyMods;
     }
     }
 
 
     _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode);
     _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode);
@@ -461,7 +472,7 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value)
             }
             }
         }
         }
 
 
-        window->stickyKeys = value ? GLFW_TRUE : GLFW_FALSE;
+        window->stickyKeys = value;
     }
     }
     else if (mode == GLFW_STICKY_MOUSE_BUTTONS)
     else if (mode == GLFW_STICKY_MOUSE_BUTTONS)
     {
     {
@@ -481,8 +492,10 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value)
             }
             }
         }
         }
 
 
-        window->stickyMouseButtons = value ? GLFW_TRUE : GLFW_FALSE;
+        window->stickyMouseButtons = value;
     }
     }
+    else if (mode == GLFW_LOCK_KEY_MODS)
+        window->lockKeyMods = value ? GLFW_TRUE : GLFW_FALSE;
     else
     else
         _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode);
         _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode);
 }
 }

+ 1 - 0
src/internal.h

@@ -419,6 +419,7 @@ struct _GLFWwindow
 
 
     GLFWbool            stickyKeys;
     GLFWbool            stickyKeys;
     GLFWbool            stickyMouseButtons;
     GLFWbool            stickyMouseButtons;
+    GLFWbool            lockKeyMods;
     int                 cursorMode;
     int                 cursorMode;
     char                mouseButtons[GLFW_MOUSE_BUTTON_LAST + 1];
     char                mouseButtons[GLFW_MOUSE_BUTTON_LAST + 1];
     char                keys[GLFW_KEY_LAST + 1];
     char                keys[GLFW_KEY_LAST + 1];

+ 4 - 0
src/mir_window.c

@@ -123,6 +123,10 @@ static int mirModToGLFWMod(uint32_t mods)
         publicMods |= GLFW_MOD_CONTROL;
         publicMods |= GLFW_MOD_CONTROL;
     if (mods & mir_input_event_modifier_meta)
     if (mods & mir_input_event_modifier_meta)
         publicMods |= GLFW_MOD_SUPER;
         publicMods |= GLFW_MOD_SUPER;
+    if (mods & mir_input_event_modifier_caps_lock)
+        publicMods |= GLFW_MOD_CAPS_LOCK;
+    if (mods & mir_input_event_modifier_num_lock)
+        publicMods |= GLFW_MOD_NUM_LOCK;
 
 
     return publicMods;
     return publicMods;
 }
 }

+ 8 - 0
src/win32_window.c

@@ -392,6 +392,10 @@ static int getKeyMods(void)
         mods |= GLFW_MOD_ALT;
         mods |= GLFW_MOD_ALT;
     if ((GetKeyState(VK_LWIN) | GetKeyState(VK_RWIN)) & 0x8000)
     if ((GetKeyState(VK_LWIN) | GetKeyState(VK_RWIN)) & 0x8000)
         mods |= GLFW_MOD_SUPER;
         mods |= GLFW_MOD_SUPER;
+    if (GetKeyState(VK_CAPITAL) & 1)
+        mods |= GLFW_MOD_CAPS_LOCK;
+    if (GetKeyState(VK_NUMLOCK) & 1)
+        mods |= GLFW_MOD_NUM_LOCK;
 
 
     return mods;
     return mods;
 }
 }
@@ -410,6 +414,10 @@ static int getAsyncKeyMods(void)
         mods |= GLFW_MOD_ALT;
         mods |= GLFW_MOD_ALT;
     if ((GetAsyncKeyState(VK_LWIN) | GetAsyncKeyState(VK_RWIN)) & 0x8000)
     if ((GetAsyncKeyState(VK_LWIN) | GetAsyncKeyState(VK_RWIN)) & 0x8000)
         mods |= GLFW_MOD_SUPER;
         mods |= GLFW_MOD_SUPER;
+    if (GetAsyncKeyState(VK_CAPITAL) & 1)
+        mods |= GLFW_MOD_CAPS_LOCK;
+    if (GetAsyncKeyState(VK_NUMLOCK) & 1)
+        mods |= GLFW_MOD_NUM_LOCK;
 
 
     return mods;
     return mods;
 }
 }

+ 8 - 0
src/wl_init.c

@@ -264,6 +264,10 @@ static void keyboardHandleKeymap(void* data,
         1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Shift");
         1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Shift");
     _glfw.wl.xkb.superMask =
     _glfw.wl.xkb.superMask =
         1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod4");
         1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod4");
+    _glfw.wl.xkb.capsLockMask =
+        1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Lock");
+    _glfw.wl.xkb.numLockMask =
+        1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod2");
 }
 }
 
 
 static void keyboardHandleEnter(void* data,
 static void keyboardHandleEnter(void* data,
@@ -409,6 +413,10 @@ static void keyboardHandleModifiers(void* data,
         modifiers |= GLFW_MOD_SHIFT;
         modifiers |= GLFW_MOD_SHIFT;
     if (mask & _glfw.wl.xkb.superMask)
     if (mask & _glfw.wl.xkb.superMask)
         modifiers |= GLFW_MOD_SUPER;
         modifiers |= GLFW_MOD_SUPER;
+    if (mask & _glfw.wl.xkb.capsLockMask)
+        modifiers |= GLFW_MOD_CAPS_LOCK;
+    if (mask & _glfw.wl.xkb.numLockMask)
+        modifiers |= GLFW_MOD_NUM_LOCK;
     _glfw.wl.xkb.modifiers = modifiers;
     _glfw.wl.xkb.modifiers = modifiers;
 }
 }
 
 

+ 2 - 0
src/wl_platform.h

@@ -183,6 +183,8 @@ typedef struct _GLFWlibraryWayland
         xkb_mod_mask_t          altMask;
         xkb_mod_mask_t          altMask;
         xkb_mod_mask_t          shiftMask;
         xkb_mod_mask_t          shiftMask;
         xkb_mod_mask_t          superMask;
         xkb_mod_mask_t          superMask;
+        xkb_mod_mask_t          capsLockMask;
+        xkb_mod_mask_t          numLockMask;
         unsigned int            modifiers;
         unsigned int            modifiers;
 
 
         PFN_xkb_context_new context_new;
         PFN_xkb_context_new context_new;

+ 4 - 0
src/x11_window.c

@@ -212,6 +212,10 @@ static int translateState(int state)
         mods |= GLFW_MOD_ALT;
         mods |= GLFW_MOD_ALT;
     if (state & Mod4Mask)
     if (state & Mod4Mask)
         mods |= GLFW_MOD_SUPER;
         mods |= GLFW_MOD_SUPER;
+    if (state & LockMask)
+        mods |= GLFW_MOD_CAPS_LOCK;
+    if (state & Mod2Mask)
+        mods |= GLFW_MOD_NUM_LOCK;
 
 
     return mods;
     return mods;
 }
 }

+ 13 - 0
tests/events.c

@@ -244,6 +244,10 @@ static const char* get_mods_name(int mods)
         strcat(name, " alt");
         strcat(name, " alt");
     if (mods & GLFW_MOD_SUPER)
     if (mods & GLFW_MOD_SUPER)
         strcat(name, " super");
         strcat(name, " super");
+    if (mods & GLFW_MOD_CAPS_LOCK)
+        strcat(name, " capslock-on");
+    if (mods & GLFW_MOD_NUM_LOCK)
+        strcat(name, " numlock-on");
 
 
     return name;
     return name;
 }
 }
@@ -400,6 +404,15 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action,
             printf("(( closing %s ))\n", slot->closeable ? "enabled" : "disabled");
             printf("(( closing %s ))\n", slot->closeable ? "enabled" : "disabled");
             break;
             break;
         }
         }
+
+        case GLFW_KEY_L:
+        {
+            const int state = glfwGetInputMode(window, GLFW_LOCK_KEY_MODS);
+            glfwSetInputMode(window, GLFW_LOCK_KEY_MODS, !state);
+
+            printf("(( lock key mods %s ))\n", !state ? "enabled" : "disabled");
+            break;
+        }
     }
     }
 }
 }