tests/auto/macnativeevents/qnativeevents_mac.cpp
changeset 30 5dc02b23752f
equal deleted inserted replaced
29:b72c6db6890b 30:5dc02b23752f
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the test suite of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qnativeevents.h"
       
    43 #include <Carbon/Carbon.h>
       
    44 #include <QtCore>
       
    45 
       
    46 //  ************************************************************
       
    47 //  Quartz
       
    48 //  ************************************************************
       
    49 
       
    50 static Qt::KeyboardModifiers getModifiersFromQuartzEvent(CGEventRef inEvent)
       
    51 {
       
    52     Qt::KeyboardModifiers m;
       
    53     CGEventFlags flags = CGEventGetFlags(inEvent);
       
    54     if (flags & kCGEventFlagMaskShift || flags & kCGEventFlagMaskAlphaShift)
       
    55         m |= Qt::ShiftModifier;
       
    56     if (flags & kCGEventFlagMaskControl)
       
    57         m |= Qt::MetaModifier;
       
    58     if (flags & kCGEventFlagMaskAlternate)
       
    59         m |= Qt::AltModifier;
       
    60     if (flags & kCGEventFlagMaskCommand)
       
    61         m |= Qt::ControlModifier;
       
    62     return m;
       
    63 }
       
    64 
       
    65 static void setModifiersFromQNativeEvent(CGEventRef inEvent, const QNativeEvent &event)
       
    66 {
       
    67     CGEventFlags flags = 0;
       
    68     if (event.modifiers.testFlag(Qt::ShiftModifier))
       
    69         flags |= kCGEventFlagMaskShift;
       
    70     if (event.modifiers.testFlag(Qt::MetaModifier))
       
    71         flags |= kCGEventFlagMaskControl;
       
    72     if (event.modifiers.testFlag(Qt::AltModifier))
       
    73         flags |= kCGEventFlagMaskAlternate;
       
    74     if (event.modifiers.testFlag(Qt::ControlModifier))
       
    75         flags |= kCGEventFlagMaskCommand;
       
    76     CGEventSetFlags(inEvent, flags);
       
    77 }
       
    78 
       
    79 static QPoint getMouseLocationFromQuartzEvent(CGEventRef inEvent)
       
    80 {
       
    81     CGPoint pos = CGEventGetLocation(inEvent);
       
    82     QPoint tmp;
       
    83     tmp.setX(pos.x);
       
    84     tmp.setY(pos.y);
       
    85     return tmp;
       
    86 }
       
    87 
       
    88 static QChar getCharFromQuartzEvent(CGEventRef inEvent)
       
    89 {
       
    90     UniCharCount count = 0;
       
    91     UniChar c;
       
    92     CGEventKeyboardGetUnicodeString(inEvent, 1, &count, &c);
       
    93     return QChar(c);
       
    94 }
       
    95 
       
    96 static CGEventRef EventHandler_Quartz(CGEventTapProxy proxy, CGEventType type, CGEventRef inEvent, void *refCon)
       
    97 {
       
    98     Q_UNUSED(proxy);
       
    99     QNativeInput *nativeInput = static_cast<QNativeInput *>(refCon);
       
   100     switch (type){
       
   101         case kCGEventKeyDown:{
       
   102             QNativeKeyEvent e;
       
   103             e.modifiers = getModifiersFromQuartzEvent(inEvent);
       
   104             e.nativeKeyCode = CGEventGetIntegerValueField(inEvent, kCGKeyboardEventKeycode);
       
   105             e.character = getCharFromQuartzEvent(inEvent);
       
   106             e.press = true;
       
   107             nativeInput->notify(&e);
       
   108             break;
       
   109         }
       
   110         case kCGEventKeyUp:{
       
   111             QNativeKeyEvent e;
       
   112             e.modifiers = getModifiersFromQuartzEvent(inEvent);
       
   113             e.nativeKeyCode = CGEventGetIntegerValueField(inEvent, kCGKeyboardEventKeycode);
       
   114             e.character = getCharFromQuartzEvent(inEvent);
       
   115             e.press = false;
       
   116             nativeInput->notify(&e);
       
   117             break;
       
   118         }
       
   119         case kCGEventLeftMouseDown:{
       
   120             QNativeMouseButtonEvent e;
       
   121             e.modifiers = getModifiersFromQuartzEvent(inEvent);
       
   122             e.globalPos = getMouseLocationFromQuartzEvent(inEvent);
       
   123             e.clickCount = CGEventGetIntegerValueField(inEvent, kCGMouseEventClickState);
       
   124             e.button = Qt::LeftButton;
       
   125             nativeInput->notify(&e);
       
   126             break;
       
   127         }
       
   128         case kCGEventLeftMouseUp:{
       
   129             QNativeMouseButtonEvent e;
       
   130             e.modifiers = getModifiersFromQuartzEvent(inEvent);
       
   131             e.globalPos = getMouseLocationFromQuartzEvent(inEvent);
       
   132             e.clickCount = 0;
       
   133             e.button = Qt::LeftButton;
       
   134             nativeInput->notify(&e);
       
   135             break;
       
   136         }
       
   137         case kCGEventRightMouseDown:{
       
   138             QNativeMouseButtonEvent e;
       
   139             e.modifiers = getModifiersFromQuartzEvent(inEvent);
       
   140             e.globalPos = getMouseLocationFromQuartzEvent(inEvent);
       
   141             e.clickCount = CGEventGetIntegerValueField(inEvent, kCGMouseEventClickState);
       
   142             e.button = Qt::RightButton;
       
   143             nativeInput->notify(&e);
       
   144             break;
       
   145         }
       
   146         case kCGEventRightMouseUp:{
       
   147             QNativeMouseButtonEvent e;
       
   148             e.modifiers = getModifiersFromQuartzEvent(inEvent);
       
   149             e.globalPos = getMouseLocationFromQuartzEvent(inEvent);
       
   150             e.clickCount = 0;
       
   151             e.button = Qt::RightButton;
       
   152             nativeInput->notify(&e);
       
   153             break;
       
   154         }
       
   155         case kCGEventMouseMoved:{
       
   156             QNativeMouseMoveEvent e;
       
   157             e.modifiers = getModifiersFromQuartzEvent(inEvent);
       
   158             e.globalPos = getMouseLocationFromQuartzEvent(inEvent);
       
   159             nativeInput->notify(&e);
       
   160             break;
       
   161         }
       
   162         case kCGEventLeftMouseDragged:{
       
   163             QNativeMouseDragEvent e;
       
   164             e.modifiers = getModifiersFromQuartzEvent(inEvent);
       
   165             e.globalPos = getMouseLocationFromQuartzEvent(inEvent);
       
   166             e.clickCount = CGEventGetIntegerValueField(inEvent, kCGMouseEventClickState);
       
   167             e.button = Qt::LeftButton;
       
   168             nativeInput->notify(&e);
       
   169             break;
       
   170         }
       
   171         case kCGEventScrollWheel:{
       
   172             QNativeMouseWheelEvent e;
       
   173             e.modifiers = getModifiersFromQuartzEvent(inEvent);
       
   174             e.delta = CGEventGetIntegerValueField(inEvent, kCGScrollWheelEventDeltaAxis1);
       
   175             e.globalPos = getMouseLocationFromQuartzEvent(inEvent);
       
   176             nativeInput->notify(&e);
       
   177             break;
       
   178         }
       
   179         case kCGEventFlagsChanged:{
       
   180             QNativeModifierEvent e;
       
   181             e.modifiers = getModifiersFromQuartzEvent(inEvent);
       
   182             e.nativeKeyCode = CGEventGetIntegerValueField(inEvent, kCGKeyboardEventKeycode);
       
   183             nativeInput->notify(&e);
       
   184             break;
       
   185         }
       
   186 
       
   187     }
       
   188 
       
   189     return inEvent;
       
   190 }
       
   191 
       
   192 Qt::Native::Status insertEventHandler_Quartz(QNativeInput *nativeInput, int pid = 0)
       
   193 {
       
   194     uid_t uid = geteuid();
       
   195     if (uid != 0)
       
   196         qWarning("MacNativeEvents: You must be root to listen for key events!");
       
   197 
       
   198     CFMachPortRef port;
       
   199     if (!pid){
       
   200         port = CGEventTapCreate(kCGHIDEventTap,
       
   201             kCGHeadInsertEventTap, kCGEventTapOptionListenOnly,
       
   202             kCGEventMaskForAllEvents, EventHandler_Quartz, nativeInput);
       
   203     } else {
       
   204         ProcessSerialNumber psn;
       
   205         GetProcessForPID(pid, &psn);
       
   206         port = CGEventTapCreateForPSN(&psn,
       
   207             kCGHeadInsertEventTap, kCGEventTapOptionListenOnly,
       
   208             kCGEventMaskForAllEvents, EventHandler_Quartz, nativeInput);
       
   209     }
       
   210 
       
   211     CFRunLoopSourceRef eventSrc = CFMachPortCreateRunLoopSource(NULL, port, 0);
       
   212     CFRunLoopAddSource((CFRunLoopRef) GetCFRunLoopFromEventLoop(GetMainEventLoop()),
       
   213         eventSrc, kCFRunLoopCommonModes);
       
   214 
       
   215     return Qt::Native::Success;
       
   216 }
       
   217 
       
   218 Qt::Native::Status removeEventHandler_Quartz()
       
   219 {
       
   220     return Qt::Native::Success; // ToDo:
       
   221 }
       
   222 
       
   223 Qt::Native::Status sendNativeKeyEventToProcess_Quartz(const QNativeKeyEvent &event, int pid)
       
   224 {
       
   225     ProcessSerialNumber psn;
       
   226     GetProcessForPID(pid, &psn);
       
   227 
       
   228     CGEventRef e = CGEventCreateKeyboardEvent(0, (uint)event.nativeKeyCode, event.press);
       
   229     setModifiersFromQNativeEvent(e, event);
       
   230     SetFrontProcess(&psn);
       
   231     CGEventPostToPSN(&psn, e);
       
   232     CFRelease(e);
       
   233     return Qt::Native::Success;
       
   234 }
       
   235 
       
   236 Qt::Native::Status sendNativeKeyEvent_Quartz(const QNativeKeyEvent &event)
       
   237 {
       
   238     CGEventRef e = CGEventCreateKeyboardEvent(0, (uint)event.nativeKeyCode, event.press);
       
   239     setModifiersFromQNativeEvent(e, event);
       
   240     CGEventPost(kCGHIDEventTap, e);
       
   241     CFRelease(e);
       
   242     return Qt::Native::Success;
       
   243 }
       
   244 
       
   245 Qt::Native::Status sendNativeMouseMoveEvent_Quartz(const QNativeMouseMoveEvent &event)
       
   246 {
       
   247     CGPoint pos;
       
   248     pos.x = event.globalPos.x();
       
   249     pos.y = event.globalPos.y();
       
   250 
       
   251     CGEventRef e = CGEventCreateMouseEvent(0, kCGEventMouseMoved, pos, 0);
       
   252     setModifiersFromQNativeEvent(e, event);
       
   253     CGEventPost(kCGHIDEventTap, e);
       
   254     CFRelease(e);
       
   255     return Qt::Native::Success;
       
   256 }
       
   257 
       
   258 Qt::Native::Status sendNativeMouseButtonEvent_Quartz(const QNativeMouseButtonEvent &event)
       
   259 {
       
   260     CGPoint pos;
       
   261     pos.x = event.globalPos.x();
       
   262     pos.y = event.globalPos.y();
       
   263 
       
   264     CGEventType type = 0;
       
   265     if (event.button == Qt::LeftButton)
       
   266         type = (event.clickCount > 0) ? kCGEventLeftMouseDown : kCGEventLeftMouseUp;
       
   267     else if (event.button == Qt::RightButton)
       
   268         type = (event.clickCount > 0) ? kCGEventRightMouseDown : kCGEventRightMouseUp;
       
   269     else
       
   270         type = (event.clickCount > 0) ? kCGEventOtherMouseDown : kCGEventOtherMouseUp;
       
   271 
       
   272     CGEventRef e = CGEventCreateMouseEvent(0, type, pos, event.button);
       
   273     setModifiersFromQNativeEvent(e, event);
       
   274     CGEventSetIntegerValueField(e, kCGMouseEventClickState, event.clickCount);
       
   275     CGEventPost(kCGHIDEventTap, e);
       
   276     CFRelease(e);
       
   277     return Qt::Native::Success;
       
   278 }
       
   279 
       
   280 Qt::Native::Status sendNativeMouseDragEvent_Quartz(const QNativeMouseDragEvent &event)
       
   281 {
       
   282     CGPoint pos;
       
   283     pos.x = event.globalPos.x();
       
   284     pos.y = event.globalPos.y();
       
   285 
       
   286     CGEventType type = 0;
       
   287     if (event.button == Qt::LeftButton)
       
   288         type = kCGEventLeftMouseDragged;
       
   289     else if (event.button == Qt::RightButton)
       
   290         type = kCGEventRightMouseDragged;
       
   291     else
       
   292         type = kCGEventOtherMouseDragged;
       
   293 
       
   294     CGEventRef e = CGEventCreateMouseEvent(0, type, pos, event.button);
       
   295     setModifiersFromQNativeEvent(e, event);
       
   296     CGEventPost(kCGHIDEventTap, e);
       
   297     CFRelease(e);
       
   298     return Qt::Native::Success;
       
   299 }
       
   300 
       
   301 Qt::Native::Status sendNativeMouseWheelEvent_Quartz(const QNativeMouseWheelEvent &event)
       
   302 {
       
   303     CGPoint pos;
       
   304     pos.x = event.globalPos.x();
       
   305     pos.y = event.globalPos.y();
       
   306 
       
   307     CGEventRef e = CGEventCreateScrollWheelEvent(0, kCGScrollEventUnitPixel, 1, 0);
       
   308     CGEventSetIntegerValueField(e, kCGScrollWheelEventDeltaAxis1, event.delta);
       
   309     CGEventSetLocation(e, pos);
       
   310     setModifiersFromQNativeEvent(e, event);
       
   311     CGEventPost(kCGHIDEventTap, e);
       
   312     CFRelease(e);
       
   313 
       
   314     return Qt::Native::Success;
       
   315 }
       
   316 
       
   317 Qt::Native::Status sendNativeModifierEvent_Quartz(const QNativeModifierEvent &event)
       
   318 {
       
   319     CGEventRef e = CGEventCreateKeyboardEvent(0, (uint)event.nativeKeyCode, 0);
       
   320     CGEventSetType(e, kCGEventFlagsChanged);
       
   321     setModifiersFromQNativeEvent(e, event);
       
   322     CGEventPost(kCGHIDEventTap, e);
       
   323     CFRelease(e);
       
   324     return Qt::Native::Success;
       
   325 }
       
   326 
       
   327 //  ************************************************************
       
   328 //  QNativeInput methods:
       
   329 //  ************************************************************
       
   330 
       
   331 Qt::Native::Status QNativeInput::sendNativeMouseButtonEvent(const QNativeMouseButtonEvent &event)
       
   332 {
       
   333     return sendNativeMouseButtonEvent_Quartz(event);
       
   334 }
       
   335 
       
   336 Qt::Native::Status QNativeInput::sendNativeMouseMoveEvent(const QNativeMouseMoveEvent &event)
       
   337 {
       
   338     return sendNativeMouseMoveEvent_Quartz(event);
       
   339 }
       
   340 
       
   341 Qt::Native::Status QNativeInput::sendNativeMouseDragEvent(const QNativeMouseDragEvent &event)
       
   342 {
       
   343     return sendNativeMouseDragEvent_Quartz(event);
       
   344 }
       
   345 
       
   346 Qt::Native::Status QNativeInput::sendNativeMouseWheelEvent(const QNativeMouseWheelEvent &event)
       
   347 {
       
   348     return sendNativeMouseWheelEvent_Quartz(event);
       
   349 }
       
   350 
       
   351 Qt::Native::Status QNativeInput::sendNativeKeyEvent(const QNativeKeyEvent &event, int pid)
       
   352 {
       
   353     if (!pid)
       
   354         return sendNativeKeyEvent_Quartz(event);
       
   355     else
       
   356         return sendNativeKeyEventToProcess_Quartz(event, pid);
       
   357 }
       
   358 
       
   359 Qt::Native::Status QNativeInput::sendNativeModifierEvent(const QNativeModifierEvent &event)
       
   360 {
       
   361     return sendNativeModifierEvent_Quartz(event);
       
   362 }
       
   363 
       
   364 Qt::Native::Status QNativeInput::subscribeForNativeEvents()
       
   365 {
       
   366     return insertEventHandler_Quartz(this);
       
   367 }
       
   368 
       
   369 Qt::Native::Status QNativeInput::unsubscribeForNativeEvents()
       
   370 {
       
   371     return removeEventHandler_Quartz();
       
   372 }
       
   373 
       
   374 // Some Qt to Mac mappings:
       
   375 int QNativeKeyEvent::Key_A = 0;
       
   376 int QNativeKeyEvent::Key_B = 11;
       
   377 int QNativeKeyEvent::Key_C = 8;
       
   378 int QNativeKeyEvent::Key_1 = 18;
       
   379 int QNativeKeyEvent::Key_Backspace = 51;
       
   380 int QNativeKeyEvent::Key_Enter = 36;
       
   381 int QNativeKeyEvent::Key_Del = 117;
       
   382