refs #379 key events handling for Macintoshs

This commit is contained in:
Roy Mennicke
2015-02-07 14:48:23 +01:00
committed by Roland Winklmeier
parent 9c75ff2db5
commit 4d375f6e40
8 changed files with 335 additions and 62 deletions

View File

@@ -24,6 +24,10 @@ blacksound {
blackinput {
LIBS += -lblackinput
macx {
LIBS += -framework CoreFoundation -framework ApplicationServices -framework Foundation -framework AppKit
}
win32 {
LIBS += -ldxguid -lole32 -ldinput8 -lUser32
}

View File

@@ -37,6 +37,7 @@ unix:!macx {
macx {
HEADERS += $$PWD/osx/*.h
SOURCES += $$PWD/osx/*.cpp
OBJECTIVE_SOURCES += $$PWD/osx/*.mm
}
DESTDIR = ../../lib

View File

@@ -1,53 +0,0 @@
/* Copyright (C) 2013 VATSIM Community / contributors
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "keyboard_mac.h"
#include <QDebug>
using namespace BlackMisc::Hardware;
namespace BlackInput
{
CKeyboardMac::CKeyboardMac(QObject *parent) :
IKeyboard(parent),
m_mode(Mode_Nominal)
{
}
CKeyboardMac::~CKeyboardMac()
{
}
bool CKeyboardMac::init()
{
return true;
}
void CKeyboardMac::setKeysToMonitor(const CKeyboardKeyList &keylist)
{
m_listMonitoredKeys = keylist;
}
void CKeyboardMac::startCapture(bool ignoreNextKey)
{
m_mode = Mode_Capture;
m_ignoreNextKey = ignoreNextKey;
m_pressedKey.setKeyObject(CKeyboardKey());
}
void CKeyboardMac::triggerKey(const CKeyboardKey &key, bool isPressed)
{
if(!isPressed) emit keyUp(key);
else emit keyDown(key);
}
void CKeyboardMac::sendCaptureNotification(const CKeyboardKey &key, bool isFinished)
{
if (isFinished)
emit keySelectionFinished(key);
else
emit keySelectionChanged(key);
}
}

View File

@@ -1,11 +1,13 @@
/* Copyright (C) 2013 VATSIM Community / contributors
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Copyright (C) 2015
* swift project Community / Contributors
*
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
* including this file, may be copied, modified, propagated, or distributed except according to the terms
* contained in the LICENSE file.
*/
/*!
\file
*/
//! \file
#ifndef BLACKINPUT_KEYBOARD_MAC_H
#define BLACKINPUT_KEYBOARD_MAC_H
@@ -14,9 +16,17 @@
#include "blackmisc/hardware/keyboardkeylist.h"
#include <QHash>
class __CGEvent;
typedef __CGEvent* CGEventRef;
typedef unsigned int CGEventType;
class __CGEventTapProxy;
typedef __CGEventTapProxy* CGEventTapProxy;
namespace BlackInput
{
//! \brief Linux implemenation of IKeyboard using hook procedure
//! \brief Mac OSX implemenation of IKeyboard using hook procedure
//! \todo Change QHash to a CCollection object
class CKeyboardMac : public IKeyboard
{
@@ -42,6 +52,8 @@ namespace BlackInput
//! \copydoc IKeyboard::triggerKey()
virtual void triggerKey(const BlackMisc::Hardware::CKeyboardKey &key, bool isPressed) override;
virtual void processKeyEvent(CGEventType type, CGEventRef event);
protected:
//! \copydoc IKeyboard::init()
@@ -61,6 +73,11 @@ namespace BlackInput
*/
void sendCaptureNotification(const BlackMisc::Hardware::CKeyboardKey &key, bool isFinished);
static CGEventRef myCGEventCallback(CGEventTapProxy proxy,
CGEventType type,
CGEventRef event,
void *refcon);
BlackMisc::Hardware::CKeyboardKeyList m_listMonitoredKeys; //!< Registered keys
BlackMisc::Hardware::CKeyboardKey m_pressedKey; //!< Set of virtual keys pressed in the last cycle
bool m_ignoreNextKey; //!< Is true if the next key needs to be ignored

View File

@@ -0,0 +1,202 @@
/* Copyright (C) 2015
* swift project Community / Contributors
*
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
* including this file, may be copied, modified, propagated, or distributed except according to the terms
* contained in the LICENSE file.
*/
#include "keyboard_mac.h"
#include "keymapping_mac.h"
#include <QDebug>
#include <QtWidgets/QMessageBox>
#include <CoreFoundation/CoreFoundation.h>
#include <ApplicationServices/ApplicationServices.h>
#include <AppKit/NSEvent.h>
#include <AppKit/NSAlert.h>
#include <Foundation/NSString.h>
using namespace BlackMisc::Hardware;
namespace BlackInput
{
CKeyboardMac::CKeyboardMac(QObject *parent) :
IKeyboard(parent),
m_mode(Mode_Nominal)
{
}
CKeyboardMac::~CKeyboardMac()
{
}
bool CKeyboardMac::init()
{
bool accessibilityEnabled = false;
if (AXIsProcessTrustedWithOptions != NULL) {
// 10.9 and later
const void * keys[] = { kAXTrustedCheckOptionPrompt };
const void * values[] = { kCFBooleanTrue };
CFDictionaryRef options = CFDictionaryCreate(
kCFAllocatorDefault,
keys,
values,
sizeof(keys) / sizeof(*keys),
&kCFCopyStringDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
accessibilityEnabled = AXIsProcessTrustedWithOptions(options);
}
else {
// 10.8 and older
accessibilityEnabled = AXAPIEnabled();
}
if (!accessibilityEnabled) {
QMessageBox msgBox;
msgBox.setText("In order to enable hotkeys first add Swift to the list of apps allowed to "
"control your computer in System Preferences / Security & Privacy / Privacy / Accessiblity and then restart Swift.");
msgBox.exec();
return false;
}
CGEventMask eventMask = ((1 << kCGEventKeyDown) | (1 << kCGEventKeyUp) | (1 <<kCGEventFlagsChanged));
// try creating an event tap just for keypresses. if it fails, we need Universal Access.
CFMachPortRef eventTap = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap, 0,
eventMask, myCGEventCallback, NULL);
CFRunLoopSourceRef source = CFMachPortCreateRunLoopSource(kCFAllocatorDefault,
eventTap, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopCommonModes);
CGEventTapEnable(eventTap, true);
return true;
}
void CKeyboardMac::setKeysToMonitor(const CKeyboardKeyList &keylist)
{
m_listMonitoredKeys = keylist;
}
void CKeyboardMac::startCapture(bool ignoreNextKey)
{
m_mode = Mode_Capture;
m_ignoreNextKey = ignoreNextKey;
m_pressedKey.setKeyObject(CKeyboardKey());
}
void CKeyboardMac::triggerKey(const CKeyboardKey &key, bool isPressed)
{
if(!isPressed) emit keyUp(key);
else emit keyDown(key);
}
void CKeyboardMac::processKeyEvent(CGEventType type,
CGEventRef event)
{
BlackMisc::Hardware::CKeyboardKey lastPressedKey = m_pressedKey;
if (m_ignoreNextKey)
{
m_ignoreNextKey = false;
return;
}
unsigned int vkcode = static_cast<unsigned int>(CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode));
bool isFinished = false;
if (type == kCGEventKeyDown) {
m_pressedKey.setKey(CKeyMappingMac::convertToKey(vkcode));
} else if (type == kCGEventKeyUp) {
m_pressedKey.setKey(Qt::Key_unknown);
isFinished = true;
} else if (type == kCGEventFlagsChanged) {
// m_pressedKey.removeAllModifiers();
CGEventFlags f = CGEventGetFlags(event);
qDebug() << "hier";
if ((f & kCGEventFlagMaskShift) == kCGEventFlagMaskShift) {
qDebug() << "shift";
if (vkcode == 56) {
m_pressedKey.addModifier(CKeyboardKey::ModifierShiftLeft);
} else if (vkcode == 60) {
m_pressedKey.addModifier(CKeyboardKey::ModifierShiftRight);
}
} else {
m_pressedKey.removeModifier(CKeyboardKey::ModifierShiftLeft);
m_pressedKey.removeModifier(CKeyboardKey::ModifierShiftRight);
}
if ((f & kCGEventFlagMaskControl) == kCGEventFlagMaskControl) {
qDebug() << "ctrl";
// at least on the mac wireless keyboard there is no right ctrl key
if (vkcode == 59) {
m_pressedKey.addModifier(CKeyboardKey::ModifierCtrlLeft);
}
} else {
m_pressedKey.removeModifier(CKeyboardKey::ModifierCtrlLeft);
}
if ((f & kCGEventFlagMaskAlternate) == kCGEventFlagMaskAlternate) {
qDebug() << "alt";
if (vkcode == 58) {
m_pressedKey.addModifier(CKeyboardKey::ModifierAltLeft);
} else if (vkcode == 61) {
m_pressedKey.addModifier(CKeyboardKey::ModifierAltRight);
}
} else {
m_pressedKey.removeModifier(CKeyboardKey::ModifierAltLeft);
m_pressedKey.removeModifier(CKeyboardKey::ModifierAltRight);
}
}
if (lastPressedKey == m_pressedKey)
return;
if (m_mode == Mode_Capture)
{
if (isFinished)
{
sendCaptureNotification(lastPressedKey, true);
m_mode = Mode_Nominal;
}
else
{
sendCaptureNotification(m_pressedKey, false);
}
}
else
{
if (m_listMonitoredKeys.contains(lastPressedKey)) emit keyUp(lastPressedKey);
if (m_listMonitoredKeys.contains(m_pressedKey)) emit keyDown(m_pressedKey);
}
}
void CKeyboardMac::sendCaptureNotification(const CKeyboardKey &key, bool isFinished)
{
if (isFinished)
emit keySelectionFinished(key);
else
emit keySelectionChanged(key);
}
CGEventRef CKeyboardMac::myCGEventCallback(CGEventTapProxy,
CGEventType type,
CGEventRef event,
void *)
{
CKeyboardMac *keyboardMac = qobject_cast<CKeyboardMac*>(IKeyboard::getInstance());
keyboardMac->processKeyEvent(type, event);
// send event to next application
return event;
}
}

View File

@@ -0,0 +1,33 @@
/* Copyright (C) 2015
* swift project Community / Contributors
*
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
* including this file, may be copied, modified, propagated, or distributed except according to the terms
* contained in the LICENSE file.
*/
//! \file
#ifndef BLACKINPUT_KEYMAPPING_MAC_H
#define BLACKINPUT_KEYMAPPING_MAC_H
#include "blackmisc/hwkeyboardkey.h"
namespace BlackInput
{
//! \brief This class provides methods to map between Mac OS X virtual keys and CKeyboardKey
class CKeyMappingMac
{
public:
/*!
* \brief Convert to Qt key
* \param virtualKey
* \return
*/
static Qt::Key convertToKey(unsigned int virtualKey);
};
} // namespace BlackInput
#endif // KEYMAPPING_MAC_H

View File

@@ -0,0 +1,62 @@
/* Copyright (C) 2015
* swift project Community / Contributors
*
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
* including this file, may be copied, modified, propagated, or distributed except according to the terms
* contained in the LICENSE file.
*/
#include "keymapping_mac.h"
#include <QDebug>
#include <Carbon/Carbon.h>
using namespace BlackMisc::Hardware;
namespace BlackInput
{
Qt::Key CKeyMappingMac::convertToKey(unsigned int virtualKey)
{
switch (virtualKey)
{
case kVK_ANSI_0: return Qt::Key_0;
case kVK_ANSI_1: return Qt::Key_1;
case kVK_ANSI_2: return Qt::Key_2;
case kVK_ANSI_3: return Qt::Key_3;
case kVK_ANSI_4: return Qt::Key_4;
case kVK_ANSI_5: return Qt::Key_5;
case kVK_ANSI_6: return Qt::Key_6;
case kVK_ANSI_7: return Qt::Key_7;
case kVK_ANSI_8: return Qt::Key_8;
case kVK_ANSI_9: return Qt::Key_9;
case kVK_ANSI_A: return Qt::Key_A;
case kVK_ANSI_B: return Qt::Key_B;
case kVK_ANSI_C: return Qt::Key_C;
case kVK_ANSI_D: return Qt::Key_D;
case kVK_ANSI_E: return Qt::Key_E;
case kVK_ANSI_F: return Qt::Key_F;
case kVK_ANSI_G: return Qt::Key_G;
case kVK_ANSI_H: return Qt::Key_H;
case kVK_ANSI_I: return Qt::Key_I;
case kVK_ANSI_J: return Qt::Key_J;
case kVK_ANSI_K: return Qt::Key_K;
case kVK_ANSI_L: return Qt::Key_L;
case kVK_ANSI_M: return Qt::Key_M;
case kVK_ANSI_N: return Qt::Key_N;
case kVK_ANSI_O: return Qt::Key_O;
case kVK_ANSI_P: return Qt::Key_P;
case kVK_ANSI_Q: return Qt::Key_Q;
case kVK_ANSI_R: return Qt::Key_R;
case kVK_ANSI_S: return Qt::Key_S;
case kVK_ANSI_T: return Qt::Key_T;
case kVK_ANSI_U: return Qt::Key_U;
case kVK_ANSI_V: return Qt::Key_V;
case kVK_ANSI_W: return Qt::Key_W;
case kVK_ANSI_X: return Qt::Key_X;
case kVK_ANSI_Y: return Qt::Key_Y;
case kVK_ANSI_Z: return Qt::Key_Z;
default: return Qt::Key_unknown;
}
}
} // namespace BlackInput

View File

@@ -11,7 +11,14 @@ SOURCES += *.cpp
HEADERS += *.h
FORMS += *.ui
CONFIG += blackmisc blacksound blackinput blackcore blackgui
CONFIG -= app_bundle
macx {
CONFIG += app_bundle
deployment.files = ../blackgui/qss
deployment.path = Contents/MacOS
QMAKE_BUNDLE_DATA += deployment
}
DEPENDPATH += . ../../src/blackmisc ../../src/blackgui ../../src/blacksound ../../src/blackcore ../../src/blackinput
INCLUDEPATH += . ../../src