Ver código fonte

Add glfwGetEventTime for querying input event time

Fixes #1012.
Felipe Ferreira da Silva 8 anos atrás
pai
commit
c577ae4b0e

+ 21 - 0
include/GLFW/glfw3.h

@@ -3366,6 +3366,27 @@ GLFWAPI GLFWwindowmaximizefun glfwSetWindowMaximizeCallback(GLFWwindow* window,
  */
 GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* window, GLFWframebuffersizefun cbfun);
 
+/*! @brief Returns the time of the last input event.
+ *
+ *  This function returns the time, in seconds, of the last event occurence. The
+ *  only events queried are the input events button-press, button-release,
+ *  key-press, key-release and cursor motion, and the proper place to call this
+ *  function is in one of the input callbacks.
+ *
+ *  @return The value, in seconds, of the last input event occurence.
+ *
+ *  @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
+ *
+ *  @thread_safety This function must only be called from the main thread.
+ *
+ *  @sa @ref events
+ *
+ *  @since Added in version 3.3.
+ *
+ *  @ingroup window
+ */
+GLFWAPI double glfwGetEventTime(void);
+
 /*! @brief Processes all pending events.
  *
  *  This function processes only those events that are already in the event

+ 3 - 0
src/cocoa_platform.h

@@ -118,6 +118,9 @@ typedef struct _GLFWlibraryNS
     // The window whose disabled cursor mode is active
     _GLFWwindow*        disabledCursorWindow;
 
+    // The time of the last event
+    double              lastEventTime;
+
     struct {
         CFBundleRef     bundle;
         PFN_TISCopyCurrentKeyboardLayoutInputSource CopyCurrentKeyboardLayoutInputSource;

+ 31 - 0
src/cocoa_window.m

@@ -446,6 +446,8 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
 
 - (void)mouseDown:(NSEvent *)event
 {
+    _glfw.ns.lastEventTime = [event timestamp];
+
     _glfwInputMouseClick(window,
                          GLFW_MOUSE_BUTTON_LEFT,
                          GLFW_PRESS,
@@ -454,11 +456,15 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
 
 - (void)mouseDragged:(NSEvent *)event
 {
+    _glfw.ns.lastEventTime = [event timestamp];
+
     [self mouseMoved:event];
 }
 
 - (void)mouseUp:(NSEvent *)event
 {
+    _glfw.ns.lastEventTime = [event timestamp];
+
     _glfwInputMouseClick(window,
                          GLFW_MOUSE_BUTTON_LEFT,
                          GLFW_RELEASE,
@@ -467,6 +473,8 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
 
 - (void)mouseMoved:(NSEvent *)event
 {
+    _glfw.ns.lastEventTime = [event timestamp];
+
     if (window->cursorMode == GLFW_CURSOR_DISABLED)
     {
         const double dx = [event deltaX] - window->ns.cursorWarpDeltaX;
@@ -490,6 +498,8 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
 
 - (void)rightMouseDown:(NSEvent *)event
 {
+    _glfw.ns.lastEventTime = [event timestamp];
+
     _glfwInputMouseClick(window,
                          GLFW_MOUSE_BUTTON_RIGHT,
                          GLFW_PRESS,
@@ -498,11 +508,15 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
 
 - (void)rightMouseDragged:(NSEvent *)event
 {
+    _glfw.ns.lastEventTime = [event timestamp];
+
     [self mouseMoved:event];
 }
 
 - (void)rightMouseUp:(NSEvent *)event
 {
+    _glfw.ns.lastEventTime = [event timestamp];
+
     _glfwInputMouseClick(window,
                          GLFW_MOUSE_BUTTON_RIGHT,
                          GLFW_RELEASE,
@@ -511,6 +525,8 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
 
 - (void)otherMouseDown:(NSEvent *)event
 {
+    _glfw.ns.lastEventTime = [event timestamp];
+
     _glfwInputMouseClick(window,
                          (int) [event buttonNumber],
                          GLFW_PRESS,
@@ -519,11 +535,15 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
 
 - (void)otherMouseDragged:(NSEvent *)event
 {
+    _glfw.ns.lastEventTime = [event timestamp];
+
     [self mouseMoved:event];
 }
 
 - (void)otherMouseUp:(NSEvent *)event
 {
+    _glfw.ns.lastEventTime = [event timestamp];
+
     _glfwInputMouseClick(window,
                          (int) [event buttonNumber],
                          GLFW_RELEASE,
@@ -588,6 +608,8 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
     const int key = translateKey([event keyCode]);
     const int mods = translateFlags([event modifierFlags]);
 
+    _glfw.ns.lastEventTime = [event timestamp];
+
     _glfwInputKey(window, key, [event keyCode], GLFW_PRESS, mods);
 
     [self interpretKeyEvents:[NSArray arrayWithObject:event]];
@@ -619,6 +641,9 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
 {
     const int key = translateKey([event keyCode]);
     const int mods = translateFlags([event modifierFlags]);
+
+    _glfw.ns.lastEventTime = [event timestamp];
+
     _glfwInputKey(window, key, [event keyCode], GLFW_RELEASE, mods);
 }
 
@@ -1462,6 +1487,12 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled)
         [window->ns.object setLevel:NSNormalWindowLevel];
 }
 
+double _glfwPlatformGetEventTime(void)
+{
+    /* Windows events are stored in seconds */
+    return _glfw.ns.lastEventTime;
+}
+
 void _glfwPlatformPollEvents(void)
 {
     for (;;)

+ 1 - 0
src/internal.h

@@ -685,6 +685,7 @@ void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled);
 void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled);
 void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled);
 
+double _glfwPlatformGetEventTime(void);
 void _glfwPlatformPollEvents(void);
 void _glfwPlatformWaitEvents(void);
 void _glfwPlatformWaitEventsTimeout(double timeout);

+ 3 - 0
src/mir_platform.h

@@ -114,6 +114,9 @@ typedef struct _GLFWlibraryMir
     // The window whose disabled cursor mode is active
     _GLFWwindow* disabledCursorWindow;
 
+    // The time of the last event
+    int64_t                 lastEventTime;
+
 } _GLFWlibraryMir;
 
 // Mir-specific per-cursor data

+ 12 - 0
src/mir_window.c

@@ -147,6 +147,8 @@ static void handleKeyEvent(const MirKeyboardEvent* key_event, _GLFWwindow* windo
     const long text    = _glfwKeySym2Unicode(key_code);
     const int  plain   = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT));
 
+    _glfw.mir.lastEventTime = mir_input_event_get_event_time((MirInputEvent *) key_event);
+
     _glfwInputKey(window, toGLFWKeyCode(scan_code), scan_code, pressed, mods);
 
     if (text != -1)
@@ -164,6 +166,8 @@ static void handlePointerButton(_GLFWwindow* window,
     uint32_t newButtonStates        = mir_pointer_event_buttons(pointer_event);
     int publicButton                = GLFW_MOUSE_BUTTON_LEFT;
 
+    _glfw.mir.lastEventTime = mir_input_event_get_event_time((MirEvent *) pointer_event);
+
     // XOR our old button states our new states to figure out what was added or removed
     button = newButtonStates ^ oldButtonStates;
 
@@ -201,6 +205,8 @@ static void handlePointerMotion(_GLFWwindow* window,
     const int hscroll = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_hscroll);
     const int vscroll = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_vscroll);
 
+    _glfw.mir.lastEventTime = mir_input_event_get_event_time((MirEvent *) pointer_event);
+
     if (window->cursorMode == GLFW_CURSOR_DISABLED)
     {
         if (_glfw.mir.disabledCursorWindow != window)
@@ -632,6 +638,12 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled)
                     "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
 }
 
+double _glfwPlatformGetEventTime(void)
+{
+    /* Mir events are stored in nanoseconds */
+    return (double) _glfw.mir.lastEventTime / 1000000000.0;
+}
+
 void _glfwPlatformPollEvents(void)
 {
     EventNode* node = NULL;

+ 5 - 0
src/null_window.c

@@ -204,6 +204,11 @@ int _glfwPlatformWindowVisible(_GLFWwindow* window)
     return GLFW_FALSE;
 }
 
+double _glfwPlatformGetEventTime(void)
+{
+    return 0.0;
+}
+
 void _glfwPlatformPollEvents(void)
 {
 }

+ 3 - 0
src/win32_platform.h

@@ -259,6 +259,9 @@ typedef struct _GLFWlibraryWin32
     RAWINPUT*           rawInput;
     int                 rawInputSize;
 
+    // The time of the last event
+    LONG                lastEventTime;
+
     struct {
         HINSTANCE                       instance;
         PFN_timeGetTime                 GetTime;

+ 10 - 0
src/win32_window.c

@@ -595,6 +595,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
         case WM_UNICHAR:
         {
             const GLFWbool plain = (uMsg != WM_SYSCHAR);
+            _glfw.win32.lastEventTime = GetMessageTime();
 
             if (uMsg == WM_UNICHAR && wParam == UNICODE_NOCHAR)
             {
@@ -617,6 +618,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
             const int scancode = (lParam >> 16) & 0x1ff;
             const int action = ((lParam >> 31) & 1) ? GLFW_RELEASE : GLFW_PRESS;
             const int mods = getKeyMods();
+            _glfw.win32.lastEventTime = GetMessageTime();
 
             if (key == _GLFW_KEY_INVALID)
                 break;
@@ -651,6 +653,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
         case WM_XBUTTONUP:
         {
             int i, button, action;
+            _glfw.win32.lastEventTime = GetMessageTime();
 
             if (uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONUP)
                 button = GLFW_MOUSE_BUTTON_LEFT;
@@ -701,6 +704,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
         {
             const int x = GET_X_LPARAM(lParam);
             const int y = GET_Y_LPARAM(lParam);
+            _glfw.win32.lastEventTime = GetMessageTime();
 
             // Disabled cursor motion input is provided by WM_INPUT
             if (window->cursorMode == GLFW_CURSOR_DISABLED)
@@ -1498,6 +1502,12 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled)
                  SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
 }
 
+double _glfwPlatformGetEventTime(void)
+{
+    /* Windows events are stored in milliseconds */
+    return (double) _glfw.win32.lastEventTime / 1000.0;
+}
+
 void _glfwPlatformPollEvents(void)
 {
     MSG msg;

+ 7 - 0
src/window.c

@@ -956,6 +956,13 @@ GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* handle
     return cbfun;
 }
 
+GLFWAPI double glfwGetEventTime(void)
+{
+    _GLFW_REQUIRE_INIT_OR_RETURN(0.0);
+
+    return _glfwPlatformGetEventTime();
+}
+
 GLFWAPI void glfwPollEvents(void)
 {
     _GLFW_REQUIRE_INIT();

+ 4 - 0
src/wl_init.c

@@ -83,6 +83,7 @@ static void pointerHandleMotion(void* data,
     if (!window)
         return;
 
+    _glfw.wl.lastEventTime = time;
     if (window->cursorMode == GLFW_CURSOR_DISABLED)
         return;
     else
@@ -109,6 +110,7 @@ static void pointerHandleButton(void* data,
     if (!window)
         return;
 
+    _glfw.wl.lastEventTime = time;
     _glfw.wl.pointerSerial = serial;
 
     /* Makes left, right and middle 0, 1 and 2. Overall order follows evdev
@@ -136,6 +138,7 @@ static void pointerHandleAxis(void* data,
     if (!window)
         return;
 
+    _glfw.wl.lastEventTime = time;
     /* Wayland scroll events are in pointer motion coordinate space (think
      * two finger scroll). The factor 10 is commonly used to convert to
      * "scroll step means 1.0. */
@@ -349,6 +352,7 @@ static void keyboardHandleKey(void* data,
     if (!window)
         return;
 
+    _glfw.wl.lastEventTime = time;
     keyCode = toGLFWKeyCode(key);
     action = state == WL_KEYBOARD_KEY_STATE_PRESSED
             ? GLFW_PRESS : GLFW_RELEASE;

+ 4 - 0
src/wl_platform.h

@@ -97,6 +97,7 @@ typedef struct _GLFWwindowWayland
         struct zwp_relative_pointer_v1*    relativePointer;
         struct zwp_locked_pointer_v1*      lockedPointer;
     } pointerLock;
+
 } _GLFWwindowWayland;
 
 // Wayland-specific global data
@@ -138,6 +139,9 @@ typedef struct _GLFWlibraryWayland
     _GLFWwindow*                pointerFocus;
     _GLFWwindow*                keyboardFocus;
 
+    // The time of the last event
+    unsigned int                lastEventTime;
+
 } _GLFWlibraryWayland;
 
 // Wayland-specific per-monitor data

+ 5 - 0
src/wl_window.c

@@ -675,6 +675,11 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled)
                     "Wayland: Window attribute setting not implemented yet");
 }
 
+double _glfwPlatformGetEventTime(void)
+{
+    return (double) _glfw.wl.lastEventTime / 1000.0;
+}
+
 void _glfwPlatformPollEvents(void)
 {
     handleEvents(0);

+ 3 - 0
src/x11_platform.h

@@ -226,6 +226,9 @@ typedef struct _GLFWlibraryX11
     // The window whose disabled cursor mode is active
     _GLFWwindow*    disabledCursorWindow;
 
+    // The time of the last event
+    Time            lastEventTime;
+
     // Window manager atoms
     Atom            WM_PROTOCOLS;
     Atom            WM_STATE;

+ 11 - 0
src/x11_window.c

@@ -1121,6 +1121,7 @@ static void processEvent(XEvent *event)
             const int key = translateKey(keycode);
             const int mods = translateState(event->xkey.state);
             const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT));
+            _glfw.x11.lastEventTime = event->xkey.time;
 
             if (window->x11.ic)
             {
@@ -1214,6 +1215,7 @@ static void processEvent(XEvent *event)
         {
             const int key = translateKey(keycode);
             const int mods = translateState(event->xkey.state);
+            _glfw.x11.lastEventTime = event->xkey.time;
 
             if (!_glfw.x11.xkb.detectable)
             {
@@ -1254,6 +1256,7 @@ static void processEvent(XEvent *event)
         case ButtonPress:
         {
             const int mods = translateState(event->xbutton.state);
+            _glfw.x11.lastEventTime = event->xbutton.time;
 
             if (event->xbutton.button == Button1)
                 _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS, mods);
@@ -1288,6 +1291,7 @@ static void processEvent(XEvent *event)
         case ButtonRelease:
         {
             const int mods = translateState(event->xbutton.state);
+            _glfw.x11.lastEventTime = event->xbutton.time;
 
             if (event->xbutton.button == Button1)
             {
@@ -1344,6 +1348,7 @@ static void processEvent(XEvent *event)
         {
             const int x = event->xmotion.x;
             const int y = event->xmotion.y;
+            _glfw.x11.lastEventTime = event->xmotion.time;
 
             if (x != window->x11.warpCursorPosX || y != window->x11.warpCursorPosY)
             {
@@ -2428,6 +2433,12 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled)
     XFlush(_glfw.x11.display);
 }
 
+double _glfwPlatformGetEventTime(void)
+{
+    /* X11 events are stored in milliseconds */
+    return (double) _glfw.x11.lastEventTime / 1000.0;
+}
+
 void _glfwPlatformPollEvents(void)
 {
     _GLFWwindow* window;

+ 12 - 12
tests/events.c

@@ -269,8 +269,8 @@ static void error_callback(int error, const char* description)
 static void window_pos_callback(GLFWwindow* window, int x, int y)
 {
     Slot* slot = glfwGetWindowUserPointer(window);
-    printf("%08x to %i at %0.3f: Window position: %i %i\n",
-           counter++, slot->number, glfwGetTime(), x, y);
+    printf("%08x to %i at %0.3f (event time: %0.3f): Window position: %i %i\n",
+           counter++, slot->number, glfwGetTime(), glfwGetEventTime(), x, y);
 }
 
 static void window_size_callback(GLFWwindow* window, int width, int height)
@@ -336,8 +336,8 @@ static void window_maximize_callback(GLFWwindow* window, int maximized)
 static void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
 {
     Slot* slot = glfwGetWindowUserPointer(window);
-    printf("%08x to %i at %0.3f: Mouse button %i (%s) (with%s) was %s\n",
-           counter++, slot->number, glfwGetTime(), button,
+    printf("%08x to %i at %0.3f (event time: %0.3f): Mouse button %i (%s) (with%s) was %s\n",
+           counter++, slot->number, glfwGetTime(), glfwGetEventTime(), button,
            get_button_name(button),
            get_mods_name(mods),
            get_action_name(action));
@@ -346,8 +346,8 @@ static void mouse_button_callback(GLFWwindow* window, int button, int action, in
 static void cursor_position_callback(GLFWwindow* window, double x, double y)
 {
     Slot* slot = glfwGetWindowUserPointer(window);
-    printf("%08x to %i at %0.3f: Cursor position: %f %f\n",
-           counter++, slot->number, glfwGetTime(), x, y);
+    printf("%08x to %i at %0.3f (event time: %0.3f): Cursor position: %f %f\n",
+           counter++, slot->number, glfwGetTime(), glfwGetEventTime(), x, y);
 }
 
 static void cursor_enter_callback(GLFWwindow* window, int entered)
@@ -372,8 +372,8 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action,
 
     if (name)
     {
-        printf("%08x to %i at %0.3f: Key 0x%04x Scancode 0x%04x (%s) (%s) (with%s) was %s\n",
-               counter++, slot->number, glfwGetTime(), key, scancode,
+        printf("%08x to %i at %0.3f (event time: %0.3f): Key 0x%04x Scancode 0x%04x (%s) (%s) (with%s) was %s\n",
+               counter++, slot->number, glfwGetTime(), glfwGetEventTime(), key, scancode,
                get_key_name(key),
                name,
                get_mods_name(mods),
@@ -381,8 +381,8 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action,
     }
     else
     {
-        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,
+        printf("%08x to %i at %0.3f (event time: %0.3f): Key 0x%04x Scancode 0x%04x (%s) (with%s) was %s\n",
+               counter++, slot->number, glfwGetTime(), glfwGetEventTime(), key, scancode,
                get_key_name(key),
                get_mods_name(mods),
                get_action_name(action));
@@ -406,8 +406,8 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action,
 static void char_callback(GLFWwindow* window, unsigned int codepoint)
 {
     Slot* slot = glfwGetWindowUserPointer(window);
-    printf("%08x to %i at %0.3f: Character 0x%08x (%s) input\n",
-           counter++, slot->number, glfwGetTime(), codepoint,
+    printf("%08x to %i at %0.3f (event time: %0.3f): Character 0x%08x (%s) input\n",
+           counter++, slot->number, glfwGetTime(), glfwGetEventTime(), codepoint,
            get_character_string(codepoint));
 }