Implement confined mouse mode for OS X.

Note: it seems that using #set_pointer() will result in
a long delay before an absolute mouse position is updated,
even though deltas are reported.

Thus, in CocoaPandaView, the mouse deltas are sent for both
relative and confined modes, so client code (e.g. the "mouse
modes" demo) will be able to recenter the mouse without
choppy movement.
This commit is contained in:
Ed Swartz 2015-04-23 11:20:24 -05:00 committed by Ed Swartz
parent 5f20afd5ea
commit fc5a2e5e33
4 changed files with 76 additions and 8 deletions

View File

@ -1022,6 +1022,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;
}
}
}
////////////////////////////////////////////////////////////////////
@ -1670,6 +1687,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()) {
@ -1682,15 +1701,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.

View File

@ -116,7 +116,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);

View File

@ -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";

View File

@ -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.))