diff options
Diffstat (limited to 'src/plugins/platforms/cocoa/qnsview.mm')
-rw-r--r-- | src/plugins/platforms/cocoa/qnsview.mm | 207 |
1 files changed, 191 insertions, 16 deletions
diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 4505f8b8cf..51c3953af1 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -492,7 +492,7 @@ static QTouchDevice *touchDevice = 0; return YES; } -- (void)convertFromEvent:(NSEvent *)event toWindowPoint:(QPoint *)qtWindowPoint andScreenPoint:(QPoint *)qtScreenPoint +- (void)convertFromEvent:(NSEvent *)event toWindowPoint:(QPointF *)qtWindowPoint andScreenPoint:(QPointF *)qtScreenPoint { // Calculate the mouse position in the QWindow and Qt screen coordinate system, // starting from coordinates in the NSWindow coordinate system. @@ -515,19 +515,19 @@ static QTouchDevice *touchDevice = 0; NSPoint nsWindowPoint = [event locationInWindow]; // NSWindow coordinates NSPoint nsViewPoint = [self convertPoint: nsWindowPoint fromView: nil]; // NSView/QWindow coordinates - *qtWindowPoint = QPoint(nsViewPoint.x, nsViewPoint.y); // NSView/QWindow coordinates + *qtWindowPoint = QPointF(nsViewPoint.x, nsViewPoint.y); // NSView/QWindow coordinates NSWindow *window = [self window]; // Use convertRectToScreen if available (added in 10.7). #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 if ([window respondsToSelector:@selector(convertRectToScreen:)]) { NSRect screenRect = [window convertRectToScreen : NSMakeRect(nsWindowPoint.x, nsWindowPoint.y, 0, 0)]; // OS X screen coordinates - *qtScreenPoint = QPoint(screenRect.origin.x, qt_mac_flipYCoordinate(screenRect.origin.y)); // Qt screen coordinates + *qtScreenPoint = QPointF(screenRect.origin.x, qt_mac_flipYCoordinate(screenRect.origin.y)); // Qt screen coordinates } else #endif { NSPoint screenPoint = [window convertBaseToScreen : NSMakePoint(nsWindowPoint.x, nsWindowPoint.y)]; - *qtScreenPoint = QPoint(screenPoint.x, qt_mac_flipYCoordinate(screenPoint.y)); + *qtScreenPoint = QPointF(screenPoint.x, qt_mac_flipYCoordinate(screenPoint.y)); } } @@ -538,7 +538,10 @@ static QTouchDevice *touchDevice = 0; - (void)handleMouseEvent:(NSEvent *)theEvent { - QPoint qtWindowPoint, qtScreenPoint; + [self handleTabletEvent: theEvent]; + + QPointF qtWindowPoint; + QPointF qtScreenPoint; [self convertFromEvent:theEvent toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint]; ulong timestamp = [theEvent timestamp] * 1000; @@ -678,9 +681,10 @@ static QTouchDevice *touchDevice = 0; if (m_window->flags() & Qt::WindowTransparentForInput) return [super mouseMoved:theEvent]; - QPoint windowPoint, screenPoint; + QPointF windowPoint; + QPointF screenPoint; [self convertFromEvent:theEvent toWindowPoint:&windowPoint andScreenPoint:&screenPoint]; - QWindow *childWindow = m_platformWindow->childWindowAt(windowPoint); + QWindow *childWindow = m_platformWindow->childWindowAt(windowPoint.toPoint()); // Top-level windows generate enter-leave events for sub-windows. // Qt wants to know which window (if any) will be entered at the @@ -711,9 +715,10 @@ static QTouchDevice *touchDevice = 0; if (!m_platformWindow->m_nsWindow) return; - QPoint windowPoint, screenPoint; + QPointF windowPoint; + QPointF screenPoint; [self convertFromEvent:theEvent toWindowPoint:&windowPoint andScreenPoint:&screenPoint]; - m_platformWindow->m_underMouseWindow = m_platformWindow->childWindowAt(windowPoint); + m_platformWindow->m_underMouseWindow = m_platformWindow->childWindowAt(windowPoint.toPoint()); QWindowSystemInterface::handleEnterEvent(m_platformWindow->m_underMouseWindow, windowPoint, screenPoint); } @@ -781,6 +786,162 @@ static QTouchDevice *touchDevice = 0; [self handleMouseEvent:theEvent]; } +struct QCocoaTabletDeviceData +{ + QTabletEvent::TabletDevice device; + QTabletEvent::PointerType pointerType; + uint capabilityMask; + qint64 uid; +}; + +typedef QHash<uint, QCocoaTabletDeviceData> QCocoaTabletDeviceDataHash; +Q_GLOBAL_STATIC(QCocoaTabletDeviceDataHash, tabletDeviceDataHash) + +- (void)handleTabletEvent: (NSEvent *)theEvent +{ + NSEventType eventType = [theEvent type]; + if (eventType != NSTabletPoint && [theEvent subtype] != NSTabletPointEventSubtype) + return; // Not a tablet event. + + ulong timestamp = [theEvent timestamp] * 1000; + + QPointF windowPoint; + QPointF screenPoint; + [self convertFromEvent: theEvent toWindowPoint: &windowPoint andScreenPoint: &screenPoint]; + + uint deviceId = [theEvent deviceID]; + if (!tabletDeviceDataHash->contains(deviceId)) { + qWarning("QNSView handleTabletEvent: This tablet device is unknown" + " (received no proximity event for it). Discarding event."); + return; + } + const QCocoaTabletDeviceData &deviceData = tabletDeviceDataHash->value(deviceId); + + bool down = (eventType != NSMouseMoved); + + qreal pressure; + if (down) { + pressure = [theEvent pressure]; + } else { + pressure = 0.0; + } + + NSPoint tilt = [theEvent tilt]; + int xTilt = qRound(tilt.x * 60.0); + int yTilt = qRound(tilt.y * -60.0); + qreal tangentialPressure = 0; + qreal rotation = 0; + int z = 0; + if (deviceData.capabilityMask & 0x0200) + z = [theEvent absoluteZ]; + + if (deviceData.capabilityMask & 0x0800) + tangentialPressure = [theEvent tangentialPressure]; + + rotation = [theEvent rotation]; + + Qt::KeyboardModifiers keyboardModifiers = [QNSView convertKeyModifiers:[theEvent modifierFlags]]; + + QWindowSystemInterface::handleTabletEvent(m_window, timestamp, down, windowPoint, screenPoint, + deviceData.device, deviceData.pointerType, pressure, xTilt, yTilt, + tangentialPressure, rotation, z, deviceData.uid, + keyboardModifiers); +} + +- (void)tabletPoint: (NSEvent *)theEvent +{ + if (m_window->flags() & Qt::WindowTransparentForInput) + return [super tabletPoint:theEvent]; + + [self handleTabletEvent: theEvent]; +} + +static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) +{ + qint64 uid = [theEvent uniqueID]; + uint bits = [theEvent vendorPointingDeviceType]; + if (bits == 0 && uid != 0) { + // Fallback. It seems that the driver doesn't always include all the information. + // High-End Wacom devices store their "type" in the uper bits of the Unique ID. + // I'm not sure how to handle it for consumer devices, but I'll test that in a bit. + bits = uid >> 32; + } + + QTabletEvent::TabletDevice device; + // Defined in the "EN0056-NxtGenImpGuideX" + // on Wacom's Developer Website (www.wacomeng.com) + if (((bits & 0x0006) == 0x0002) && ((bits & 0x0F06) != 0x0902)) { + device = QTabletEvent::Stylus; + } else { + switch (bits & 0x0F06) { + case 0x0802: + device = QTabletEvent::Stylus; + break; + case 0x0902: + device = QTabletEvent::Airbrush; + break; + case 0x0004: + device = QTabletEvent::FourDMouse; + break; + case 0x0006: + device = QTabletEvent::Puck; + break; + case 0x0804: + device = QTabletEvent::RotationStylus; + break; + default: + device = QTabletEvent::NoDevice; + } + } + return device; +} + +- (void)tabletProximity: (NSEvent *)theEvent +{ + if (m_window->flags() & Qt::WindowTransparentForInput) + return [super tabletProximity:theEvent]; + + ulong timestamp = [theEvent timestamp] * 1000; + + QCocoaTabletDeviceData deviceData; + deviceData.uid = [theEvent uniqueID]; + deviceData.capabilityMask = [theEvent capabilityMask]; + + switch ([theEvent pointingDeviceType]) { + case NSUnknownPointingDevice: + default: + deviceData.pointerType = QTabletEvent::UnknownPointer; + break; + case NSPenPointingDevice: + deviceData.pointerType = QTabletEvent::Pen; + break; + case NSCursorPointingDevice: + deviceData.pointerType = QTabletEvent::Cursor; + break; + case NSEraserPointingDevice: + deviceData.pointerType = QTabletEvent::Eraser; + break; + } + + deviceData.device = wacomTabletDevice(theEvent); + + // The deviceID is "unique" while in the proximity, it's a key that we can use for + // linking up QCocoaTabletDeviceData to an event (especially if there are two devices in action). + bool entering = [theEvent isEnteringProximity]; + uint deviceId = [theEvent deviceID]; + if (entering) { + tabletDeviceDataHash->insert(deviceId, deviceData); + } else { + tabletDeviceDataHash->remove(deviceId); + } + + if (entering) { + QWindowSystemInterface::handleTabletEnterProximityEvent(timestamp, deviceData.device, deviceData.pointerType, deviceData.uid); + } else { + QWindowSystemInterface::handleTabletLeaveProximityEvent(timestamp, deviceData.device, deviceData.pointerType, deviceData.uid); + } +} + - (void)touchesBeganWithEvent:(NSEvent *)event { const NSTimeInterval timestamp = [event timestamp]; @@ -861,7 +1022,8 @@ static QTouchDevice *touchDevice = 0; } #endif - QPoint qt_windowPoint, qt_screenPoint; + QPointF qt_windowPoint; + QPointF qt_screenPoint; [self convertFromEvent:theEvent toWindowPoint:&qt_windowPoint andScreenPoint:&qt_screenPoint]; NSTimeInterval timestamp = [theEvent timestamp]; ulong qt_timestamp = timestamp * 1000; @@ -880,7 +1042,23 @@ static QTouchDevice *touchDevice = 0; currentWheelModifiers = [QNSView convertKeyModifiers:[theEvent modifierFlags]]; } - QWindowSystemInterface::handleWheelEvent(m_window, qt_timestamp, qt_windowPoint, qt_screenPoint, pixelDelta, angleDelta, currentWheelModifiers); + Qt::ScrollPhase ph = Qt::ScrollUpdate; +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8 + if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_8) { + // On 10.8 and above, MayBegin is likely to happen. We treat it the same as an actual begin. + if (phase == NSEventPhaseMayBegin) + ph = Qt::ScrollBegin; + } else +#endif + if (phase == NSEventPhaseBegan) { + // On 10.7, MayBegin will not happen, so Began is the actual beginning. + ph = Qt::ScrollBegin; + } + if (phase == NSEventPhaseEnded || phase == NSEventPhaseCancelled) { + ph = Qt::ScrollEnd; + } + + QWindowSystemInterface::handleWheelEvent(m_window, qt_timestamp, qt_windowPoint, qt_screenPoint, pixelDelta, angleDelta, currentWheelModifiers, ph); if (phase == NSEventPhaseEnded || phase == NSEventPhaseCancelled || phase == NSEventPhaseNone) { currentWheelModifiers = Qt::NoModifier; @@ -923,14 +1101,11 @@ static QTouchDevice *touchDevice = 0; NSString *charactersIgnoringModifiers = [nsevent charactersIgnoringModifiers]; NSString *characters = [nsevent characters]; - // [from Qt 4 impl] There is no way to get the scan code from carbon. But we cannot + // There is no way to get the scan code from carbon/cocoa. But we cannot // use the value 0, since it indicates that the event originates from somewhere // else than the keyboard. quint32 nativeScanCode = 1; - - UInt32 nativeVirtualKey = 0; - EventRef eventRef = EventRef([nsevent eventRef]); - GetEventParameter(eventRef, kEventParamKeyCode, typeUInt32, 0, sizeof(nativeVirtualKey), 0, &nativeVirtualKey); + quint32 nativeVirtualKey = [nsevent keyCode]; QChar ch = QChar::ReplacementCharacter; int keyCode = Qt::Key_unknown; |