Pārlūkot izejas kodu

Added character with modifiers callback.

The undefined behaviour changed with #40 has been reverted, making the
character-only callback again behave like a system text field.  This
behavior has now been documentated.

Fixes #203.
Fixes #305.
Camilla Berglund 11 gadi atpakaļ
vecāks
revīzija
96b12ee504
9 mainītis faili ar 133 papildinājumiem un 38 dzēšanām
  1. 1 0
      README.md
  2. 8 0
      docs/news.dox
  3. 58 3
      include/GLFW/glfw3.h
  4. 3 1
      src/cocoa_window.m
  5. 17 3
      src/input.c
  6. 5 1
      src/internal.h
  7. 7 2
      src/win32_window.c
  8. 4 1
      src/x11_window.c
  9. 30 27
      tests/events.c

+ 1 - 0
README.md

@@ -56,6 +56,7 @@ GLFW bundles a number of dependencies in the `deps/` directory.
  - Added `glfwPostEmptyEvent` for allowing secondary threads to cause
    `glfwWaitEvents` to return
  - Added `empty` test program for verifying posting of empty events
+ - Added `glfwSetCharModsCallback` for receiving character events with modifiers
  - Added `glfwGetWindowFrameSize` for retrieving the size of the frame around
    the client area of a window
  - Added `GLFW_AUTO_ICONIFY` for controlling whether full screen windows

+ 8 - 0
docs/news.dox

@@ -47,6 +47,14 @@ GLFW not supports floating windows, also called topmost or always on top, for
 easier debugging, with the `GLFW_FLOATING` window hint.
 
 
+@subsection news_31_charmods Character with modifiers callback
+
+GLFW now provides a callback for character events with modifier key bits.
+Unlike the regular character callback, this will report character events that
+will not result in a character being input, for example if the Control key is
+held down.
+
+
 @subsection news_31_egl Stable EGL support
 
 The support for EGL is now stable, successfully running on PandaBoards, Mesa,

+ 58 - 3
include/GLFW/glfw3.h

@@ -788,6 +788,24 @@ typedef void (* GLFWkeyfun)(GLFWwindow*,int,int,int,int);
  */
 typedef void (* GLFWcharfun)(GLFWwindow*,unsigned int);
 
+/*! @brief The function signature for Unicode character with modifiers
+ *  callbacks.
+ *
+ *  This is the function signature for Unicode character with modifiers callback
+ *  functions.  It is called for each input character, regardless of what
+ *  modifier keys are held down.
+ *
+ *  @param[in] window The window that received the event.
+ *  @param[in] codepoint The Unicode code point of the character.
+ *  @param[in] mods Bit field describing which [modifier keys](@ref mods) were
+ *  held down.
+ *
+ *  @sa glfwSetCharModsCallback
+ *
+ *  @ingroup input
+ */
+typedef void (* GLFWcharmodsfun)(GLFWwindow*,unsigned int,int);
+
 /*! @brief The function signature for file drop callbacks.
  *
  *  This is the function signature for file drop callbacks.
@@ -2151,9 +2169,19 @@ GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* window, GLFWkeyfun cbfun);
  *  This function sets the character callback of the specific window, which is
  *  called when a Unicode character is input.
  *
- *  The character callback is intended for text input.  If you want to know
- *  whether a specific key was pressed or released, use the
- *  [key callback](@ref glfwSetKeyCallback) instead.
+ *  The character callback is intended for Unicode text input.  As it deals with
+ *  characters, it is keyboard layout dependent, whereas the
+ *  [key callback](@ref glfwSetKeyCallback) is not.  Characters do not map 1:1
+ *  to physical keys, as a key may produce zero, one or more characters.  If you
+ *  want to know whether a specific physical key was pressed or released, see
+ *  the key callback instead.
+ *
+ *  The character callback behaves as system text input normally does and will
+ *  not be called if modifier keys are held down that would prevent normal text
+ *  input on that platform, for example a Super (Command) key on OS X or Alt key
+ *  on Windows.  There is a
+ *  [character with modifiers callback](@ref glfwSetCharModsCallback) that
+ *  receives these events.
  *
  *  @param[in] window The window whose callback to set.
  *  @param[in] cbfun The new callback, or `NULL` to remove the currently set
@@ -2167,6 +2195,33 @@ GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* window, GLFWkeyfun cbfun);
  */
 GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* window, GLFWcharfun cbfun);
 
+/*! @brief Sets the Unicode character with modifiers callback.
+ *
+ *  This function sets the character with modifiers callback of the specific
+ *  window, which is called when a Unicode character is input regardless of what
+ *  modifier keys are used.
+ *
+ *  The character with modifiers callback is intended for implementing custom
+ *  Unicode character input.  For regular Unicode text input, see the
+ *  [character callback](@ref glfwSetCharCallback).  Like the character
+ *  callback, the character with modifiers callback deals with characters and is
+ *  keyboard layout dependent.  Characters do not map 1:1 to physical keys, as
+ *  a key may produce zero, one or more characters.  If you want to know whether
+ *  a specific physical key was pressed or released, see the
+ *  [key callback](@ref glfwSetKeyCallback) instead.
+ *
+ *  @param[in] window The window whose callback to set.
+ *  @param[in] cbfun The new callback, or `NULL` to remove the currently set
+ *  callback.
+ *  @return The previously set callback, or `NULL` if no callback was set or an
+ *  error occurred.
+ *
+ *  @note This function may only be called from the main thread.
+ *
+ *  @ingroup input
+ */
+GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* window, GLFWcharmodsfun cbfun);
+
 /*! @brief Sets the mouse button callback.
  *
  *  This function sets the mouse button callback of the specified window, which

+ 3 - 1
src/cocoa_window.m

@@ -605,13 +605,15 @@ static int translateKey(unsigned int key)
 {
     const int key = translateKey([event keyCode]);
     const int mods = translateFlags([event modifierFlags]);
+
     _glfwInputKey(window, key, [event keyCode], GLFW_PRESS, mods);
 
     NSString* characters = [event characters];
     NSUInteger i, length = [characters length];
+    const int plain = !(mods & GLFW_MOD_SUPER);
 
     for (i = 0;  i < length;  i++)
-        _glfwInputChar(window, [characters characterAtIndex:i]);
+        _glfwInputChar(window, [characters characterAtIndex:i], mods, plain);
 }
 
 - (void)flagsChanged:(NSEvent *)event

+ 17 - 3
src/input.c

@@ -153,13 +153,19 @@ void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int m
         window->callbacks.key((GLFWwindow*) window, key, scancode, action, mods);
 }
 
-void _glfwInputChar(_GLFWwindow* window, unsigned int codepoint)
+void _glfwInputChar(_GLFWwindow* window, unsigned int codepoint, int mods, int plain)
 {
     if (codepoint < 32 || (codepoint > 126 && codepoint < 160))
         return;
 
-    if (window->callbacks.character)
-        window->callbacks.character((GLFWwindow*) window, codepoint);
+    if (window->callbacks.charmods)
+        window->callbacks.charmods((GLFWwindow*) window, codepoint, mods);
+
+    if (plain)
+    {
+        if (window->callbacks.character)
+            window->callbacks.character((GLFWwindow*) window, codepoint);
+    }
 }
 
 void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset)
@@ -439,6 +445,14 @@ GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* handle, GLFWcharfun cbfun)
     return cbfun;
 }
 
+GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* handle, GLFWcharmodsfun cbfun)
+{
+    _GLFWwindow* window = (_GLFWwindow*) handle;
+    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
+    _GLFW_SWAP_POINTERS(window->callbacks.charmods, cbfun);
+    return cbfun;
+}
+
 GLFWAPI GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* handle,
                                                       GLFWmousebuttonfun cbfun)
 {

+ 5 - 1
src/internal.h

@@ -262,6 +262,7 @@ struct _GLFWwindow
         GLFWscrollfun           scroll;
         GLFWkeyfun              key;
         GLFWcharfun             character;
+        GLFWcharmodsfun         charmods;
         GLFWdropfun             drop;
     } callbacks;
 
@@ -700,9 +701,12 @@ void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int m
 /*! @brief Notifies shared code of a Unicode character input event.
  *  @param[in] window The window that received the event.
  *  @param[in] codepoint The Unicode code point of the input character.
+ *  @param[in] mods Bit field describing which modifier keys were held down.
+ *  @param[in] plain `GL_TRUE` if the character is regular text input, or
+ *  `GL_FALSE` otherwise.
  *  @ingroup event
  */
-void _glfwInputChar(_GLFWwindow* window, unsigned int codepoint);
+void _glfwInputChar(_GLFWwindow* window, unsigned int codepoint, int mods, int plain);
 
 /*! @brief Notifies shared code of a scroll event.
  *  @param[in] window The window that received the event.

+ 7 - 2
src/win32_window.c

@@ -526,9 +526,14 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
         }
 
         case WM_CHAR:
+        {
+            _glfwInputChar(window, (unsigned int) wParam, getKeyMods(), GL_TRUE);
+            return 0;
+        }
+
         case WM_SYSCHAR:
         {
-            _glfwInputChar(window, (unsigned int) wParam);
+            _glfwInputChar(window, (unsigned int) wParam, getKeyMods(), GL_FALSE);
             return 0;
         }
 
@@ -543,7 +548,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
                 return TRUE;
             }
 
-            _glfwInputChar(window, (unsigned int) wParam);
+            _glfwInputChar(window, (unsigned int) wParam, getKeyMods(), GL_TRUE);
             return FALSE;
         }
 

+ 4 - 1
src/x11_window.c

@@ -609,7 +609,10 @@ static void processEvent(XEvent *event)
             _glfwInputKey(window, key, event->xkey.keycode, GLFW_PRESS, mods);
 
             if (character != -1)
-                _glfwInputChar(window, character);
+            {
+                const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT));
+                _glfwInputChar(window, character, mods, plain);
+            }
 
             break;
         }

+ 30 - 27
tests/events.c

@@ -187,9 +187,8 @@ static const char* get_key_name(int key)
         case GLFW_KEY_LEFT_SUPER:   return "LEFT SUPER";
         case GLFW_KEY_RIGHT_SUPER:  return "RIGHT SUPER";
         case GLFW_KEY_MENU:         return "MENU";
-        case GLFW_KEY_UNKNOWN:      return "UNKNOWN";
 
-        default:                    return NULL;
+        default:                    return "UNKNOWN";
     }
 }
 
@@ -218,15 +217,22 @@ static const char* get_button_name(int button)
             return "right";
         case GLFW_MOUSE_BUTTON_MIDDLE:
             return "middle";
+        default:
+        {
+            static char name[16];
+            sprintf(name, "%i", button);
+            return name;
+        }
     }
-
-    return NULL;
 }
 
 static const char* get_mods_name(int mods)
 {
     static char name[512];
 
+    if (mods == 0)
+        return " no mods";
+
     name[0] = '\0';
 
     if (mods & GLFW_MOD_SHIFT)
@@ -321,18 +327,11 @@ static void window_iconify_callback(GLFWwindow* window, int iconified)
 static void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
 {
     Slot* slot = glfwGetWindowUserPointer(window);
-    const char* name = get_button_name(button);
-
-    printf("%08x to %i at %0.3f: Mouse button %i",
-           counter++, slot->number, glfwGetTime(), button);
-
-    if (name)
-        printf(" (%s)", name);
-
-    if (mods)
-        printf(" (with%s)", get_mods_name(mods));
-
-    printf(" was %s\n", get_action_name(action));
+    printf("%08x to %i at %0.3f: Mouse button %i (%s) (with%s) was %s\n",
+           counter++, slot->number, glfwGetTime(), button,
+           get_button_name(button),
+           get_mods_name(mods),
+           get_action_name(action));
 }
 
 static void cursor_position_callback(GLFWwindow* window, double x, double y)
@@ -359,19 +358,13 @@ static void scroll_callback(GLFWwindow* window, double x, double y)
 
 static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
 {
-    const char* name = get_key_name(key);
     Slot* slot = glfwGetWindowUserPointer(window);
 
-    printf("%08x to %i at %0.3f: Key 0x%04x Scancode 0x%04x",
-           counter++, slot->number, glfwGetTime(), key, scancode);
-
-    if (name)
-        printf(" (%s)", name);
-
-    if (mods)
-        printf(" (with%s)", get_mods_name(mods));
-
-    printf(" was %s\n", get_action_name(action));
+    printf("%08x to %i at %0.3f: Key 0x%04x Scancode 0x%04x (%s) (with%s) was %s\n",
+           counter++, slot->number, glfwGetTime(), key, scancode,
+           get_key_name(key),
+           get_mods_name(mods),
+           get_action_name(action));
 
     if (action != GLFW_PRESS)
         return;
@@ -396,6 +389,15 @@ static void char_callback(GLFWwindow* window, unsigned int codepoint)
            get_character_string(codepoint));
 }
 
+static void char_mods_callback(GLFWwindow* window, unsigned int codepoint, int mods)
+{
+    Slot* slot = glfwGetWindowUserPointer(window);
+    printf("%08x to %i at %0.3f: Character 0x%08x (%s) (with%s) input\n",
+            counter++, slot->number, glfwGetTime(), codepoint,
+            get_character_string(codepoint),
+            get_mods_name(mods));
+}
+
 static void drop_callback(GLFWwindow* window, int count, const char** names)
 {
     int i;
@@ -546,6 +548,7 @@ int main(int argc, char** argv)
         glfwSetScrollCallback(slots[i].window, scroll_callback);
         glfwSetKeyCallback(slots[i].window, key_callback);
         glfwSetCharCallback(slots[i].window, char_callback);
+        glfwSetCharModsCallback(slots[i].window, char_mods_callback);
         glfwSetDropCallback(slots[i].window, drop_callback);
 
         glfwMakeContextCurrent(slots[i].window);