mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-03-23 07:15:35 +08:00
refs #379 key events handling for Macintoshs
This commit is contained in:
committed by
Roland Winklmeier
parent
9c75ff2db5
commit
4d375f6e40
@@ -24,6 +24,10 @@ blacksound {
|
||||
blackinput {
|
||||
LIBS += -lblackinput
|
||||
|
||||
macx {
|
||||
LIBS += -framework CoreFoundation -framework ApplicationServices -framework Foundation -framework AppKit
|
||||
}
|
||||
|
||||
win32 {
|
||||
LIBS += -ldxguid -lole32 -ldinput8 -lUser32
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ unix:!macx {
|
||||
macx {
|
||||
HEADERS += $$PWD/osx/*.h
|
||||
SOURCES += $$PWD/osx/*.cpp
|
||||
OBJECTIVE_SOURCES += $$PWD/osx/*.mm
|
||||
}
|
||||
|
||||
DESTDIR = ../../lib
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
202
src/blackinput/osx/keyboard_mac.mm
Normal file
202
src/blackinput/osx/keyboard_mac.mm
Normal 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;
|
||||
}
|
||||
}
|
||||
33
src/blackinput/osx/keymapping_mac.h
Normal file
33
src/blackinput/osx/keymapping_mac.h
Normal 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
|
||||
62
src/blackinput/osx/keymapping_mac.mm
Normal file
62
src/blackinput/osx/keymapping_mac.mm
Normal 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
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user