summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/cocoa/qnsview.mm
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/cocoa/qnsview.mm')
-rw-r--r--src/plugins/platforms/cocoa/qnsview.mm207
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;