aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcancel <cancel@cancel.fm>2021-02-19 23:34:21 +0900
committercancel <cancel@cancel.fm>2021-02-20 00:19:35 +0900
commit9ea9c481aab3aeac4e43906d048fdcf14da12d73 (patch)
treedcc17edba988fd3e74ad88fcf5c0f79dfdfcaa78
parentd54c27f9ea1b10bec1134c06bb40a1b2ad322792 (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.h55
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;