Просмотр исходного кода

Added a conservative set of key modifiers.

Camilla Berglund 12 лет назад
Родитель
Сommit
2d1b835711
24 измененных файлов с 239 добавлено и 97 удалено
  1. 1 0
      README.md
  2. 2 2
      examples/boing.c
  3. 2 2
      examples/gears.c
  4. 1 1
      examples/heightmap.c
  5. 2 2
      examples/splitview.c
  6. 2 2
      examples/wave.c
  7. 19 2
      include/GL/glfw3.h
  8. 51 9
      src/cocoa_window.m
  9. 4 4
      src/input.c
  10. 3 2
      src/internal.h
  11. 59 21
      src/win32_window.c
  12. 2 2
      src/window.c
  13. 39 13
      src/x11_window.c
  14. 1 1
      tests/accuracy.c
  15. 3 9
      tests/clipboard.c
  16. 31 8
      tests/events.c
  17. 10 10
      tests/fsaa.c
  18. 1 1
      tests/gamma.c
  19. 1 1
      tests/iconify.c
  20. 1 1
      tests/modes.c
  21. 1 1
      tests/peter.c
  22. 1 1
      tests/reopen.c
  23. 1 1
      tests/sharing.c
  24. 1 1
      tests/tearing.c

+ 1 - 0
README.md

@@ -309,6 +309,7 @@ GLFW.
  * Added `GLFW_VISIBLE` window hint and parameter for controlling and polling
    window visibility
  * Added `GLFW_REPEAT` key action for repeated keys
+ * Added key modifier parameter to key and mouse button callbacks
  * Added `windows` simple multi-window test program
  * Added `sharing` simple OpenGL object sharing test program
  * Added `modes` video mode enumeration and setting test program

+ 2 - 2
examples/boing.c

@@ -43,7 +43,7 @@
 void init( void );
 void display( void );
 void reshape( GLFWwindow* window, int w, int h );
-void key_callback( GLFWwindow* window, int key, int action );
+void key_callback( GLFWwindow* window, int key, int action, int mods );
 void DrawBoingBall( void );
 void BounceBall( double dt );
 void DrawBoingBallBand( GLfloat long_lo, GLfloat long_hi );
@@ -245,7 +245,7 @@ void reshape( GLFWwindow* window, int w, int h )
               0.0, -1.0, 0.0 );         /* up vector */
 }
 
-void key_callback( GLFWwindow* window, int key, int action )
+void key_callback( GLFWwindow* window, int key, int action, int mods )
 {
     if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
         glfwSetWindowShouldClose(window, GL_TRUE);

+ 2 - 2
examples/gears.c

@@ -211,13 +211,13 @@ static void animate(void)
 
 
 /* change view angle, exit upon ESC */
-void key( GLFWwindow* window, int k, int action )
+void key( GLFWwindow* window, int k, int action, int mods )
 {
   if( action != GLFW_PRESS ) return;
 
   switch (k) {
   case GLFW_KEY_Z:
-    if( glfwGetKey( window, GLFW_KEY_LEFT_SHIFT ) )
+    if( mods & GLFW_MOD_SHIFT )
       view_rotz -= 5.0;
     else
       view_rotz += 5.0;

+ 1 - 1
examples/heightmap.c

@@ -477,7 +477,7 @@ static void update_mesh(void)
  * GLFW callback functions
  *********************************************************************/
 
-static void key_callback(GLFWwindow* window, int key, int action)
+static void key_callback(GLFWwindow* window, int key, int action, int mods)
 {
     switch(key)
     {

+ 2 - 2
examples/splitview.c

@@ -414,7 +414,7 @@ static void cursorPosFun(GLFWwindow* window, double x, double y)
 // Mouse button callback function
 //========================================================================
 
-static void mouseButtonFun(GLFWwindow* window, int button, int action)
+static void mouseButtonFun(GLFWwindow* window, int button, int action, int mods)
 {
     if ((button == GLFW_MOUSE_BUTTON_LEFT) && action == GLFW_PRESS)
     {
@@ -434,7 +434,7 @@ static void mouseButtonFun(GLFWwindow* window, int button, int action)
     do_redraw = 1;
 }
 
-static void key_callback(GLFWwindow* window, int key, int action)
+static void key_callback(GLFWwindow* window, int key, int action, int mods)
 {
     if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
         glfwSetWindowShouldClose(window, GL_TRUE);

+ 2 - 2
examples/wave.c

@@ -270,7 +270,7 @@ static void error_callback(int error, const char* description)
 // Handle key strokes
 //========================================================================
 
-void key_callback(GLFWwindow* window, int key, int action)
+void key_callback(GLFWwindow* window, int key, int action, int mods)
 {
     if (action != GLFW_PRESS)
         return;
@@ -313,7 +313,7 @@ void key_callback(GLFWwindow* window, int key, int action)
 // Callback function for mouse button events
 //========================================================================
 
-void mouse_button_callback(GLFWwindow* window, int button, int action)
+void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
 {
     if (button != GLFW_MOUSE_BUTTON_LEFT)
         return;

+ 19 - 2
include/GL/glfw3.h

@@ -407,6 +407,21 @@ extern "C" {
 
 /*! @} */
 
+/*! @name keys Modifier key flags
+ *  @{ */
+
+/*! @ingroup input
+ */
+#define GLFW_MOD_SHIFT           0x0001
+/*! @ingroup input
+ */
+#define GLFW_MOD_CTRL            0x0002
+/*! @ingroup input
+ */
+#define GLFW_MOD_ALT             0x0004
+
+/*! @} */
+
 /*! @defgroup buttons Mouse buttons
  *  @ingroup input
  *  @{ */
@@ -669,12 +684,13 @@ typedef void (* GLFWwindowiconifyfun)(GLFWwindow*,int);
  *  @param[in] button The [mouse button](@ref buttons) that was pressed or
  *  released.
  *  @param[in] action One of `GLFW_PRESS` or `GLFW_RELEASE`.
+ *  @param[in] mods Bit field describing which modifier keys were held down.
  *
  *  @sa glfwSetMouseButtonCallback
  *
  *  @ingroup input
  */
-typedef void (* GLFWmousebuttonfun)(GLFWwindow*,int,int);
+typedef void (* GLFWmousebuttonfun)(GLFWwindow*,int,int,int);
 
 /*! @brief The function signature for cursor position callbacks.
  *
@@ -725,12 +741,13 @@ typedef void (* GLFWscrollfun)(GLFWwindow*,double,double);
  *  @param[in] window The window that received the event.
  *  @param[in] key The [keyboard key](@ref keys) that was pressed or released.
  *  @param[in] action @ref GLFW_PRESS, @ref GLFW_RELEASE or @ref GLFW_REPEAT.
+ *  @param[in] mods Bit field describing which modifier keys were held down.
  *
  *  @sa glfwSetKeyCallback
  *
  *  @ingroup input
  */
-typedef void (* GLFWkeyfun)(GLFWwindow*,int,int);
+typedef void (* GLFWkeyfun)(GLFWwindow*,int,int,int);
 
 /*! @brief The function signature for Unicode character callbacks.
  *

+ 51 - 9
src/cocoa_window.m

@@ -201,6 +201,22 @@ static void centerCursor(_GLFWwindow *window)
 
 @end
 
+// Converts Mac OS X key modifiers into GLFW ones
+//
+static int convertKeyMods(NSUInteger flags)
+{
+    int mods = 0;
+
+    if (flags & NSShiftKeyMask)
+        mods |= GLFW_MOD_SHIFT;
+    if (flags & NSControlKeyMask)
+        mods |= GLFW_MOD_CTRL;
+    if (flags & NSAlternateKeyMask)
+        mods |= GLFW_MOD_ALT;
+
+    return mods;
+}
+
 // Converts a Mac OS X keycode to a GLFW keycode
 //
 static int convertMacKeyCode(unsigned int macKeyCode)
@@ -413,7 +429,10 @@ static int convertMacKeyCode(unsigned int macKeyCode)
 
 - (void)mouseDown:(NSEvent *)event
 {
-    _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS);
+    _glfwInputMouseClick(window,
+                         GLFW_MOUSE_BUTTON_LEFT,
+                         GLFW_PRESS,
+                         convertKeyMods([event modifierFlags]));
 }
 
 - (void)mouseDragged:(NSEvent *)event
@@ -423,7 +442,10 @@ static int convertMacKeyCode(unsigned int macKeyCode)
 
 - (void)mouseUp:(NSEvent *)event
 {
-    _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_LEFT, GLFW_RELEASE);
+    _glfwInputMouseClick(window,
+                         GLFW_MOUSE_BUTTON_LEFT,
+                         GLFW_RELEASE,
+                         convertKeyMods([event modifierFlags]));
 }
 
 - (void)mouseMoved:(NSEvent *)event
@@ -442,7 +464,10 @@ static int convertMacKeyCode(unsigned int macKeyCode)
 
 - (void)rightMouseDown:(NSEvent *)event
 {
-    _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_RIGHT, GLFW_PRESS);
+    _glfwInputMouseClick(window,
+                         GLFW_MOUSE_BUTTON_RIGHT,
+                         GLFW_PRESS,
+                         convertKeyMods([event modifierFlags]));
 }
 
 - (void)rightMouseDragged:(NSEvent *)event
@@ -452,12 +477,18 @@ static int convertMacKeyCode(unsigned int macKeyCode)
 
 - (void)rightMouseUp:(NSEvent *)event
 {
-    _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_RIGHT, GLFW_RELEASE);
+    _glfwInputMouseClick(window,
+                         GLFW_MOUSE_BUTTON_RIGHT,
+                         GLFW_RELEASE,
+                         convertKeyMods([event modifierFlags]));
 }
 
 - (void)otherMouseDown:(NSEvent *)event
 {
-    _glfwInputMouseClick(window, [event buttonNumber], GLFW_PRESS);
+    _glfwInputMouseClick(window,
+                         [event buttonNumber],
+                         GLFW_PRESS,
+                         convertKeyMods([event modifierFlags]));
 }
 
 - (void)otherMouseDragged:(NSEvent *)event
@@ -467,7 +498,10 @@ static int convertMacKeyCode(unsigned int macKeyCode)
 
 - (void)otherMouseUp:(NSEvent *)event
 {
-    _glfwInputMouseClick(window, [event buttonNumber], GLFW_RELEASE);
+    _glfwInputMouseClick(window,
+                         [event buttonNumber],
+                         GLFW_RELEASE,
+                         convertKeyMods([event modifierFlags]));
 }
 
 - (void)mouseExited:(NSEvent *)event
@@ -503,7 +537,12 @@ static int convertMacKeyCode(unsigned int macKeyCode)
 
 - (void)keyDown:(NSEvent *)event
 {
-    _glfwInputKey(window, convertMacKeyCode([event keyCode]), GLFW_PRESS);
+    const NSUInteger mods = [event modifierFlags];
+
+    _glfwInputKey(window,
+                  convertMacKeyCode([event keyCode]),
+                  GLFW_PRESS,
+                  convertKeyMods(mods));
 
     if ([event modifierFlags] & NSCommandKeyMask)
         return;
@@ -530,12 +569,15 @@ static int convertMacKeyCode(unsigned int macKeyCode)
 
     key = convertMacKeyCode([event keyCode]);
     if (key != -1)
-      _glfwInputKey(window, key, action);
+        _glfwInputKey(window, key, action, convertKeyMods([event modifierFlags]));
 }
 
 - (void)keyUp:(NSEvent *)event
 {
-    _glfwInputKey(window, convertMacKeyCode([event keyCode]), GLFW_RELEASE);
+    _glfwInputKey(window,
+                  convertMacKeyCode([event keyCode]),
+                  GLFW_RELEASE,
+                  convertKeyMods([event modifierFlags]));
 }
 
 - (void)scrollWheel:(NSEvent *)event

+ 4 - 4
src/input.c

@@ -122,7 +122,7 @@ static void setStickyMouseButtons(_GLFWwindow* window, int enabled)
 //////                         GLFW event API                       //////
 //////////////////////////////////////////////////////////////////////////
 
-void _glfwInputKey(_GLFWwindow* window, int key, int action)
+void _glfwInputKey(_GLFWwindow* window, int key, int action, int mods)
 {
     GLboolean repeated = GL_FALSE;
 
@@ -141,7 +141,7 @@ void _glfwInputKey(_GLFWwindow* window, int key, int action)
         action = GLFW_REPEAT;
 
     if (window->callbacks.key)
-        window->callbacks.key((GLFWwindow*) window, key, action);
+        window->callbacks.key((GLFWwindow*) window, key, action, mods);
 }
 
 void _glfwInputChar(_GLFWwindow* window, unsigned int character)
@@ -162,7 +162,7 @@ void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset)
         window->callbacks.scroll((GLFWwindow*) window, xoffset, yoffset);
 }
 
-void _glfwInputMouseClick(_GLFWwindow* window, int button, int action)
+void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods)
 {
     if (button < 0 || button > GLFW_MOUSE_BUTTON_LAST)
         return;
@@ -174,7 +174,7 @@ void _glfwInputMouseClick(_GLFWwindow* window, int button, int action)
         window->mouseButton[button] = (char) action;
 
     if (window->callbacks.mouseButton)
-        window->callbacks.mouseButton((GLFWwindow*) window, button, action);
+        window->callbacks.mouseButton((GLFWwindow*) window, button, action, mods);
 }
 
 void _glfwInputCursorMotion(_GLFWwindow* window, double x, double y)

+ 3 - 2
src/internal.h

@@ -591,9 +591,10 @@ void _glfwInputWindowCloseRequest(_GLFWwindow* window);
  *  @param[in] window The window that received the event.
  *  @param[in] key The key that was pressed or released.
  *  @param[in] action @ref GLFW_PRESS or @ref GLFW_RELEASE.
+ *  @param[in] mods The modifiers pressed when the event was generated.
  *  @ingroup event
  */
-void _glfwInputKey(_GLFWwindow* window, int key, int action);
+void _glfwInputKey(_GLFWwindow* window, int key, int action, int mods);
 
 /*! @brief Notifies shared code of a Unicode character input event.
  *  @param[in] window The window that received the event.
@@ -616,7 +617,7 @@ void _glfwInputScroll(_GLFWwindow* window, double x, double y);
  *  @param[in] action @ref GLFW_PRESS or @ref GLFW_RELEASE.
  *  @ingroup event
  */
-void _glfwInputMouseClick(_GLFWwindow* window, int button, int action);
+void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods);
 
 /*! @brief Notifies shared code of a cursor motion event.
  *  @param[in] window The window that received the event.

+ 59 - 21
src/win32_window.c

@@ -104,6 +104,38 @@ static void showCursor(_GLFWwindow* window)
     }
 }
 
+// Retrieves and translates modifier keys
+//
+static int getKeyMods(void)
+{
+    int mods = 0;
+
+    if (GetKeyState(VK_SHIFT) & (1 << 31))
+        mods |= GLFW_MOD_SHIFT;
+    if (GetKeyState(VK_CONTROL) & (1 << 31))
+        mods |= GLFW_MOD_CTRL;
+    if (GetKeyState(VK_MENU) & (1 << 31))
+        mods |= GLFW_MOD_ALT;
+
+    return mods;
+}
+
+// Retrieves and translates modifier keys
+//
+static int getAsyncKeyMods(void)
+{
+    int mods = 0;
+
+    if (GetAsyncKeyState(VK_SHIFT) & (1 << 31))
+        mods |= GLFW_MOD_SHIFT;
+    if (GetAsyncKeyState(VK_CONTROL) & (1 << 31))
+        mods |= GLFW_MOD_CTRL;
+    if (GetAsyncKeyState(VK_MENU) & (1 << 31))
+        mods |= GLFW_MOD_ALT;
+
+    return mods;
+}
+
 // Translates a Windows key to the corresponding GLFW key
 //
 static int translateKey(WPARAM wParam, LPARAM lParam)
@@ -433,7 +465,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
         case WM_KEYDOWN:
         case WM_SYSKEYDOWN:
         {
-            _glfwInputKey(window, translateKey(wParam, lParam), GLFW_PRESS);
+            _glfwInputKey(window, translateKey(wParam, lParam), GLFW_PRESS, getKeyMods());
             break;
         }
 
@@ -461,20 +493,22 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
         case WM_KEYUP:
         case WM_SYSKEYUP:
         {
+            const int mods = getKeyMods();
+
             if (wParam == VK_SHIFT)
             {
                 // Special trick: release both shift keys on SHIFT up event
-                _glfwInputKey(window, GLFW_KEY_LEFT_SHIFT, GLFW_RELEASE);
-                _glfwInputKey(window, GLFW_KEY_RIGHT_SHIFT, GLFW_RELEASE);
+                _glfwInputKey(window, GLFW_KEY_LEFT_SHIFT, GLFW_RELEASE, mods);
+                _glfwInputKey(window, GLFW_KEY_RIGHT_SHIFT, GLFW_RELEASE, mods);
             }
             else if (wParam == VK_SNAPSHOT)
             {
                 // Key down is not reported for the print screen key
-                _glfwInputKey(window, GLFW_KEY_PRINT_SCREEN, GLFW_PRESS);
-                _glfwInputKey(window, GLFW_KEY_PRINT_SCREEN, GLFW_RELEASE);
+                _glfwInputKey(window, GLFW_KEY_PRINT_SCREEN, GLFW_PRESS, mods);
+                _glfwInputKey(window, GLFW_KEY_PRINT_SCREEN, GLFW_RELEASE, mods);
             }
             else
-                _glfwInputKey(window, translateKey(wParam, lParam), GLFW_RELEASE);
+                _glfwInputKey(window, translateKey(wParam, lParam), GLFW_RELEASE, getKeyMods());
 
             break;
         }
@@ -484,20 +518,22 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
         case WM_MBUTTONDOWN:
         case WM_XBUTTONDOWN:
         {
+            const int mods = getKeyMods();
+
             SetCapture(hWnd);
 
             if (uMsg == WM_LBUTTONDOWN)
-                _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS);
+                _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS, mods);
             else if (uMsg == WM_RBUTTONDOWN)
-                _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_RIGHT, GLFW_PRESS);
+                _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_RIGHT, GLFW_PRESS, mods);
             else if (uMsg == WM_MBUTTONDOWN)
-                _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_MIDDLE, GLFW_PRESS);
+                _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_MIDDLE, GLFW_PRESS, mods);
             else
             {
                 if (HIWORD(wParam) == XBUTTON1)
-                    _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_4, GLFW_PRESS);
+                    _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_4, GLFW_PRESS, mods);
                 else if (HIWORD(wParam) == XBUTTON2)
-                    _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_5, GLFW_PRESS);
+                    _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_5, GLFW_PRESS, mods);
 
                 return TRUE;
             }
@@ -510,20 +546,22 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
         case WM_MBUTTONUP:
         case WM_XBUTTONUP:
         {
+            const int mods = getKeyMods();
+
             ReleaseCapture();
 
             if (uMsg == WM_LBUTTONUP)
-                _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_LEFT, GLFW_RELEASE);
+                _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_LEFT, GLFW_RELEASE, mods);
             else if (uMsg == WM_RBUTTONUP)
-                _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_RIGHT, GLFW_RELEASE);
+                _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_RIGHT, GLFW_RELEASE, mods);
             else if (uMsg == WM_MBUTTONUP)
-                _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_MIDDLE, GLFW_RELEASE);
+                _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_MIDDLE, GLFW_RELEASE, mods);
             else
             {
                 if (HIWORD(wParam) == XBUTTON1)
-                    _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_4, GLFW_RELEASE);
+                    _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_4, GLFW_RELEASE, mods);
                 else if (HIWORD(wParam) == XBUTTON2)
-                    _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_5, GLFW_RELEASE);
+                    _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_5, GLFW_RELEASE, mods);
 
                 return TRUE;
             }
@@ -1017,19 +1055,19 @@ void _glfwPlatformPollEvents(void)
         // This is the only async event handling in GLFW, but it solves some
         // nasty problems
         {
-            int lshiftDown, rshiftDown;
+            const int mods = getAsyncKeyMods();
 
             // Get current state of left and right shift keys
-            lshiftDown = (GetAsyncKeyState(VK_LSHIFT) >> 15) & 1;
-            rshiftDown = (GetAsyncKeyState(VK_RSHIFT) >> 15) & 1;
+            const int lshiftDown = (GetAsyncKeyState(VK_LSHIFT) >> 15) & 1;
+            const int rshiftDown = (GetAsyncKeyState(VK_RSHIFT) >> 15) & 1;
 
             // See if this differs from our belief of what has happened
             // (we only have to check for lost key up events)
             if (!lshiftDown && window->key[GLFW_KEY_LEFT_SHIFT] == 1)
-                _glfwInputKey(window, GLFW_KEY_LEFT_SHIFT, GLFW_RELEASE);
+                _glfwInputKey(window, GLFW_KEY_LEFT_SHIFT, GLFW_RELEASE, mods);
 
             if (!rshiftDown && window->key[GLFW_KEY_RIGHT_SHIFT] == 1)
-                _glfwInputKey(window, GLFW_KEY_RIGHT_SHIFT, GLFW_RELEASE);
+                _glfwInputKey(window, GLFW_KEY_RIGHT_SHIFT, GLFW_RELEASE, mods);
         }
 
         // Did the cursor move in an focused window that has captured the cursor

+ 2 - 2
src/window.c

@@ -77,14 +77,14 @@ void _glfwInputWindowFocus(_GLFWwindow* window, GLboolean focused)
             for (i = 0;  i <= GLFW_KEY_LAST;  i++)
             {
                 if (window->key[i] == GLFW_PRESS)
-                    _glfwInputKey(window, i, GLFW_RELEASE);
+                    _glfwInputKey(window, i, GLFW_RELEASE, 0);
             }
 
             // Release all pressed mouse buttons
             for (i = 0;  i <= GLFW_MOUSE_BUTTON_LAST;  i++)
             {
                 if (window->mouseButton[i] == GLFW_PRESS)
-                    _glfwInputMouseClick(window, i, GLFW_RELEASE);
+                    _glfwInputMouseClick(window, i, GLFW_RELEASE, 0);
             }
         }
     }

+ 39 - 13
src/x11_window.c

@@ -58,6 +58,22 @@ typedef struct
 #define MWM_HINTS_DECORATIONS (1L << 1)
 
 
+// Translates an X event modifier state mask
+//
+int translateState(int state)
+{
+    int mods = 0;
+
+    if (state & ShiftMask)
+        mods |= GLFW_MOD_SHIFT;
+    if (state & ControlMask)
+        mods |= GLFW_MOD_CTRL;
+    if (state & Mod1Mask)
+        mods |= GLFW_MOD_ALT;
+
+    return mods;
+}
+
 // Translates an X Window key to internal coding
 //
 static int translateKey(int keycode)
@@ -511,31 +527,36 @@ static void processEvent(XEvent *event)
     {
         case KeyPress:
         {
-            _glfwInputKey(window, translateKey(event->xkey.keycode), GLFW_PRESS);
+            const int key = translateKey(event->xkey.keycode);
+            const int mods = translateState(event->xkey.state);
 
-            if (!(event->xkey.state & ControlMask) &&
-                !(event->xkey.state & Mod1Mask /*Alt*/))
-            {
-            _glfwInputChar(window, translateChar(&event->xkey));
-            }
+            _glfwInputKey(window, key, GLFW_PRESS, mods);
+
+            if (!(mods & GLFW_MOD_CTRL) && !(mods & GLFW_MOD_ALT))
+                _glfwInputChar(window, translateChar(&event->xkey));
 
             break;
         }
 
         case KeyRelease:
         {
-            _glfwInputKey(window, translateKey(event->xkey.keycode), GLFW_RELEASE);
+            const int key = translateKey(event->xkey.keycode);
+            const int mods = translateState(event->xkey.state);
+
+            _glfwInputKey(window, key, GLFW_RELEASE, mods);
             break;
         }
 
         case ButtonPress:
         {
+            const int mods = translateState(event->xbutton.state);
+
             if (event->xbutton.button == Button1)
-                _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS);
+                _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS, mods);
             else if (event->xbutton.button == Button2)
-                _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_MIDDLE, GLFW_PRESS);
+                _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_MIDDLE, GLFW_PRESS, mods);
             else if (event->xbutton.button == Button3)
-                _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_RIGHT, GLFW_PRESS);
+                _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_RIGHT, GLFW_PRESS, mods);
 
             // Modern X provides scroll events as mouse button presses
             else if (event->xbutton.button == Button4)
@@ -552,23 +573,28 @@ static void processEvent(XEvent *event)
 
         case ButtonRelease:
         {
+            const int mods = translateState(event->xbutton.state);
+
             if (event->xbutton.button == Button1)
             {
                 _glfwInputMouseClick(window,
                                      GLFW_MOUSE_BUTTON_LEFT,
-                                     GLFW_RELEASE);
+                                     GLFW_RELEASE,
+                                     mods);
             }
             else if (event->xbutton.button == Button2)
             {
                 _glfwInputMouseClick(window,
                                      GLFW_MOUSE_BUTTON_MIDDLE,
-                                     GLFW_RELEASE);
+                                     GLFW_RELEASE,
+                                     mods);
             }
             else if (event->xbutton.button == Button3)
             {
                 _glfwInputMouseClick(window,
                                      GLFW_MOUSE_BUTTON_RIGHT,
-                                     GLFW_RELEASE);
+                                     GLFW_RELEASE,
+                                     mods);
             }
             break;
         }

+ 1 - 1
tests/accuracy.c

@@ -74,7 +74,7 @@ static void cursor_position_callback(GLFWwindow* window, double x, double y)
     cursor_y = y;
 }
 
-static void key_callback(GLFWwindow* window, int key, int action)
+static void key_callback(GLFWwindow* window, int key, int action, int mods)
 {
     if (key == GLFW_KEY_SPACE && action == GLFW_PRESS)
         set_swap_interval(window, 1 - swap_interval);

+ 3 - 9
tests/clipboard.c

@@ -39,18 +39,12 @@ static void usage(void)
     printf("Usage: clipboard [-h]\n");
 }
 
-static GLboolean control_is_down(GLFWwindow* window)
-{
-    return glfwGetKey(window, GLFW_KEY_LEFT_CONTROL) ||
-           glfwGetKey(window, GLFW_KEY_RIGHT_CONTROL);
-}
-
 static void error_callback(int error, const char* description)
 {
     fprintf(stderr, "Error: %s\n", description);
 }
 
-static void key_callback(GLFWwindow* window, int key, int action)
+static void key_callback(GLFWwindow* window, int key, int action, int mods)
 {
     if (action != GLFW_PRESS)
         return;
@@ -62,7 +56,7 @@ static void key_callback(GLFWwindow* window, int key, int action)
             break;
 
         case GLFW_KEY_V:
-            if (control_is_down(window))
+            if (mods == GLFW_MOD_CTRL)
             {
                 const char* string;
 
@@ -75,7 +69,7 @@ static void key_callback(GLFWwindow* window, int key, int action)
             break;
 
         case GLFW_KEY_C:
-            if (control_is_down(window))
+            if (mods == GLFW_MOD_CTRL)
             {
                 const char* string = "Hello GLFW World!";
                 glfwSetClipboardString(window, string);

+ 31 - 8
tests/events.c

@@ -36,6 +36,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <ctype.h>
+#include <string.h>
 #include <locale.h>
 
 // These must match the input mode defaults
@@ -206,6 +207,22 @@ static const char* get_button_name(int button)
     return NULL;
 }
 
+static const char* get_mods_name(int mods)
+{
+    static char name[512];
+
+    name[0] = '\0';
+
+    if (mods & GLFW_MOD_SHIFT)
+        strcat(name, " shift");
+    if (mods & GLFW_MOD_CTRL)
+        strcat(name, " control");
+    if (mods & GLFW_MOD_ALT)
+        strcat(name, " alt");
+
+    return name;
+}
+
 static const char* get_character_string(int character)
 {
     // This assumes UTF-8, which is stupid
@@ -278,16 +295,19 @@ static void window_iconify_callback(GLFWwindow* window, int iconified)
            iconified ? "iconified" : "restored");
 }
 
-static void mouse_button_callback(GLFWwindow* window, int button, int action)
+static void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
 {
     const char* name = get_button_name(button);
 
     printf("%08x at %0.3f: Mouse button %i", counter++, glfwGetTime(), button);
 
     if (name)
-        printf(" (%s) was %s\n", name, get_action_name(action));
-    else
-        printf(" was %s\n", get_action_name(action));
+        printf(" (%s)", name);
+
+    if (mods)
+        printf(" (with%s)", get_mods_name(mods));
+
+    printf(" was %s\n", get_action_name(action));
 }
 
 static void cursor_position_callback(GLFWwindow* window, double x, double y)
@@ -308,16 +328,19 @@ static void scroll_callback(GLFWwindow* window, double x, double y)
     printf("%08x at %0.3f: Scroll: %0.3f %0.3f\n", counter++, glfwGetTime(), x, y);
 }
 
-static void key_callback(GLFWwindow* window, int key, int action)
+static void key_callback(GLFWwindow* window, int key, int action, int mods)
 {
     const char* name = get_key_name(key);
 
     printf("%08x at %0.3f: Key 0x%04x", counter++, glfwGetTime(), key);
 
     if (name)
-        printf(" (%s) was %s\n", name, get_action_name(action));
-    else
-        printf(" was %s\n", get_action_name(action));
+        printf(" (%s)", name);
+
+    if (mods)
+        printf(" (with%s)", get_mods_name(mods));
+
+    printf(" was %s\n", get_action_name(action));
 
     if (action != GLFW_PRESS)
         return;

+ 10 - 10
tests/fsaa.c

@@ -48,17 +48,17 @@ static void window_size_callback(GLFWwindow* window, int width, int height)
     glViewport(0, 0, width, height);
 }
 
-static void key_callback(GLFWwindow* window, int key, int action)
+static void key_callback(GLFWwindow* window, int key, int action, int mods)
 {
-  if (action != GLFW_PRESS)
-    return;
-
-  switch (key)
-  {
-    case GLFW_KEY_SPACE:
-      glfwSetTime(0.0);
-      break;
-  }
+    if (action != GLFW_PRESS)
+        return;
+
+    switch (key)
+    {
+        case GLFW_KEY_SPACE:
+            glfwSetTime(0.0);
+            break;
+    }
 }
 
 static void usage(void)

+ 1 - 1
tests/gamma.c

@@ -60,7 +60,7 @@ static void error_callback(int error, const char* description)
     fprintf(stderr, "Error: %s\n", description);
 }
 
-static void key_callback(GLFWwindow* window, int key, int action)
+static void key_callback(GLFWwindow* window, int key, int action, int mods)
 {
     if (action != GLFW_PRESS)
         return;

+ 1 - 1
tests/iconify.c

@@ -45,7 +45,7 @@ static void error_callback(int error, const char* description)
     fprintf(stderr, "Error: %s\n", description);
 }
 
-static void key_callback(GLFWwindow* window, int key, int action)
+static void key_callback(GLFWwindow* window, int key, int action, int mods)
 {
     printf("%0.2f Key %s\n",
            glfwGetTime(),

+ 1 - 1
tests/modes.c

@@ -73,7 +73,7 @@ static void window_size_callback(GLFWwindow* window, int width, int height)
     glViewport(0, 0, width, height);
 }
 
-static void key_callback(GLFWwindow* window, int key, int action)
+static void key_callback(GLFWwindow* window, int key, int action, int mods)
 {
     if (key == GLFW_KEY_ESCAPE)
         glfwSetWindowShouldClose(window, GL_TRUE);

+ 1 - 1
tests/peter.c

@@ -65,7 +65,7 @@ static void cursor_position_callback(GLFWwindow* window, double x, double y)
     cursor_y = y;
 }
 
-static void key_callback(GLFWwindow* window, int key, int action)
+static void key_callback(GLFWwindow* window, int key, int action, int mods)
 {
     switch (key)
     {

+ 1 - 1
tests/reopen.c

@@ -53,7 +53,7 @@ static void window_close_callback(GLFWwindow* window)
     printf("Close callback triggered\n");
 }
 
-static void key_callback(GLFWwindow* window, int key, int action)
+static void key_callback(GLFWwindow* window, int key, int action, int mods)
 {
     if (action != GLFW_PRESS)
         return;

+ 1 - 1
tests/sharing.c

@@ -44,7 +44,7 @@ static void error_callback(int error, const char* description)
     fprintf(stderr, "Error: %s\n", description);
 }
 
-static void key_callback(GLFWwindow* window, int key, int action)
+static void key_callback(GLFWwindow* window, int key, int action, int mods)
 {
     if (action == GLFW_PRESS && key == GLFW_KEY_ESCAPE)
         glfwSetWindowShouldClose(window, GL_TRUE);

+ 1 - 1
tests/tearing.c

@@ -64,7 +64,7 @@ static void window_size_callback(GLFWwindow* window, int width, int height)
     glViewport(0, 0, width, height);
 }
 
-static void key_callback(GLFWwindow* window, int key, int action)
+static void key_callback(GLFWwindow* window, int key, int action, int mods)
 {
     if (key == GLFW_KEY_SPACE && action == GLFW_PRESS)
         set_swap_interval(window, 1 - swap_interval);