diff --git a/panda/src/cocoadisplay/cocoaGraphicsWindow.mm b/panda/src/cocoadisplay/cocoaGraphicsWindow.mm index 3c3a933e51..7ac27c723d 100644 --- a/panda/src/cocoadisplay/cocoaGraphicsWindow.mm +++ b/panda/src/cocoadisplay/cocoaGraphicsWindow.mm @@ -1026,6 +1026,23 @@ set_properties_now(WindowProperties &properties) { } properties.clear_z_order(); } + + if (properties.has_mouse_mode()) { + switch (properties.get_mouse_mode()) { + case WindowProperties::M_absolute: + case WindowProperties::M_confined: // confined is maintained in mouse move event + CGAssociateMouseAndMouseCursorPosition(true); + _properties.set_mouse_mode(properties.get_mouse_mode()); + properties.clear_mouse_mode(); + break; + + case WindowProperties::M_relative: + CGAssociateMouseAndMouseCursorPosition(false); + _properties.set_mouse_mode(properties.get_mouse_mode()); + properties.clear_mouse_mode(); + break; + } + } } //////////////////////////////////////////////////////////////////// @@ -1674,6 +1691,8 @@ handle_mouse_button_event(int button, bool down) { //////////////////////////////////////////////////////////////////// void CocoaGraphicsWindow:: handle_mouse_moved_event(bool in_window, double x, double y, bool absolute) { + double nx, ny; + if (absolute) { if (cocoadisplay_cat.is_spam()) { if (in_window != _input_devices[0].get_pointer().get_in_window()) { @@ -1686,15 +1705,40 @@ handle_mouse_moved_event(bool in_window, double x, double y, bool absolute) { } // Strangely enough, in Cocoa, mouse Y coordinates are 1-based. - _input_devices[0].set_pointer(in_window, x, y - 1, - ClockObject::get_global_clock()->get_frame_time()); + nx = x; + ny = y - 1; } else { // We received deltas, so add it to the current mouse position. MouseData md = _input_devices[0].get_pointer(); - _input_devices[0].set_pointer_in_window(md.get_x() + x, md.get_y() + y); + nx = md.get_x() + x; + ny = md.get_y() + y; } + if (_properties.get_mouse_mode() == WindowProperties::M_confined + && !in_window) { + CGPoint point; + + nx = std::max(0., std::min((double) get_x_size() - 1, nx)); + ny = std::max(0., std::min((double) get_y_size() - 1, ny)); + + if (_properties.get_fullscreen()) { + point = CGPointMake(nx, ny + 1); + } else { + point = CGPointMake(nx + _properties.get_x_origin(), + ny + _properties.get_y_origin() + 1); + } + + if (CGWarpMouseCursorPosition(point) == kCGErrorSuccess) { + in_window = true; + } else { + cocoadisplay_cat.warning() << "Failed to return mouse pointer to window\n"; + } + } + + _input_devices[0].set_pointer(in_window, nx, ny, + ClockObject::get_global_clock()->get_frame_time()); + if (in_window != _mouse_hidden && _properties.get_cursor_hidden()) { // Hide the cursor if the mouse enters the window, // and unhide it when the mouse leaves the window. diff --git a/panda/src/cocoadisplay/cocoaPandaView.mm b/panda/src/cocoadisplay/cocoaPandaView.mm index c624f0cdb6..3f0fa550fd 100644 --- a/panda/src/cocoadisplay/cocoaPandaView.mm +++ b/panda/src/cocoadisplay/cocoaPandaView.mm @@ -118,7 +118,10 @@ NSPoint loc = [self convertPoint:[event locationInWindow] fromView:nil]; BOOL inside = [self mouse:loc inRect:[self bounds]]; - if (_graphicsWindow->get_properties().get_mouse_mode() == WindowProperties::M_relative) { + // the correlation between mouse deltas and location + // are "debounced" apparently, so send deltas for both + // relative and confined modes + if (_graphicsWindow->get_properties().get_mouse_mode() != WindowProperties::M_absolute) { _graphicsWindow->handle_mouse_moved_event(inside, [event deltaX], [event deltaY], false); } else { _graphicsWindow->handle_mouse_moved_event(inside, loc.x, loc.y, true); diff --git a/panda/src/osxdisplay/osxGraphicsWindow.mm b/panda/src/osxdisplay/osxGraphicsWindow.mm index 3b18fd3914..36db5a55ce 100644 --- a/panda/src/osxdisplay/osxGraphicsWindow.mm +++ b/panda/src/osxdisplay/osxGraphicsWindow.mm @@ -2064,6 +2064,25 @@ set_properties_now(WindowProperties &properties) { properties.clear_minimized(); } + if (properties.has_mouse_mode()) { + switch (properties.get_mouse_mode()) { + case WindowProperties::M_absolute: + CGAssociateMouseAndMouseCursorPosition(true); + _properties.set_mouse_mode(WindowProperties::M_absolute); + properties.clear_mouse_mode(); + break; + + case WindowProperties::M_relative: + CGAssociateMouseAndMouseCursorPosition(false); + _properties.set_mouse_mode(WindowProperties::M_relative); + properties.clear_mouse_mode(); + break; + + case WindowProperties::M_confined: + break; + } + } + if (osxdisplay_cat.is_debug()) { osxdisplay_cat.debug() << "set_properties_now Out....." << _properties << "\n"; diff --git a/samples/mouse-modes/main.py b/samples/mouse-modes/main.py index 50e81f550e..75ddbf08ea 100644 --- a/samples/mouse-modes/main.py +++ b/samples/mouse-modes/main.py @@ -34,7 +34,8 @@ class App(ShowBase): # Disable the camera trackball controls. self.disableMouse() - self.mouseMagnitude = 144 + # control mapping of mouse movement to box movement + self.mouseMagnitude = 1 self.rotateX, self.rotateY = 0, 0 @@ -146,7 +147,8 @@ class App(ShowBase): if self.manualRecenterMouse: # move mouse back to center self.recenterMouse() - + self.lastMouseX, self.lastMouseY = 0, 0 + # scale position and delta to pixels for user w, h = self.win.getSize() @@ -158,8 +160,8 @@ class App(ShowBase): int(dx*w), int(dy*h))) # rotate box by delta - self.rotateX += dx * 10 - self.rotateY += dy * 10 + self.rotateX += dx * 10 * self.mouseMagnitude + self.rotateY += dy * 10 * self.mouseMagnitude self.positionText.setText("Model rotation: {0}, {1}".format( int(self.rotateX*1000)/1000., int(self.rotateY*1000)/1000.))