5635823e17
As in the past, to avoid rewriting various autotests that contain line-number information, an extra blank line has been inserted at the end of the license text to ensure that this commit does not change the total number of lines in the license header. Change-Id: I311e001373776812699d6efc045b5f742890c689 Reviewed-by: Rohan McGovern <rohan.mcgovern@nokia.com>
383 lines
13 KiB
C++
383 lines
13 KiB
C++
/****************************************************************************
|
|
**
|
|
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
|
** Contact: http://www.qt-project.org/
|
|
**
|
|
** 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;
|
|
|