diff options
| author | cancel <cancel@cancel.fm> | 2021-02-19 23:34:21 +0900 |
|---|---|---|
| committer | cancel <cancel@cancel.fm> | 2021-02-20 00:19:35 +0900 |
| commit | 9ea9c481aab3aeac4e43906d048fdcf14da12d73 (patch) | |
| tree | dcc17edba988fd3e74ad88fcf5c0f79dfdfcaa78 | |
| parent | d54c27f9ea1b10bec1134c06bb40a1b2ad322792 (diff) | |
Improve macOS mouse latency and stale positioning
This commit makes several changes to input event handling in macOS:
_sapp_macos_update_mouse() has been changed to take an NSEvent*
argument, instead of no arguments. And instead of using [window
mouseLocationOutsideOfEventStream] to get the position of the mouse, it
uses event.locationInWindow. This seems to sometimes eliminate a frame
of mouse latency.
_sapp_macos_update_mouse() is no longer called immediately before
rendering a frame. Instead, it's called at the beginning of each of the
mouseMoved:, mouseDragged:, mouseDown:, etc. methods with its associated
NSEvent*. Immediately after, _sapp_macos_mouse_event() is called. This
eliminates a full frame of mouse latency. This also fixes situations
where the mouse cursor's resting apparent position would lag behind its
resting true position after the user stops moving the mouse.
_sapp_macos_poll_input_events() has been added, which calls [NSApp
nextEventMatchingMask: ...] to manually read and dispatch input events
from the event queue. _sapp_macos_poll_input_events() is called
immediately before _sapp_macos_frame(). This will sometimes catch and
dispatch input events that occurred shortly before the frame is to be
rendered, but hadn't yet been dispatched by other mechanisms. This
occasionally eliminates a frame of latency, and improves the worst-case
bounds. This seems to happen to 5% or fewer mouse events.
[NSEvent setMouseCoalescingEnabled:NO], if it even still does anything,
is now called once at during application startup instead of toggled off
and on along with mouse lock.
| -rw-r--r-- | sokol_app.h | 55 |
1 files changed, 50 insertions, 5 deletions
diff --git a/sokol_app.h b/sokol_app.h index 47c52ca8..6b08b8c8 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -2917,9 +2917,9 @@ _SOKOL_PRIVATE void _sapp_macos_update_window_title(void) { [_sapp.macos.window setTitle: [NSString stringWithUTF8String:_sapp.window_title]]; } -_SOKOL_PRIVATE void _sapp_macos_update_mouse(void) { +_SOKOL_PRIVATE void _sapp_macos_update_mouse(NSEvent* event) { if (!_sapp.mouse.locked) { - const NSPoint mouse_pos = [_sapp.macos.window mouseLocationOutsideOfEventStream]; + const NSPoint mouse_pos = event.locationInWindow; float new_x = mouse_pos.x * _sapp.dpi_scale; float new_y = _sapp.framebuffer_height - (mouse_pos.y * _sapp.dpi_scale) - 1; /* don't update dx/dy in the very first update */ @@ -2961,19 +2961,16 @@ _SOKOL_PRIVATE void _sapp_macos_lock_mouse(bool lock) { stack with calls to sapp_show_mouse() */ if (_sapp.mouse.locked) { - [NSEvent setMouseCoalescingEnabled:NO]; CGAssociateMouseAndMouseCursorPosition(NO); CGDisplayHideCursor(kCGDirectMainDisplay); } else { CGDisplayShowCursor(kCGDirectMainDisplay); CGAssociateMouseAndMouseCursorPosition(YES); - [NSEvent setMouseCoalescingEnabled:YES]; } } _SOKOL_PRIVATE void _sapp_macos_frame(void) { - _sapp_macos_update_mouse(); _sapp_frame(); if (_sapp.quit_requested || _sapp.quit_ordered) { [_sapp.macos.window performClose:nil]; @@ -3083,6 +3080,7 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { } [_sapp.macos.window makeKeyAndOrderFront:nil]; _sapp_macos_update_dimensions(); + [NSEvent setMouseCoalescingEnabled:NO]; } - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)sender { @@ -3227,8 +3225,42 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { } #endif +_SOKOL_PRIVATE void _sapp_macos_poll_input_events() { + const NSEventMask mask = NSEventMaskLeftMouseDown | + NSEventMaskLeftMouseUp| + NSEventMaskRightMouseDown | + NSEventMaskRightMouseUp | + NSEventMaskMouseMoved | + NSEventMaskLeftMouseDragged | + NSEventMaskRightMouseDragged | + NSEventMaskMouseEntered | + NSEventMaskMouseExited | + NSEventMaskKeyDown | + NSEventMaskKeyUp | + NSEventMaskCursorUpdate | + NSEventMaskScrollWheel | + NSEventMaskTabletPoint | + NSEventMaskTabletProximity | + NSEventMaskOtherMouseDown | + NSEventMaskOtherMouseUp | + NSEventMaskOtherMouseDragged | + NSEventMaskPressure | + NSEventMaskDirectTouch; + @autoreleasepool { + for (;;) { + NSEvent* event = [NSApp nextEventMatchingMask:mask untilDate:nil inMode:NSDefaultRunLoopMode dequeue:YES]; + if (event == nil) { + break; + } + [NSApp sendEvent:event]; + } + } +} + - (void)drawRect:(NSRect)rect { _SOKOL_UNUSED(rect); + /* Catch any last-moment input events */ + _sapp_macos_poll_input_events(); _sapp_macos_frame(); #if !defined(SOKOL_METAL) [[_sapp.macos.view openGLContext] flushBuffer]; @@ -3260,6 +3292,7 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { [super updateTrackingAreas]; } - (void)mouseEntered:(NSEvent*)event { + _sapp_macos_update_mouse(event); /* don't send mouse enter/leave while dragging (so that it behaves the same as on Windows while SetCapture is active */ @@ -3268,39 +3301,47 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { } } - (void)mouseExited:(NSEvent*)event { + _sapp_macos_update_mouse(event); if (0 == _sapp.macos.mouse_buttons) { _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_LEAVE, SAPP_MOUSEBUTTON_INVALID, _sapp_macos_mod(event.modifierFlags)); } } - (void)mouseDown:(NSEvent*)event { + _sapp_macos_update_mouse(event); _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_DOWN, SAPP_MOUSEBUTTON_LEFT, _sapp_macos_mod(event.modifierFlags)); _sapp.macos.mouse_buttons |= (1<<SAPP_MOUSEBUTTON_LEFT); } - (void)mouseUp:(NSEvent*)event { + _sapp_macos_update_mouse(event); _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_UP, SAPP_MOUSEBUTTON_LEFT, _sapp_macos_mod(event.modifierFlags)); _sapp.macos.mouse_buttons &= ~(1<<SAPP_MOUSEBUTTON_LEFT); } - (void)rightMouseDown:(NSEvent*)event { + _sapp_macos_update_mouse(event); _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_DOWN, SAPP_MOUSEBUTTON_RIGHT, _sapp_macos_mod(event.modifierFlags)); _sapp.macos.mouse_buttons |= (1<<SAPP_MOUSEBUTTON_RIGHT); } - (void)rightMouseUp:(NSEvent*)event { + _sapp_macos_update_mouse(event); _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_UP, SAPP_MOUSEBUTTON_RIGHT, _sapp_macos_mod(event.modifierFlags)); _sapp.macos.mouse_buttons &= ~(1<<SAPP_MOUSEBUTTON_RIGHT); } - (void)otherMouseDown:(NSEvent*)event { + _sapp_macos_update_mouse(event); if (2 == event.buttonNumber) { _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_DOWN, SAPP_MOUSEBUTTON_MIDDLE, _sapp_macos_mod(event.modifierFlags)); _sapp.macos.mouse_buttons |= (1<<SAPP_MOUSEBUTTON_MIDDLE); } } - (void)otherMouseUp:(NSEvent*)event { + _sapp_macos_update_mouse(event); if (2 == event.buttonNumber) { _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_UP, SAPP_MOUSEBUTTON_MIDDLE, _sapp_macos_mod(event.modifierFlags)); _sapp.macos.mouse_buttons &= (1<<SAPP_MOUSEBUTTON_MIDDLE); } } - (void)otherMouseDragged:(NSEvent*)event { + _sapp_macos_update_mouse(event); if (2 == event.buttonNumber) { if (_sapp.mouse.locked) { _sapp.mouse.dx = [event deltaX]; @@ -3310,6 +3351,7 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { } } - (void)mouseMoved:(NSEvent*)event { + _sapp_macos_update_mouse(event); if (_sapp.mouse.locked) { _sapp.mouse.dx = [event deltaX]; _sapp.mouse.dy = [event deltaY]; @@ -3317,6 +3359,7 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_INVALID , _sapp_macos_mod(event.modifierFlags)); } - (void)mouseDragged:(NSEvent*)event { + _sapp_macos_update_mouse(event); if (_sapp.mouse.locked) { _sapp.mouse.dx = [event deltaX]; _sapp.mouse.dy = [event deltaY]; @@ -3324,6 +3367,7 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_INVALID , _sapp_macos_mod(event.modifierFlags)); } - (void)rightMouseDragged:(NSEvent*)event { + _sapp_macos_update_mouse(event); if (_sapp.mouse.locked) { _sapp.mouse.dx = [event deltaX]; _sapp.mouse.dy = [event deltaY]; @@ -3331,6 +3375,7 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_INVALID, _sapp_macos_mod(event.modifierFlags)); } - (void)scrollWheel:(NSEvent*)event { + _sapp_macos_update_mouse(event); if (_sapp_events_enabled()) { float dx = (float) event.scrollingDeltaX; float dy = (float) event.scrollingDeltaY; |