Cocoa: implement support for wheel events
authorRichard Moe Gustavsen <richard.gustavsen@nokia.com>
Wed, 22 Jun 2011 11:57:35 +0000 (13:57 +0200)
committerRichard Moe Gustavsen <richard.gustavsen@nokia.com>
Wed, 22 Jun 2011 11:59:35 +0000 (13:59 +0200)
src/plugins/platforms/cocoa/qnsview.mm

index 5d7fd05..be50dda 100644 (file)
 **
 ****************************************************************************/
 
-#include "qnsview.h"
+#include <Carbon/Carbon.h>
 
+#include "qnsview.h"
 #include <QtGui/QWindowSystemInterface>
-
 #include <QtCore/QDebug>
 
+@interface NSEvent (Qt_Compile_Leopard_DeviceDelta)
+  - (CGFloat)deviceDeltaX;
+  - (CGFloat)deviceDeltaY;
+  - (CGFloat)deviceDeltaZ;
+@end
+
 @implementation QNSView
 
 - (id) init
 {
     [self handleMouseEvent:theEvent];
 }
+
 - (void)mouseEntered:(NSEvent *)theEvent
 {
-        Q_UNUSED(theEvent);
-        QWindowSystemInterface::handleEnterEvent(m_window);
+    Q_UNUSED(theEvent);
+    QWindowSystemInterface::handleEnterEvent(m_window);
 }
+
 - (void)mouseExited:(NSEvent *)theEvent
 {
-        Q_UNUSED(theEvent);
-        QWindowSystemInterface::handleLeaveEvent(m_window);
+    Q_UNUSED(theEvent);
+    QWindowSystemInterface::handleLeaveEvent(m_window);
 }
+
 - (void)rightMouseDown:(NSEvent *)theEvent
 {
-        m_buttons |= Qt::RightButton;
+    m_buttons |= Qt::RightButton;
     [self handleMouseEvent:theEvent];
 }
+
 - (void)rightMouseDragged:(NSEvent *)theEvent
 {
-        if (!(m_buttons & Qt::LeftButton))
-            qWarning("Internal Mousebutton tracking invalid(missing Qt::LeftButton");
-        [self handleMouseEvent:theEvent];
+    if (!(m_buttons & Qt::LeftButton))
+        qWarning("Internal Mousebutton tracking invalid(missing Qt::LeftButton");
+    [self handleMouseEvent:theEvent];
 }
+
 - (void)rightMouseUp:(NSEvent *)theEvent
 {
-        m_buttons &= QFlag(~int(Qt::RightButton));
-        [self handleMouseEvent:theEvent];
+    m_buttons &= QFlag(~int(Qt::RightButton));
+    [self handleMouseEvent:theEvent];
 }
+
 - (void)otherMouseDown:(NSEvent *)theEvent
 {
-        m_buttons |= Qt::RightButton;
+    m_buttons |= Qt::RightButton;
     [self handleMouseEvent:theEvent];
 }
+
 - (void)otherMouseDragged:(NSEvent *)theEvent
 {
-        if (!(m_buttons & Qt::LeftButton))
-            qWarning("Internal Mousebutton tracking invalid(missing Qt::LeftButton");
-        [self handleMouseEvent:theEvent];
+    if (!(m_buttons & Qt::LeftButton))
+        qWarning("Internal Mousebutton tracking invalid(missing Qt::LeftButton");
+    [self handleMouseEvent:theEvent];
 }
+
 - (void)otherMouseUp:(NSEvent *)theEvent
 {
-        m_buttons &= QFlag(~int(Qt::MiddleButton));
-        [self handleMouseEvent:theEvent];
+    m_buttons &= QFlag(~int(Qt::MiddleButton));
+    [self handleMouseEvent:theEvent];
+}
+
+#ifndef QT_NO_WHEELEVENT
+- (void)scrollWheel:(NSEvent *)theEvent
+{
+    int deltaX = 0;
+    int deltaY = 0;
+    int deltaZ = 0;
+
+    const EventRef carbonEvent = (EventRef)[theEvent eventRef];
+    const UInt32 carbonEventKind = carbonEvent ? ::GetEventKind(carbonEvent) : 0;
+    const bool scrollEvent = carbonEventKind == kEventMouseScroll;
+
+    if (scrollEvent) {
+        // The mouse device containts pixel scroll wheel support (Mighty Mouse, Trackpad).
+        // Since deviceDelta is delivered as pixels rather than degrees, we need to
+        // convert from pixels to degrees in a sensible manner.
+        // It looks like 1/4 degrees per pixel behaves most native.
+        // (NB: Qt expects the unit for delta to be 8 per degree):
+        const int pixelsToDegrees = 2; // 8 * 1/4
+        deltaX = [theEvent deviceDeltaX] * pixelsToDegrees;
+        deltaY = [theEvent deviceDeltaY] * pixelsToDegrees;
+        deltaZ = [theEvent deviceDeltaZ] * pixelsToDegrees;
+    } else {
+        // carbonEventKind == kEventMouseWheelMoved
+        // Remove acceleration, and use either -120 or 120 as delta:
+        deltaX = qBound(-120, int([theEvent deltaX] * 10000), 120);
+        deltaY = qBound(-120, int([theEvent deltaY] * 10000), 120);
+        deltaZ = qBound(-120, int([theEvent deltaZ] * 10000), 120);
+    }
+
+    NSPoint windowPoint = [self convertPoint: [theEvent locationInWindow] fromView: nil];
+    QPoint qt_windowPoint(windowPoint.x, windowPoint.y);
+    NSTimeInterval timestamp = [theEvent timestamp];
+    ulong qt_timestamp = timestamp * 1000;
+
+    if (deltaX != 0)
+        QWindowSystemInterface::handleWheelEvent(m_window, qt_timestamp, qt_windowPoint, qt_windowPoint, deltaX, Qt::Horizontal);
+
+    if (deltaY != 0)
+        QWindowSystemInterface::handleWheelEvent(m_window, qt_timestamp, qt_windowPoint, qt_windowPoint, deltaY, Qt::Vertical);
+
+    if (deltaZ != 0)
+        // Qt doesn't explicitly support wheels with a Z component. In a misguided attempt to
+        // try to be ahead of the pack, I'm adding this extra value.
+        QWindowSystemInterface::handleWheelEvent(m_window, qt_timestamp, qt_windowPoint, qt_windowPoint, deltaY, (Qt::Orientation)3);
 }
+#endif //QT_NO_WHEELEVENT
 
 - (int) convertKeyCode : (QChar)keyChar
 {