diff --git a/ui/cocoa.m b/ui/cocoa.m index 1a626e215fc7bf3ca4ba751a7ac352afbec214f4..06951d03f0dd1d5f65eaa2529951074a3ef1a016 100644 --- a/ui/cocoa.m +++ b/ui/cocoa.m @@ -256,7 +256,7 @@ static int cocoa_keycode_to_qemu(int keycode) BOOL isMouseGrabbed; BOOL isFullscreen; BOOL isAbsoluteEnabled; - BOOL isTabletEnabled; + BOOL isMouseDeassociated; } - (void) switchSurface:(DisplaySurface *)surface; - (void) grabMouse; @@ -264,8 +264,21 @@ static int cocoa_keycode_to_qemu(int keycode) - (void) toggleFullScreen:(id)sender; - (void) handleEvent:(NSEvent *)event; - (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled; +/* The state surrounding mouse grabbing is potentially confusing. + * isAbsoluteEnabled tracks qemu_input_is_absolute() [ie "is the emulated + * pointing device an absolute-position one?"], but is only updated on + * next refresh. + * isMouseGrabbed tracks whether GUI events are directed to the guest; + * it controls whether special keys like Cmd get sent to the guest, + * and whether we capture the mouse when in non-absolute mode. + * isMouseDeassociated tracks whether we've told MacOSX to disassociate + * the mouse and mouse cursor position by calling + * CGAssociateMouseAndMouseCursorPosition(FALSE) + * (which basically happens if we grab in non-absolute mode). + */ - (BOOL) isMouseGrabbed; - (BOOL) isAbsoluteEnabled; +- (BOOL) isMouseDeassociated; - (float) cdx; - (float) cdy; - (QEMUScreen) gscreen; @@ -613,14 +626,12 @@ QemuCocoaView *cocoaView; case NSMouseMoved: if (isAbsoluteEnabled) { if (![self screenContainsPoint:p] || ![[self window] isKeyWindow]) { - if (isTabletEnabled) { // if we leave the window, deactivate the tablet - [NSCursor unhide]; - isTabletEnabled = FALSE; + if (isMouseGrabbed) { + [self ungrabMouse]; } } else { - if (!isTabletEnabled) { // if we enter the window, activate the tablet - [NSCursor hide]; - isTabletEnabled = TRUE; + if (!isMouseGrabbed) { + [self grabMouse]; } } } @@ -659,16 +670,9 @@ QemuCocoaView *cocoaView; mouse_event = true; break; case NSLeftMouseUp: - if (isTabletEnabled) { - mouse_event = true; - } else if (!isMouseGrabbed) { - if ([self screenContainsPoint:p]) { - [self grabMouse]; - } else { - [NSApp sendEvent:event]; - } - } else { - mouse_event = true; + mouse_event = true; + if (!isMouseGrabbed && [self screenContainsPoint:p]) { + [self grabMouse]; } break; case NSRightMouseUp: @@ -678,13 +682,11 @@ QemuCocoaView *cocoaView; mouse_event = true; break; case NSScrollWheel: - if (isTabletEnabled || isMouseGrabbed) { + if (isMouseGrabbed) { buttons |= ([event deltaY] < 0) ? MOUSE_EVENT_WHEELUP : MOUSE_EVENT_WHEELDN; - mouse_event = true; - } else { - [NSApp sendEvent:event]; } + mouse_event = true; break; default: [NSApp sendEvent:event]; @@ -702,12 +704,20 @@ QemuCocoaView *cocoaView; qemu_input_update_buttons(dcl->con, bmap, last_buttons, buttons); last_buttons = buttons; } - if (isTabletEnabled) { - qemu_input_queue_abs(dcl->con, INPUT_AXIS_X, p.x, screen.width); - qemu_input_queue_abs(dcl->con, INPUT_AXIS_Y, p.y, screen.height); - } else if (isMouseGrabbed) { - qemu_input_queue_rel(dcl->con, INPUT_AXIS_X, (int)[event deltaX]); - qemu_input_queue_rel(dcl->con, INPUT_AXIS_Y, (int)[event deltaY]); + if (isMouseGrabbed) { + if (isAbsoluteEnabled) { + /* Note that the origin for Cocoa mouse coords is bottom left, not top left. + * The check on screenContainsPoint is to avoid sending out of range values for + * clicks in the titlebar. + */ + if ([self screenContainsPoint:p]) { + qemu_input_queue_abs(dcl->con, INPUT_AXIS_X, p.x, screen.width); + qemu_input_queue_abs(dcl->con, INPUT_AXIS_Y, screen.height - p.y, screen.height); + } + } else { + qemu_input_queue_rel(dcl->con, INPUT_AXIS_X, (int)[event deltaX]); + qemu_input_queue_rel(dcl->con, INPUT_AXIS_Y, (int)[event deltaY]); + } } else { [NSApp sendEvent:event]; } @@ -726,7 +736,10 @@ QemuCocoaView *cocoaView; [normalWindow setTitle:@"QEMU - (Press ctrl + alt to release Mouse)"]; } [NSCursor hide]; - CGAssociateMouseAndMouseCursorPosition(FALSE); + if (!isAbsoluteEnabled) { + isMouseDeassociated = TRUE; + CGAssociateMouseAndMouseCursorPosition(FALSE); + } isMouseGrabbed = TRUE; // while isMouseGrabbed = TRUE, QemuCocoaApp sends all events to [cocoaView handleEvent:] } @@ -741,13 +754,17 @@ QemuCocoaView *cocoaView; [normalWindow setTitle:@"QEMU"]; } [NSCursor unhide]; - CGAssociateMouseAndMouseCursorPosition(TRUE); + if (isMouseDeassociated) { + CGAssociateMouseAndMouseCursorPosition(TRUE); + isMouseDeassociated = FALSE; + } isMouseGrabbed = FALSE; } - (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled {isAbsoluteEnabled = tIsAbsoluteEnabled;} - (BOOL) isMouseGrabbed {return isMouseGrabbed;} - (BOOL) isAbsoluteEnabled {return isAbsoluteEnabled;} +- (BOOL) isMouseDeassociated {return isMouseDeassociated;} - (float) cdx {return cdx;} - (float) cdy {return cdy;} - (QEMUScreen) gscreen {return screen;}