/**************************************************************************** ** ** Copyright (C) 2012 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 #include // ************************************************************ // 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(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;