From 4d375f6e40c3b7c082eacdcd8c78b25890e9e30a Mon Sep 17 00:00:00 2001 From: Roy Mennicke Date: Sat, 7 Feb 2015 14:48:23 +0100 Subject: [PATCH] refs #379 key events handling for Macintoshs --- libraries.pri | 4 + src/blackinput/blackinput.pro | 1 + src/blackinput/osx/keyboard_mac.cpp | 53 ----- src/blackinput/osx/keyboard_mac.h | 33 +++- src/blackinput/osx/keyboard_mac.mm | 202 ++++++++++++++++++++ src/blackinput/osx/keymapping_mac.h | 33 ++++ src/blackinput/osx/keymapping_mac.mm | 62 ++++++ src/swiftgui_standard/swiftgui_standard.pro | 9 +- 8 files changed, 335 insertions(+), 62 deletions(-) delete mode 100644 src/blackinput/osx/keyboard_mac.cpp create mode 100644 src/blackinput/osx/keyboard_mac.mm create mode 100644 src/blackinput/osx/keymapping_mac.h create mode 100644 src/blackinput/osx/keymapping_mac.mm diff --git a/libraries.pri b/libraries.pri index 98f9a7970..58de4146c 100644 --- a/libraries.pri +++ b/libraries.pri @@ -24,6 +24,10 @@ blacksound { blackinput { LIBS += -lblackinput + macx { + LIBS += -framework CoreFoundation -framework ApplicationServices -framework Foundation -framework AppKit + } + win32 { LIBS += -ldxguid -lole32 -ldinput8 -lUser32 } diff --git a/src/blackinput/blackinput.pro b/src/blackinput/blackinput.pro index 6e20501f8..8fd7c1171 100644 --- a/src/blackinput/blackinput.pro +++ b/src/blackinput/blackinput.pro @@ -37,6 +37,7 @@ unix:!macx { macx { HEADERS += $$PWD/osx/*.h SOURCES += $$PWD/osx/*.cpp + OBJECTIVE_SOURCES += $$PWD/osx/*.mm } DESTDIR = ../../lib diff --git a/src/blackinput/osx/keyboard_mac.cpp b/src/blackinput/osx/keyboard_mac.cpp deleted file mode 100644 index 2851aa43d..000000000 --- a/src/blackinput/osx/keyboard_mac.cpp +++ /dev/null @@ -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 - -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); - } -} diff --git a/src/blackinput/osx/keyboard_mac.h b/src/blackinput/osx/keyboard_mac.h index 44a387f1f..71372bf29 100644 --- a/src/blackinput/osx/keyboard_mac.h +++ b/src/blackinput/osx/keyboard_mac.h @@ -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 +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 diff --git a/src/blackinput/osx/keyboard_mac.mm b/src/blackinput/osx/keyboard_mac.mm new file mode 100644 index 000000000..8b876b74e --- /dev/null +++ b/src/blackinput/osx/keyboard_mac.mm @@ -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 +#include +#include +#include +#include +#include +#include + +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 <(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(IKeyboard::getInstance()); + keyboardMac->processKeyEvent(type, event); + + // send event to next application + return event; + } +} diff --git a/src/blackinput/osx/keymapping_mac.h b/src/blackinput/osx/keymapping_mac.h new file mode 100644 index 000000000..cce74a0c0 --- /dev/null +++ b/src/blackinput/osx/keymapping_mac.h @@ -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 diff --git a/src/blackinput/osx/keymapping_mac.mm b/src/blackinput/osx/keymapping_mac.mm new file mode 100644 index 000000000..caf32d066 --- /dev/null +++ b/src/blackinput/osx/keymapping_mac.mm @@ -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 +#include + +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 diff --git a/src/swiftgui_standard/swiftgui_standard.pro b/src/swiftgui_standard/swiftgui_standard.pro index b8410b897..8eb52c65e 100644 --- a/src/swiftgui_standard/swiftgui_standard.pro +++ b/src/swiftgui_standard/swiftgui_standard.pro @@ -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