tests/auto/macnativeevents/qnativeevents_mac.cpp
changeset 30 5dc02b23752f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/auto/macnativeevents/qnativeevents_mac.cpp	Tue Jul 06 15:10:48 2010 +0300
@@ -0,0 +1,382 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qnativeevents.h"
+#include <Carbon/Carbon.h>
+#include <QtCore>
+
+//  ************************************************************
+//  Quartz
+//  ************************************************************
+
+static Qt::KeyboardModifiers getModifiersFromQuartzEvent(CGEventRef inEvent)
+{
+    Qt::KeyboardModifiers m;
+    CGEventFlags flags = CGEventGetFlags(inEvent);
+    if (flags & kCGEventFlagMaskShift || flags & kCGEventFlagMaskAlphaShift)
+        m |= Qt::ShiftModifier;
+    if (flags & kCGEventFlagMaskControl)
+        m |= Qt::MetaModifier;
+    if (flags & kCGEventFlagMaskAlternate)
+        m |= Qt::AltModifier;
+    if (flags & kCGEventFlagMaskCommand)
+        m |= Qt::ControlModifier;
+    return m;
+}
+
+static void setModifiersFromQNativeEvent(CGEventRef inEvent, const QNativeEvent &event)
+{
+    CGEventFlags flags = 0;
+    if (event.modifiers.testFlag(Qt::ShiftModifier))
+        flags |= kCGEventFlagMaskShift;
+    if (event.modifiers.testFlag(Qt::MetaModifier))
+        flags |= kCGEventFlagMaskControl;
+    if (event.modifiers.testFlag(Qt::AltModifier))
+        flags |= kCGEventFlagMaskAlternate;
+    if (event.modifiers.testFlag(Qt::ControlModifier))
+        flags |= kCGEventFlagMaskCommand;
+    CGEventSetFlags(inEvent, flags);
+}
+
+static QPoint getMouseLocationFromQuartzEvent(CGEventRef inEvent)
+{
+    CGPoint pos = CGEventGetLocation(inEvent);
+    QPoint tmp;
+    tmp.setX(pos.x);
+    tmp.setY(pos.y);
+    return tmp;
+}
+
+static QChar getCharFromQuartzEvent(CGEventRef inEvent)
+{
+    UniCharCount count = 0;
+    UniChar c;
+    CGEventKeyboardGetUnicodeString(inEvent, 1, &count, &c);
+    return QChar(c);
+}
+
+static CGEventRef EventHandler_Quartz(CGEventTapProxy proxy, CGEventType type, CGEventRef inEvent, void *refCon)
+{
+    Q_UNUSED(proxy);
+    QNativeInput *nativeInput = static_cast<QNativeInput *>(refCon);
+    switch (type){
+        case kCGEventKeyDown:{
+            QNativeKeyEvent e;
+            e.modifiers = getModifiersFromQuartzEvent(inEvent);
+            e.nativeKeyCode = CGEventGetIntegerValueField(inEvent, kCGKeyboardEventKeycode);
+            e.character = getCharFromQuartzEvent(inEvent);
+            e.press = true;
+            nativeInput->notify(&e);
+            break;
+        }
+        case kCGEventKeyUp:{
+            QNativeKeyEvent e;
+            e.modifiers = getModifiersFromQuartzEvent(inEvent);
+            e.nativeKeyCode = CGEventGetIntegerValueField(inEvent, kCGKeyboardEventKeycode);
+            e.character = getCharFromQuartzEvent(inEvent);
+            e.press = false;
+            nativeInput->notify(&e);
+            break;
+        }
+        case kCGEventLeftMouseDown:{
+            QNativeMouseButtonEvent e;
+            e.modifiers = getModifiersFromQuartzEvent(inEvent);
+            e.globalPos = getMouseLocationFromQuartzEvent(inEvent);
+            e.clickCount = CGEventGetIntegerValueField(inEvent, kCGMouseEventClickState);
+            e.button = Qt::LeftButton;
+            nativeInput->notify(&e);
+            break;
+        }
+        case kCGEventLeftMouseUp:{
+            QNativeMouseButtonEvent e;
+            e.modifiers = getModifiersFromQuartzEvent(inEvent);
+            e.globalPos = getMouseLocationFromQuartzEvent(inEvent);
+            e.clickCount = 0;
+            e.button = Qt::LeftButton;
+            nativeInput->notify(&e);
+            break;
+        }
+        case kCGEventRightMouseDown:{
+            QNativeMouseButtonEvent e;
+            e.modifiers = getModifiersFromQuartzEvent(inEvent);
+            e.globalPos = getMouseLocationFromQuartzEvent(inEvent);
+            e.clickCount = CGEventGetIntegerValueField(inEvent, kCGMouseEventClickState);
+            e.button = Qt::RightButton;
+            nativeInput->notify(&e);
+            break;
+        }
+        case kCGEventRightMouseUp:{
+            QNativeMouseButtonEvent e;
+            e.modifiers = getModifiersFromQuartzEvent(inEvent);
+            e.globalPos = getMouseLocationFromQuartzEvent(inEvent);
+            e.clickCount = 0;
+            e.button = Qt::RightButton;
+            nativeInput->notify(&e);
+            break;
+        }
+        case kCGEventMouseMoved:{
+            QNativeMouseMoveEvent e;
+            e.modifiers = getModifiersFromQuartzEvent(inEvent);
+            e.globalPos = getMouseLocationFromQuartzEvent(inEvent);
+            nativeInput->notify(&e);
+            break;
+        }
+        case kCGEventLeftMouseDragged:{
+            QNativeMouseDragEvent e;
+            e.modifiers = getModifiersFromQuartzEvent(inEvent);
+            e.globalPos = getMouseLocationFromQuartzEvent(inEvent);
+            e.clickCount = CGEventGetIntegerValueField(inEvent, kCGMouseEventClickState);
+            e.button = Qt::LeftButton;
+            nativeInput->notify(&e);
+            break;
+        }
+        case kCGEventScrollWheel:{
+            QNativeMouseWheelEvent e;
+            e.modifiers = getModifiersFromQuartzEvent(inEvent);
+            e.delta = CGEventGetIntegerValueField(inEvent, kCGScrollWheelEventDeltaAxis1);
+            e.globalPos = getMouseLocationFromQuartzEvent(inEvent);
+            nativeInput->notify(&e);
+            break;
+        }
+        case kCGEventFlagsChanged:{
+            QNativeModifierEvent e;
+            e.modifiers = getModifiersFromQuartzEvent(inEvent);
+            e.nativeKeyCode = CGEventGetIntegerValueField(inEvent, kCGKeyboardEventKeycode);
+            nativeInput->notify(&e);
+            break;
+        }
+
+    }
+
+    return inEvent;
+}
+
+Qt::Native::Status insertEventHandler_Quartz(QNativeInput *nativeInput, int pid = 0)
+{
+    uid_t uid = geteuid();
+    if (uid != 0)
+        qWarning("MacNativeEvents: You must be root to listen for key events!");
+
+    CFMachPortRef port;
+    if (!pid){
+        port = CGEventTapCreate(kCGHIDEventTap,
+            kCGHeadInsertEventTap, kCGEventTapOptionListenOnly,
+            kCGEventMaskForAllEvents, EventHandler_Quartz, nativeInput);
+    } else {
+        ProcessSerialNumber psn;
+        GetProcessForPID(pid, &psn);
+        port = CGEventTapCreateForPSN(&psn,
+            kCGHeadInsertEventTap, kCGEventTapOptionListenOnly,
+            kCGEventMaskForAllEvents, EventHandler_Quartz, nativeInput);
+    }
+
+    CFRunLoopSourceRef eventSrc = CFMachPortCreateRunLoopSource(NULL, port, 0);
+    CFRunLoopAddSource((CFRunLoopRef) GetCFRunLoopFromEventLoop(GetMainEventLoop()),
+        eventSrc, kCFRunLoopCommonModes);
+
+    return Qt::Native::Success;
+}
+
+Qt::Native::Status removeEventHandler_Quartz()
+{
+    return Qt::Native::Success; // ToDo:
+}
+
+Qt::Native::Status sendNativeKeyEventToProcess_Quartz(const QNativeKeyEvent &event, int pid)
+{
+    ProcessSerialNumber psn;
+    GetProcessForPID(pid, &psn);
+
+    CGEventRef e = CGEventCreateKeyboardEvent(0, (uint)event.nativeKeyCode, event.press);
+    setModifiersFromQNativeEvent(e, event);
+    SetFrontProcess(&psn);
+    CGEventPostToPSN(&psn, e);
+    CFRelease(e);
+    return Qt::Native::Success;
+}
+
+Qt::Native::Status sendNativeKeyEvent_Quartz(const QNativeKeyEvent &event)
+{
+    CGEventRef e = CGEventCreateKeyboardEvent(0, (uint)event.nativeKeyCode, event.press);
+    setModifiersFromQNativeEvent(e, event);
+    CGEventPost(kCGHIDEventTap, e);
+    CFRelease(e);
+    return Qt::Native::Success;
+}
+
+Qt::Native::Status sendNativeMouseMoveEvent_Quartz(const QNativeMouseMoveEvent &event)
+{
+    CGPoint pos;
+    pos.x = event.globalPos.x();
+    pos.y = event.globalPos.y();
+
+    CGEventRef e = CGEventCreateMouseEvent(0, kCGEventMouseMoved, pos, 0);
+    setModifiersFromQNativeEvent(e, event);
+    CGEventPost(kCGHIDEventTap, e);
+    CFRelease(e);
+    return Qt::Native::Success;
+}
+
+Qt::Native::Status sendNativeMouseButtonEvent_Quartz(const QNativeMouseButtonEvent &event)
+{
+    CGPoint pos;
+    pos.x = event.globalPos.x();
+    pos.y = event.globalPos.y();
+
+    CGEventType type = 0;
+    if (event.button == Qt::LeftButton)
+        type = (event.clickCount > 0) ? kCGEventLeftMouseDown : kCGEventLeftMouseUp;
+    else if (event.button == Qt::RightButton)
+        type = (event.clickCount > 0) ? kCGEventRightMouseDown : kCGEventRightMouseUp;
+    else
+        type = (event.clickCount > 0) ? kCGEventOtherMouseDown : kCGEventOtherMouseUp;
+
+    CGEventRef e = CGEventCreateMouseEvent(0, type, pos, event.button);
+    setModifiersFromQNativeEvent(e, event);
+    CGEventSetIntegerValueField(e, kCGMouseEventClickState, event.clickCount);
+    CGEventPost(kCGHIDEventTap, e);
+    CFRelease(e);
+    return Qt::Native::Success;
+}
+
+Qt::Native::Status sendNativeMouseDragEvent_Quartz(const QNativeMouseDragEvent &event)
+{
+    CGPoint pos;
+    pos.x = event.globalPos.x();
+    pos.y = event.globalPos.y();
+
+    CGEventType type = 0;
+    if (event.button == Qt::LeftButton)
+        type = kCGEventLeftMouseDragged;
+    else if (event.button == Qt::RightButton)
+        type = kCGEventRightMouseDragged;
+    else
+        type = kCGEventOtherMouseDragged;
+
+    CGEventRef e = CGEventCreateMouseEvent(0, type, pos, event.button);
+    setModifiersFromQNativeEvent(e, event);
+    CGEventPost(kCGHIDEventTap, e);
+    CFRelease(e);
+    return Qt::Native::Success;
+}
+
+Qt::Native::Status sendNativeMouseWheelEvent_Quartz(const QNativeMouseWheelEvent &event)
+{
+    CGPoint pos;
+    pos.x = event.globalPos.x();
+    pos.y = event.globalPos.y();
+
+    CGEventRef e = CGEventCreateScrollWheelEvent(0, kCGScrollEventUnitPixel, 1, 0);
+    CGEventSetIntegerValueField(e, kCGScrollWheelEventDeltaAxis1, event.delta);
+    CGEventSetLocation(e, pos);
+    setModifiersFromQNativeEvent(e, event);
+    CGEventPost(kCGHIDEventTap, e);
+    CFRelease(e);
+
+    return Qt::Native::Success;
+}
+
+Qt::Native::Status sendNativeModifierEvent_Quartz(const QNativeModifierEvent &event)
+{
+    CGEventRef e = CGEventCreateKeyboardEvent(0, (uint)event.nativeKeyCode, 0);
+    CGEventSetType(e, kCGEventFlagsChanged);
+    setModifiersFromQNativeEvent(e, event);
+    CGEventPost(kCGHIDEventTap, e);
+    CFRelease(e);
+    return Qt::Native::Success;
+}
+
+//  ************************************************************
+//  QNativeInput methods:
+//  ************************************************************
+
+Qt::Native::Status QNativeInput::sendNativeMouseButtonEvent(const QNativeMouseButtonEvent &event)
+{
+    return sendNativeMouseButtonEvent_Quartz(event);
+}
+
+Qt::Native::Status QNativeInput::sendNativeMouseMoveEvent(const QNativeMouseMoveEvent &event)
+{
+    return sendNativeMouseMoveEvent_Quartz(event);
+}
+
+Qt::Native::Status QNativeInput::sendNativeMouseDragEvent(const QNativeMouseDragEvent &event)
+{
+    return sendNativeMouseDragEvent_Quartz(event);
+}
+
+Qt::Native::Status QNativeInput::sendNativeMouseWheelEvent(const QNativeMouseWheelEvent &event)
+{
+    return sendNativeMouseWheelEvent_Quartz(event);
+}
+
+Qt::Native::Status QNativeInput::sendNativeKeyEvent(const QNativeKeyEvent &event, int pid)
+{
+    if (!pid)
+        return sendNativeKeyEvent_Quartz(event);
+    else
+        return sendNativeKeyEventToProcess_Quartz(event, pid);
+}
+
+Qt::Native::Status QNativeInput::sendNativeModifierEvent(const QNativeModifierEvent &event)
+{
+    return sendNativeModifierEvent_Quartz(event);
+}
+
+Qt::Native::Status QNativeInput::subscribeForNativeEvents()
+{
+    return insertEventHandler_Quartz(this);
+}
+
+Qt::Native::Status QNativeInput::unsubscribeForNativeEvents()
+{
+    return removeEventHandler_Quartz();
+}
+
+// Some Qt to Mac mappings:
+int QNativeKeyEvent::Key_A = 0;
+int QNativeKeyEvent::Key_B = 11;
+int QNativeKeyEvent::Key_C = 8;
+int QNativeKeyEvent::Key_1 = 18;
+int QNativeKeyEvent::Key_Backspace = 51;
+int QNativeKeyEvent::Key_Enter = 36;
+int QNativeKeyEvent::Key_Del = 117;
+