/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Digia. For licensing terms and ** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/contact-us. ** ** 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, Digia gives you certain additional ** rights. These rights are described in the Digia 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. ** ** ** $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;