summaryrefslogtreecommitdiff
path: root/platform/osx
diff options
context:
space:
mode:
authorbruvzg <7645683+bruvzg@users.noreply.github.com>2020-07-02 15:55:53 +0300
committerbruvzg <7645683+bruvzg@users.noreply.github.com>2020-07-02 17:34:58 +0300
commita9e341cff3e2c7a01e5931e25cb7a2dc71d8e19d (patch)
treea94a07fe08f0a29288b80165c76e4d803b6a15dc /platform/osx
parentf4aea9353707eb10b8039ae8b2ad8820c5aabe2f (diff)
[macOS] Implement confined mouse mode.
Diffstat (limited to 'platform/osx')
-rw-r--r--platform/osx/display_server_osx.h8
-rw-r--r--platform/osx/display_server_osx.mm60
2 files changed, 63 insertions, 5 deletions
diff --git a/platform/osx/display_server_osx.h b/platform/osx/display_server_osx.h
index ac419a821c..8e27f10dc2 100644
--- a/platform/osx/display_server_osx.h
+++ b/platform/osx/display_server_osx.h
@@ -86,6 +86,14 @@ public:
uint32_t unicode;
};
+ struct WarpEvent {
+ NSTimeInterval timestamp;
+ NSPoint delta;
+ };
+
+ List<WarpEvent> warp_events;
+ NSTimeInterval last_warp = 0;
+
Vector<KeyEvent> key_event_buffer;
int key_event_pos;
diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm
index 220ba9ac7e..ee67f46a4c 100644
--- a/platform/osx/display_server_osx.mm
+++ b/platform/osx/display_server_osx.mm
@@ -848,13 +848,59 @@ static void _mouseDownEvent(DisplayServer::WindowID window_id, NSEvent *event, i
ERR_FAIL_COND(!DS_OSX->windows.has(window_id));
DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
+ NSPoint delta = NSMakePoint([event deltaX], [event deltaY]);
+ NSPoint mpos = [event locationInWindow];
+
+ if (DS_OSX->mouse_mode == DisplayServer::MOUSE_MODE_CONFINED) {
+ // Discard late events
+ if (([event timestamp]) < DS_OSX->last_warp) {
+ return;
+ }
+
+ // Warp affects next event delta, subtract previous warp deltas
+ List<DisplayServerOSX::WarpEvent>::Element *F = DS_OSX->warp_events.front();
+ while (F) {
+ if (F->get().timestamp < [event timestamp]) {
+ List<DisplayServerOSX::WarpEvent>::Element *E = F;
+ delta.x -= E->get().delta.x;
+ delta.y -= E->get().delta.y;
+ F = F->next();
+ DS_OSX->warp_events.erase(E);
+ } else {
+ F = F->next();
+ }
+ }
+
+ // Confine mouse position to the window, and update delta
+ NSRect frame = [wd.window_object frame];
+ NSPoint conf_pos = mpos;
+ conf_pos.x = CLAMP(conf_pos.x + delta.x, 0.f, frame.size.width);
+ conf_pos.y = CLAMP(conf_pos.y - delta.y, 0.f, frame.size.height);
+ delta.x = conf_pos.x - mpos.x;
+ delta.y = mpos.y - conf_pos.y;
+ mpos = conf_pos;
+
+ // Move mouse cursor
+ NSRect pointInWindowRect = NSMakeRect(conf_pos.x, conf_pos.y, 0, 0);
+ conf_pos = [[wd.window_view window] convertRectToScreen:pointInWindowRect].origin;
+ conf_pos.y = CGDisplayBounds(CGMainDisplayID()).size.height - conf_pos.y;
+ CGWarpMouseCursorPosition(conf_pos);
+
+ // Save warp data
+ DS_OSX->last_warp = [[NSProcessInfo processInfo] systemUptime];
+ DisplayServerOSX::WarpEvent ev;
+ ev.timestamp = DS_OSX->last_warp;
+ ev.delta = delta;
+ DS_OSX->warp_events.push_back(ev);
+ }
+
Ref<InputEventMouseMotion> mm;
mm.instance();
mm->set_window_id(window_id);
mm->set_button_mask(DS_OSX->last_button_state);
const CGFloat backingScaleFactor = (OS::get_singleton()->is_hidpi_allowed()) ? [[event window] backingScaleFactor] : 1.0;
- const Vector2i pos = _get_mouse_pos(wd, [event locationInWindow], backingScaleFactor);
+ const Vector2i pos = _get_mouse_pos(wd, mpos, backingScaleFactor);
mm->set_position(pos);
mm->set_pressure([event pressure]);
if ([event subtype] == NSEventSubtypeTabletPoint) {
@@ -863,9 +909,7 @@ static void _mouseDownEvent(DisplayServer::WindowID window_id, NSEvent *event, i
}
mm->set_global_position(pos);
mm->set_speed(Input::get_singleton()->get_last_mouse_speed());
- Vector2i relativeMotion = Vector2i();
- relativeMotion.x = [event deltaX] * backingScaleFactor;
- relativeMotion.y = [event deltaY] * backingScaleFactor;
+ const Vector2i relativeMotion = Vector2i(delta.x, delta.y) * backingScaleFactor;
mm->set_relative(relativeMotion);
_get_key_modifier_state([event modifierFlags], mm);
@@ -1970,11 +2014,15 @@ void DisplayServerOSX::mouse_set_mode(MouseMode p_mode) {
CGDisplayHideCursor(kCGDirectMainDisplay);
}
CGAssociateMouseAndMouseCursorPosition(true);
+ } else if (p_mode == MOUSE_MODE_CONFINED) {
+ CGDisplayShowCursor(kCGDirectMainDisplay);
+ CGAssociateMouseAndMouseCursorPosition(false);
} else {
CGDisplayShowCursor(kCGDirectMainDisplay);
CGAssociateMouseAndMouseCursorPosition(true);
}
+ warp_events.clear();
mouse_mode = p_mode;
}
@@ -2004,7 +2052,9 @@ void DisplayServerOSX::mouse_warp_to_position(const Point2i &p_to) {
CGEventSourceSetLocalEventsSuppressionInterval(lEventRef, 0.0);
CGAssociateMouseAndMouseCursorPosition(false);
CGWarpMouseCursorPosition(lMouseWarpPos);
- CGAssociateMouseAndMouseCursorPosition(true);
+ if (mouse_mode != MOUSE_MODE_CONFINED) {
+ CGAssociateMouseAndMouseCursorPosition(true);
+ }
}
}