summaryrefslogtreecommitdiffstats
path: root/tests/auto/integrationtests/macnativeevents/qnativeevents_mac.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/integrationtests/macnativeevents/qnativeevents_mac.cpp')
-rw-r--r--tests/auto/integrationtests/macnativeevents/qnativeevents_mac.cpp382
1 files changed, 382 insertions, 0 deletions
diff --git a/tests/auto/integrationtests/macnativeevents/qnativeevents_mac.cpp b/tests/auto/integrationtests/macnativeevents/qnativeevents_mac.cpp
new file mode 100644
index 0000000000..8987a8d502
--- /dev/null
+++ b/tests/auto/integrationtests/macnativeevents/qnativeevents_mac.cpp
@@ -0,0 +1,382 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $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::ControlModifier;
+ if (flags & kCGEventFlagMaskAlternate)
+ m |= Qt::AltModifier;
+ if (flags & kCGEventFlagMaskCommand)
+ m |= Qt::MetaModifier;
+ 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::ControlModifier))
+ flags |= kCGEventFlagMaskControl;
+ if (event.modifiers.testFlag(Qt::AltModifier))
+ flags |= kCGEventFlagMaskAlternate;
+ if (event.modifiers.testFlag(Qt::MetaModifier))
+ 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;
+