Code cleanup in qxtglobalshortcut

This commit is contained in:
Jonas Kvinge
2018-11-27 19:14:35 +01:00
parent 77e5d0288f
commit 3b93963688
9 changed files with 690 additions and 818 deletions

View File

@@ -1,6 +1,13 @@
cmake_minimum_required(VERSION 2.8.11) cmake_minimum_required(VERSION 2.8.11)
set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD 11)
if (UNIX AND NOT APPLE)
find_package(X11)
if (X11_FOUND)
include_directories(${X11_INCLUDE_DIR})
endif(X11_FOUND)
endif(NOT APPLE)
include_directories(${Qt5Gui_PRIVATE_INCLUDE_DIRS}) include_directories(${Qt5Gui_PRIVATE_INCLUDE_DIRS})
if (NOT WIN32 AND NOT APPLE) if (NOT WIN32 AND NOT APPLE)
find_path(HAVE_QPA_QPLATFORMNATIVEINTERFACE_H qpa/qplatformnativeinterface.h PATHS ${Qt5Gui_PRIVATE_INCLUDE_DIRS}) find_path(HAVE_QPA_QPLATFORMNATIVEINTERFACE_H qpa/qplatformnativeinterface.h PATHS ${Qt5Gui_PRIVATE_INCLUDE_DIRS})
@@ -9,25 +16,16 @@ if (NOT WIN32 AND NOT APPLE)
endif(NOT HAVE_QPA_QPLATFORMNATIVEINTERFACE_H) endif(NOT HAVE_QPA_QPLATFORMNATIVEINTERFACE_H)
endif(NOT WIN32 AND NOT APPLE) endif(NOT WIN32 AND NOT APPLE)
set(QXT-SOURCES set(QXT-SOURCES qxtglobal.cpp qxtglobalshortcut.cpp)
qxtglobal.cpp set(QXT-MOC-HEADERS qxtglobalshortcut.h )
qxtglobalshortcut.cpp
)
set(QXT-MOC-HEADERS if(X11_FOUND)
qxtglobalshortcut.h set(QXT-SOURCES ${QXT-SOURCES} qxtglobalshortcut_x11.cpp)
)
find_package(X11)
include_directories(${X11_INCLUDE_DIR})
if(WIN32)
set(QXT-SOURCES ${QXT-SOURCES} qxtglobalshortcut_win.cpp)
elseif(APPLE) elseif(APPLE)
set(QXT-SOURCES ${QXT-SOURCES} qxtglobalshortcut_mac.cpp) set(QXT-SOURCES ${QXT-SOURCES} qxtglobalshortcut_mac.cpp)
else(WIN32) elseif(WIN32)
set(QXT-SOURCES ${QXT-SOURCES} qxtglobalshortcut_x11.cpp) set(QXT-SOURCES ${QXT-SOURCES} qxtglobalshortcut_win.cpp)
endif(WIN32) endif()
QT5_WRAP_CPP(QXT-SOURCES-MOC ${QXT-MOC-HEADERS}) QT5_WRAP_CPP(QXT-SOURCES-MOC ${QXT-MOC-HEADERS})
@@ -36,8 +34,8 @@ ADD_LIBRARY(qxt STATIC
${QXT-SOURCES-MOC} ${QXT-SOURCES-MOC}
) )
if(WIN32) target_link_libraries(qxt Qt5::Core Qt5::Widgets)
target_link_libraries(qxt Qt5::Core Qt5::Widgets)
else(WIN32) if(X11_FOUND)
target_link_libraries(qxt Qt5::Core Qt5::Widgets Qt5::X11Extras) target_link_libraries(qxt Qt5::X11Extras)
endif(WIN32) endif(X11_FOUND)

View File

@@ -1,4 +1,3 @@
/**************************************************************************** /****************************************************************************
** Copyright (c) 2006 - 2011, the LibQxt project. ** Copyright (c) 2006 - 2011, the LibQxt project.
** See the Qxt AUTHORS file for a list of authors and copyright holders. ** See the Qxt AUTHORS file for a list of authors and copyright holders.

View File

@@ -1,4 +1,3 @@
/**************************************************************************** /****************************************************************************
** Copyright (c) 2006 - 2011, the LibQxt project. ** Copyright (c) 2006 - 2011, the LibQxt project.
** See the Qxt AUTHORS file for a list of authors and copyright holders. ** See the Qxt AUTHORS file for a list of authors and copyright holders.
@@ -161,73 +160,73 @@ template <typename PUB>
class QxtPrivate class QxtPrivate
{ {
public: public:
virtual ~QxtPrivate() virtual ~QxtPrivate()
{} {}
inline void QXT_setPublic(PUB* pub) inline void QXT_setPublic(PUB* pub)
{ {
qxt_p_ptr = pub; qxt_p_ptr = pub;
} }
protected: protected:
inline PUB& qxt_p() inline PUB& qxt_p()
{ {
return *qxt_p_ptr; return *qxt_p_ptr;
} }
inline const PUB& qxt_p() const inline const PUB& qxt_p() const
{ {
return *qxt_p_ptr; return *qxt_p_ptr;
} }
inline PUB* qxt_ptr() inline PUB* qxt_ptr()
{ {
return qxt_p_ptr; return qxt_p_ptr;
} }
inline const PUB* qxt_ptr() const inline const PUB* qxt_ptr() const
{ {
return qxt_p_ptr; return qxt_p_ptr;
} }
private: private:
PUB* qxt_p_ptr; PUB* qxt_p_ptr;
}; };
template <typename PUB, typename PVT> template <typename PUB, typename PVT>
class QxtPrivateInterface class QxtPrivateInterface
{ {
friend class QxtPrivate<PUB>; friend class QxtPrivate<PUB>;
public: public:
QxtPrivateInterface() QxtPrivateInterface()
{ {
pvt = new PVT; pvt = new PVT;
} }
~QxtPrivateInterface() ~QxtPrivateInterface()
{ {
delete pvt; delete pvt;
} }
inline void setPublic(PUB* pub) inline void setPublic(PUB* pub)
{ {
pvt->QXT_setPublic(pub); pvt->QXT_setPublic(pub);
} }
inline PVT& operator()() inline PVT& operator()()
{ {
return *static_cast<PVT*>(pvt); return *static_cast<PVT*>(pvt);
} }
inline const PVT& operator()() const inline const PVT& operator()() const
{ {
return *static_cast<PVT*>(pvt); return *static_cast<PVT*>(pvt);
} }
inline PVT * operator->() inline PVT * operator->()
{ {
return static_cast<PVT*>(pvt); return static_cast<PVT*>(pvt);
} }
inline const PVT * operator->() const inline const PVT * operator->() const
{ {
return static_cast<PVT*>(pvt); return static_cast<PVT*>(pvt);
} }
private: private:
QxtPrivateInterface(const QxtPrivateInterface&) { } QxtPrivateInterface(const QxtPrivateInterface&) { }
QxtPrivateInterface& operator=(const QxtPrivateInterface&) { } QxtPrivateInterface& operator=(const QxtPrivateInterface&) { }
QxtPrivate<PUB>* pvt; QxtPrivate<PUB>* pvt;
}; };
#endif // QXT_GLOBAL #endif // QXT_GLOBAL

View File

@@ -38,185 +38,160 @@
#include "qxtglobalshortcut_p.h" #include "qxtglobalshortcut_p.h"
bool QxtGlobalShortcutPrivate::error = false; bool QxtGlobalShortcutPrivate::error = false;
#ifndef Q_OS_MAC #ifndef Q_OS_MACOS
int QxtGlobalShortcutPrivate::ref = 0; int QxtGlobalShortcutPrivate::ref = 0;
#if QT_VERSION < QT_VERSION_CHECK(5,0,0) #endif // Q_OS_MACOS
QAbstractEventDispatcher::EventFilter QxtGlobalShortcutPrivate::prevEventFilter = 0;
#endif
#endif // Q_OS_MAC
QHash<QPair<quint32, quint32>, QxtGlobalShortcut*> QxtGlobalShortcutPrivate::shortcuts; QHash<QPair<quint32, quint32>, QxtGlobalShortcut*> QxtGlobalShortcutPrivate::shortcuts;
QxtGlobalShortcutPrivate::QxtGlobalShortcutPrivate() : enabled(true), key(Qt::Key(0)), mods(Qt::NoModifier) QxtGlobalShortcutPrivate::QxtGlobalShortcutPrivate() : enabled(true), key(Qt::Key(0)), mods(Qt::NoModifier) {
{ #ifndef Q_OS_MACOS
#ifndef Q_OS_MAC if (!ref++)
if (!ref++)
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
prevEventFilter = QAbstractEventDispatcher::instance()->setEventFilter(eventFilter);
#else
QAbstractEventDispatcher::instance()->installNativeEventFilter(this); QAbstractEventDispatcher::instance()->installNativeEventFilter(this);
#endif #endif // Q_OS_MACOS
#endif // Q_OS_MAC
} }
QxtGlobalShortcutPrivate::~QxtGlobalShortcutPrivate() QxtGlobalShortcutPrivate::~QxtGlobalShortcutPrivate() {
{ #ifndef Q_OS_MACOS
#ifndef Q_OS_MAC if (!--ref)
if (!--ref) QAbstractEventDispatcher::instance()->removeNativeEventFilter(this);
#if QT_VERSION < QT_VERSION_CHECK(5,0,0) #endif // Q_OS_MACOS
QAbstractEventDispatcher::instance()->setEventFilter(prevEventFilter);
#else
QAbstractEventDispatcher::instance()->removeNativeEventFilter(this);
#endif
#endif // Q_OS_MAC
} }
bool QxtGlobalShortcutPrivate::setShortcut(const QKeySequence& shortcut) bool QxtGlobalShortcutPrivate::setShortcut(const QKeySequence& shortcut) {
{
Qt::KeyboardModifiers allMods = Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier; Qt::KeyboardModifiers allMods = Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier;
key = shortcut.isEmpty() ? Qt::Key(0) : Qt::Key((shortcut[0] ^ allMods) & shortcut[0]); key = shortcut.isEmpty() ? Qt::Key(0) : Qt::Key((shortcut[0] ^ allMods) & shortcut[0]);
mods = shortcut.isEmpty() ? Qt::KeyboardModifiers(0) : Qt::KeyboardModifiers(shortcut[0] & allMods); mods = shortcut.isEmpty() ? Qt::KeyboardModifiers(0) : Qt::KeyboardModifiers(shortcut[0] & allMods);
const quint32 nativeKey = nativeKeycode(key); const quint32 nativeKey = nativeKeycode(key);
const quint32 nativeMods = nativeModifiers(mods); const quint32 nativeMods = nativeModifiers(mods);
const bool res = registerShortcut(nativeKey, nativeMods); const bool res = registerShortcut(nativeKey, nativeMods);
if (res) if (res)
shortcuts.insert(qMakePair(nativeKey, nativeMods), &qxt_p()); shortcuts.insert(qMakePair(nativeKey, nativeMods), &qxt_p());
else else
qWarning() << "QxtGlobalShortcut failed to register:" << QKeySequence(key + mods).toString(); qWarning() << "QxtGlobalShortcut failed to register:" << QKeySequence(key + mods).toString();
return res; return res;
} }
bool QxtGlobalShortcutPrivate::unsetShortcut() bool QxtGlobalShortcutPrivate::unsetShortcut() {
{ bool res = false;
bool res = false; const quint32 nativeKey = nativeKeycode(key);
const quint32 nativeKey = nativeKeycode(key); const quint32 nativeMods = nativeModifiers(mods);
const quint32 nativeMods = nativeModifiers(mods); if (shortcuts.value(qMakePair(nativeKey, nativeMods)) == &qxt_p())
if (shortcuts.value(qMakePair(nativeKey, nativeMods)) == &qxt_p()) res = unregisterShortcut(nativeKey, nativeMods);
res = unregisterShortcut(nativeKey, nativeMods); if (res)
if (res) shortcuts.remove(qMakePair(nativeKey, nativeMods));
shortcuts.remove(qMakePair(nativeKey, nativeMods)); else
else qWarning() << "QxtGlobalShortcut failed to unregister:" << QKeySequence(key + mods).toString();
qWarning() << "QxtGlobalShortcut failed to unregister:" << QKeySequence(key + mods).toString(); key = Qt::Key(0);
key = Qt::Key(0); mods = Qt::KeyboardModifiers(0);
mods = Qt::KeyboardModifiers(0); return res;
return res;
} }
void QxtGlobalShortcutPrivate::activateShortcut(quint32 nativeKey, quint32 nativeMods) void QxtGlobalShortcutPrivate::activateShortcut(quint32 nativeKey, quint32 nativeMods) {
{ QxtGlobalShortcut* shortcut = shortcuts.value(qMakePair(nativeKey, nativeMods));
QxtGlobalShortcut* shortcut = shortcuts.value(qMakePair(nativeKey, nativeMods)); if (shortcut && shortcut->isEnabled())
if (shortcut && shortcut->isEnabled()) emit shortcut->activated();
emit shortcut->activated();
} }
/*! /*!
\class QxtGlobalShortcut \class QxtGlobalShortcut
\inmodule QxtWidgets \inmodule QxtWidgets
\brief The QxtGlobalShortcut class provides a global shortcut aka "hotkey". \brief The QxtGlobalShortcut class provides a global shortcut aka "hotkey".
A global shortcut triggers even if the application is not active. This A global shortcut triggers even if the application is not active. This
makes it easy to implement applications that react to certain shortcuts makes it easy to implement applications that react to certain shortcuts
still if some other application is active or if the application is for still if some other application is active or if the application is for
example minimized to the system tray. example minimized to the system tray.
Example usage: Example usage:
\code \code
QxtGlobalShortcut* shortcut = new QxtGlobalShortcut(window); QxtGlobalShortcut* shortcut = new QxtGlobalShortcut(window);
connect(shortcut, SIGNAL(activated()), window, SLOT(toggleVisibility())); connect(shortcut, SIGNAL(activated()), window, SLOT(toggleVisibility()));
shortcut->setShortcut(QKeySequence("Ctrl+Shift+F12")); shortcut->setShortcut(QKeySequence("Ctrl+Shift+F12"));
\endcode \endcode
\bold {Note:} Since Qxt 0.6 QxtGlobalShortcut no more requires QxtApplication. \bold {Note:} Since Qxt 0.6 QxtGlobalShortcut no more requires QxtApplication.
*/ */
/*! /*!
\fn QxtGlobalShortcut::activated() \fn QxtGlobalShortcut::activated()
This signal is emitted when the user types the shortcut's key sequence. This signal is emitted when the user types the shortcut's key sequence.
\sa shortcut \sa shortcut
*/ */
/*! /*!
Constructs a new QxtGlobalShortcut with \a parent. Constructs a new QxtGlobalShortcut with \a parent.
*/ */
QxtGlobalShortcut::QxtGlobalShortcut(QObject* parent) QxtGlobalShortcut::QxtGlobalShortcut(QObject* parent) : QObject(parent) {
: QObject(parent) QXT_INIT_PRIVATE(QxtGlobalShortcut);
{
QXT_INIT_PRIVATE(QxtGlobalShortcut);
} }
/*! /*!
Constructs a new QxtGlobalShortcut with \a shortcut and \a parent. Constructs a new QxtGlobalShortcut with \a shortcut and \a parent.
*/ */
QxtGlobalShortcut::QxtGlobalShortcut(const QKeySequence& shortcut, QObject* parent) QxtGlobalShortcut::QxtGlobalShortcut(const QKeySequence& shortcut, QObject* parent) : QObject(parent) {
: QObject(parent) QXT_INIT_PRIVATE(QxtGlobalShortcut);
{ setShortcut(shortcut);
QXT_INIT_PRIVATE(QxtGlobalShortcut);
setShortcut(shortcut);
} }
/*! /*!
Destructs the QxtGlobalShortcut. Destructs the QxtGlobalShortcut.
*/ */
QxtGlobalShortcut::~QxtGlobalShortcut() QxtGlobalShortcut::~QxtGlobalShortcut() {
{ if (qxt_d().key != 0) qxt_d().unsetShortcut();
if (qxt_d().key != 0)
qxt_d().unsetShortcut();
} }
/*! /*!
\property QxtGlobalShortcut::shortcut \property QxtGlobalShortcut::shortcut
\brief the shortcut key sequence \brief the shortcut key sequence
\bold {Note:} Notice that corresponding key press and release events are not \bold {Note:} Notice that corresponding key press and release events are not
delivered for registered global shortcuts even if they are disabled. delivered for registered global shortcuts even if they are disabled.
Also, comma separated key sequences are not supported. Also, comma separated key sequences are not supported.
Only the first part is used: Only the first part is used:
\code \code
qxtShortcut->setShortcut(QKeySequence("Ctrl+Alt+A,Ctrl+Alt+B")); qxtShortcut->setShortcut(QKeySequence("Ctrl+Alt+A,Ctrl+Alt+B"));
Q_ASSERT(qxtShortcut->shortcut() == QKeySequence("Ctrl+Alt+A")); Q_ASSERT(qxtShortcut->shortcut() == QKeySequence("Ctrl+Alt+A"));
\endcode \endcode
*/ */
QKeySequence QxtGlobalShortcut::shortcut() const QKeySequence QxtGlobalShortcut::shortcut() const {
{ return QKeySequence(qxt_d().key | qxt_d().mods);
return QKeySequence(qxt_d().key | qxt_d().mods);
} }
bool QxtGlobalShortcut::setShortcut(const QKeySequence& shortcut) bool QxtGlobalShortcut::setShortcut(const QKeySequence& shortcut) {
{ if (qxt_d().key != 0)
if (qxt_d().key != 0) qxt_d().unsetShortcut();
qxt_d().unsetShortcut(); return qxt_d().setShortcut(shortcut);
return qxt_d().setShortcut(shortcut);
} }
/*! /*!
\property QxtGlobalShortcut::enabled \property QxtGlobalShortcut::enabled
\brief whether the shortcut is enabled \brief whether the shortcut is enabled
A disabled shortcut does not get activated. A disabled shortcut does not get activated.
The default value is \c true. The default value is \c true.
\sa setDisabled() \sa setDisabled()
*/ */
bool QxtGlobalShortcut::isEnabled() const bool QxtGlobalShortcut::isEnabled() const {
{ return qxt_d().enabled;
return qxt_d().enabled;
} }
void QxtGlobalShortcut::setEnabled(bool enabled) void QxtGlobalShortcut::setEnabled(bool enabled) {
{ qxt_d().enabled = enabled;
qxt_d().enabled = enabled;
} }
/*! /*!
Sets the shortcut \a disabled. Sets the shortcut \a disabled.
\sa enabled \sa enabled
*/ */
void QxtGlobalShortcut::setDisabled(bool disabled) void QxtGlobalShortcut::setDisabled(bool disabled) {
{ qxt_d().enabled = !disabled;
qxt_d().enabled = !disabled;
} }

View File

@@ -1,4 +1,3 @@
#ifndef QXTGLOBALSHORTCUT_H
/**************************************************************************** /****************************************************************************
** Copyright (c) 2006 - 2011, the LibQxt project. ** Copyright (c) 2006 - 2011, the LibQxt project.
** See the Qxt AUTHORS file for a list of authors and copyright holders. ** See the Qxt AUTHORS file for a list of authors and copyright holders.
@@ -29,6 +28,7 @@
** <http://libqxt.org> <foundation@libqxt.org> ** <http://libqxt.org> <foundation@libqxt.org>
*****************************************************************************/ *****************************************************************************/
#ifndef QXTGLOBALSHORTCUT_H
#define QXTGLOBALSHORTCUT_H #define QXTGLOBALSHORTCUT_H
#include <QObject> #include <QObject>
@@ -39,30 +39,29 @@
class QxtGlobalShortcutPrivate; class QxtGlobalShortcutPrivate;
class QXT_GUI_EXPORT QxtGlobalShortcut : public QObject class QXT_GUI_EXPORT QxtGlobalShortcut : public QObject {
{ Q_OBJECT
Q_OBJECT QXT_DECLARE_PRIVATE(QxtGlobalShortcut)
QXT_DECLARE_PRIVATE(QxtGlobalShortcut) Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled)
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled) Q_PROPERTY(QKeySequence shortcut READ shortcut WRITE setShortcut)
Q_PROPERTY(QKeySequence shortcut READ shortcut WRITE setShortcut)
public: public:
explicit QxtGlobalShortcut(QObject* parent = nullptr); explicit QxtGlobalShortcut(QObject* parent = nullptr);
explicit QxtGlobalShortcut(const QKeySequence& shortcut, QObject* parent = nullptr); explicit QxtGlobalShortcut(const QKeySequence& shortcut, QObject* parent = nullptr);
~QxtGlobalShortcut(); ~QxtGlobalShortcut();
QKeySequence shortcut() const; QKeySequence shortcut() const;
bool setShortcut(const QKeySequence& shortcut); bool setShortcut(const QKeySequence& shortcut);
bool isEnabled() const; bool isEnabled() const;
public Q_SLOTS: public Q_SLOTS:
void setEnabled(bool enabled = true); void setEnabled(bool enabled = true);
void setDisabled(bool disabled = true); void setDisabled(bool disabled = true);
Q_SIGNALS: Q_SIGNALS:
void activated(); void activated();
}; };
#endif // QXTGLOBALSHORTCUT_H #endif // QXTGLOBALSHORTCUT_H

View File

@@ -1,4 +1,3 @@
#include <Carbon/Carbon.h>
/**************************************************************************** /****************************************************************************
** Copyright (c) 2006 - 2011, the LibQxt project. ** Copyright (c) 2006 - 2011, the LibQxt project.
** See the Qxt AUTHORS file for a list of authors and copyright holders. ** See the Qxt AUTHORS file for a list of authors and copyright holders.
@@ -29,9 +28,12 @@
** <http://libqxt.org> <foundation@libqxt.org> ** <http://libqxt.org> <foundation@libqxt.org>
*****************************************************************************/ *****************************************************************************/
#include <Carbon/Carbon.h>
#include "qxtglobalshortcut_p.h" #include "qxtglobalshortcut_p.h"
#include <QMap> #include <QMap>
#include <QHash> #include <QHash>
#include <QPair>
#include <QtDebug> #include <QtDebug>
#include <QApplication> #include <QApplication>
@@ -41,218 +43,165 @@ static QHash<Identifier, quint32> keyIDs;
static quint32 hotKeySerial = 0; static quint32 hotKeySerial = 0;
static bool qxt_mac_handler_installed = false; static bool qxt_mac_handler_installed = false;
OSStatus qxt_mac_handle_hot_key(EventHandlerCallRef nextHandler, EventRef event, void* data) OSStatus qxt_mac_handle_hot_key(EventHandlerCallRef nextHandler, EventRef event, void* data) {
{
Q_UNUSED(nextHandler);
Q_UNUSED(data);
if (GetEventClass(event) == kEventClassKeyboard && GetEventKind(event) == kEventHotKeyPressed)
{
EventHotKeyID keyID;
GetEventParameter(event, kEventParamDirectObject, typeEventHotKeyID, nullptr, sizeof(keyID), nullptr, &keyID);
Identifier id = keyIDs.key(keyID.id);
QxtGlobalShortcutPrivate::activateShortcut(id.second, id.first);
}
return noErr;
}
quint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers)
{
quint32 native = 0;
if (modifiers & Qt::ShiftModifier)
native |= shiftKey;
if (modifiers & Qt::ControlModifier)
native |= cmdKey;
if (modifiers & Qt::AltModifier)
native |= optionKey;
if (modifiers & Qt::MetaModifier)
native |= controlKey;
if (modifiers & Qt::KeypadModifier)
native |= kEventKeyModifierNumLockMask;
return native;
}
quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key)
{
UTF16Char ch;
// Constants found in NSEvent.h from AppKit.framework
switch (key)
{
case Qt::Key_Return:
return kVK_Return;
case Qt::Key_Enter:
return kVK_ANSI_KeypadEnter;
case Qt::Key_Tab:
return kVK_Tab;
case Qt::Key_Space:
return kVK_Space;
case Qt::Key_Backspace:
return kVK_Delete;
case Qt::Key_Control:
return kVK_Command;
case Qt::Key_Shift:
return kVK_Shift;
case Qt::Key_CapsLock:
return kVK_CapsLock;
case Qt::Key_Option:
return kVK_Option;
case Qt::Key_Meta:
return kVK_Control;
case Qt::Key_F17:
return kVK_F17;
case Qt::Key_VolumeUp:
return kVK_VolumeUp;
case Qt::Key_VolumeDown:
return kVK_VolumeDown;
case Qt::Key_F18:
return kVK_F18;
case Qt::Key_F19:
return kVK_F19;
case Qt::Key_F20:
return kVK_F20;
case Qt::Key_F5:
return kVK_F5;
case Qt::Key_F6:
return kVK_F6;
case Qt::Key_F7:
return kVK_F7;
case Qt::Key_F3:
return kVK_F3;
case Qt::Key_F8:
return kVK_F8;
case Qt::Key_F9:
return kVK_F9;
case Qt::Key_F11:
return kVK_F11;
case Qt::Key_F13:
return kVK_F13;
case Qt::Key_F16:
return kVK_F16;
case Qt::Key_F14:
return kVK_F14;
case Qt::Key_F10:
return kVK_F10;
case Qt::Key_F12:
return kVK_F12;
case Qt::Key_F15:
return kVK_F15;
case Qt::Key_Help:
return kVK_Help;
case Qt::Key_Home:
return kVK_Home;
case Qt::Key_PageUp:
return kVK_PageUp;
case Qt::Key_Delete:
return kVK_ForwardDelete;
case Qt::Key_F4:
return kVK_F4;
case Qt::Key_End:
return kVK_End;
case Qt::Key_F2:
return kVK_F2;
case Qt::Key_PageDown:
return kVK_PageDown;
case Qt::Key_F1:
return kVK_F1;
case Qt::Key_Left:
return kVK_LeftArrow;
case Qt::Key_Right:
return kVK_RightArrow;
case Qt::Key_Down:
return kVK_DownArrow;
case Qt::Key_Up:
return kVK_UpArrow;
default:
;
}
if (key == Qt::Key_Escape) ch = 27;
else if (key == Qt::Key_Return) ch = 13;
else if (key == Qt::Key_Enter) ch = 3;
else if (key == Qt::Key_Tab) ch = 9;
else ch = key;
CFDataRef currentLayoutData;
TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
if (currentKeyboard == nullptr)
return 0;
currentLayoutData = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
CFRelease(currentKeyboard);
if (currentLayoutData == nullptr)
return 0;
UCKeyboardLayout* header = (UCKeyboardLayout*)CFDataGetBytePtr(currentLayoutData);
UCKeyboardTypeHeader* table = header->keyboardTypeList;
uint8_t *data = (uint8_t*)header;
// God, would a little documentation for this shit kill you...
for (quint32 i=0; i < header->keyboardTypeCount; i++)
{
UCKeyStateRecordsIndex* stateRec = 0;
if (table[i].keyStateRecordsIndexOffset != 0)
{
stateRec = reinterpret_cast<UCKeyStateRecordsIndex*>(data + table[i].keyStateRecordsIndexOffset);
if (stateRec->keyStateRecordsIndexFormat != kUCKeyStateRecordsIndexFormat) stateRec = 0;
}
UCKeyToCharTableIndex* charTable = reinterpret_cast<UCKeyToCharTableIndex*>(data + table[i].keyToCharTableIndexOffset);
if (charTable->keyToCharTableIndexFormat != kUCKeyToCharTableIndexFormat) continue;
for (quint32 j=0; j < charTable->keyToCharTableCount; j++)
{
UCKeyOutput* keyToChar = reinterpret_cast<UCKeyOutput*>(data + charTable->keyToCharTableOffsets[j]);
for (quint32 k=0; k < charTable->keyToCharTableSize; k++)
{
if (keyToChar[k] & kUCKeyOutputTestForIndexMask)
{
long idx = keyToChar[k] & kUCKeyOutputGetIndexMask;
if (stateRec && idx < stateRec->keyStateRecordCount)
{
UCKeyStateRecord* rec = reinterpret_cast<UCKeyStateRecord*>(data + stateRec->keyStateRecordOffsets[idx]);
if (rec->stateZeroCharData == ch) return k;
}
}
else if (!(keyToChar[k] & kUCKeyOutputSequenceIndexMask) && keyToChar[k] < 0xFFFE)
{
if (keyToChar[k] == ch) return k;
}
} // for k
} // for j
} // for i
return 0;
}
bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods)
{
if (!qxt_mac_handler_installed)
{
EventTypeSpec t;
t.eventClass = kEventClassKeyboard;
t.eventKind = kEventHotKeyPressed;
InstallApplicationEventHandler(&qxt_mac_handle_hot_key, 1, &t, nullptr, nullptr);
}
Q_UNUSED(nextHandler);
Q_UNUSED(data);
if (GetEventClass(event) == kEventClassKeyboard && GetEventKind(event) == kEventHotKeyPressed) {
EventHotKeyID keyID; EventHotKeyID keyID;
keyID.signature = 'cute'; GetEventParameter(event, kEventParamDirectObject, typeEventHotKeyID, nullptr, sizeof(keyID), nullptr, &keyID);
keyID.id = ++hotKeySerial; Identifier id = keyIDs.key(keyID.id);
QxtGlobalShortcutPrivate::activateShortcut(id.second, id.first);
}
return noErr;
EventHotKeyRef ref = 0; }
bool rv = !RegisterEventHotKey(nativeKey, nativeMods, keyID, GetApplicationEventTarget(), 0, &ref);
if (rv) quint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers) {
{
keyIDs.insert(Identifier(nativeMods, nativeKey), keyID.id); quint32 native = 0;
keyRefs.insert(keyID.id, ref); if (modifiers & Qt::ShiftModifier) native |= shiftKey;
if (modifiers & Qt::ControlModifier) native |= cmdKey;
if (modifiers & Qt::AltModifier) native |= optionKey;
if (modifiers & Qt::MetaModifier) native |= controlKey;
if (modifiers & Qt::KeypadModifier) native |= kEventKeyModifierNumLockMask;
return native;
}
quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key) {
UTF16Char ch;
// Constants found in NSEvent.h from AppKit.framework
switch (key) {
case Qt::Key_Return: return kVK_Return;
case Qt::Key_Enter: return kVK_ANSI_KeypadEnter;
case Qt::Key_Tab: return kVK_Tab;
case Qt::Key_Space: return kVK_Space;
case Qt::Key_Backspace: return kVK_Delete;
case Qt::Key_Control: return kVK_Command;
case Qt::Key_Shift: return kVK_Shift;
case Qt::Key_CapsLock: return kVK_CapsLock;
case Qt::Key_Option: return kVK_Option;
case Qt::Key_Meta: return kVK_Control;
case Qt::Key_F17: return kVK_F17;
case Qt::Key_VolumeUp: return kVK_VolumeUp;
case Qt::Key_VolumeDown: return kVK_VolumeDown;
case Qt::Key_F18: return kVK_F18;
case Qt::Key_F19: return kVK_F19;
case Qt::Key_F20: return kVK_F20;
case Qt::Key_F5: return kVK_F5;
case Qt::Key_F6: return kVK_F6;
case Qt::Key_F7: return kVK_F7;
case Qt::Key_F3: return kVK_F3;
case Qt::Key_F8: return kVK_F8;
case Qt::Key_F9: return kVK_F9;
case Qt::Key_F11: return kVK_F11;
case Qt::Key_F13: return kVK_F13;
case Qt::Key_F16: return kVK_F16;
case Qt::Key_F14: return kVK_F14;
case Qt::Key_F10: return kVK_F10;
case Qt::Key_F12: return kVK_F12;
case Qt::Key_F15: return kVK_F15;
case Qt::Key_Help: return kVK_Help;
case Qt::Key_Home: return kVK_Home;
case Qt::Key_PageUp: return kVK_PageUp;
case Qt::Key_Delete: return kVK_ForwardDelete;
case Qt::Key_F4: return kVK_F4;
case Qt::Key_End: return kVK_End;
case Qt::Key_F2: return kVK_F2;
case Qt::Key_PageDown: return kVK_PageDown;
case Qt::Key_F1: return kVK_F1;
case Qt::Key_Left: return kVK_LeftArrow;
case Qt::Key_Right: return kVK_RightArrow;
case Qt::Key_Down: return kVK_DownArrow;
case Qt::Key_Up: return kVK_UpArrow;
default:
;
}
if (key == Qt::Key_Escape) ch = 27;
else if (key == Qt::Key_Return) ch = 13;
else if (key == Qt::Key_Enter) ch = 3;
else if (key == Qt::Key_Tab) ch = 9;
else ch = key;
CFDataRef currentLayoutData;
TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
if (currentKeyboard == nullptr)
return 0;
currentLayoutData = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
CFRelease(currentKeyboard);
if (currentLayoutData == nullptr)
return 0;
UCKeyboardLayout* header = (UCKeyboardLayout*)CFDataGetBytePtr(currentLayoutData);
UCKeyboardTypeHeader* table = header->keyboardTypeList;
uint8_t *data = (uint8_t*)header;
// God, would a little documentation for this shit kill you...
for (quint32 i=0; i < header->keyboardTypeCount; i++) {
UCKeyStateRecordsIndex* stateRec = 0;
if (table[i].keyStateRecordsIndexOffset != 0) {
stateRec = reinterpret_cast<UCKeyStateRecordsIndex*>(data + table[i].keyStateRecordsIndexOffset);
if (stateRec->keyStateRecordsIndexFormat != kUCKeyStateRecordsIndexFormat) stateRec = 0;
} }
return rv;
UCKeyToCharTableIndex* charTable = reinterpret_cast<UCKeyToCharTableIndex*>(data + table[i].keyToCharTableIndexOffset);
if (charTable->keyToCharTableIndexFormat != kUCKeyToCharTableIndexFormat) continue;
for (quint32 j=0; j < charTable->keyToCharTableCount; j++) {
UCKeyOutput* keyToChar = reinterpret_cast<UCKeyOutput*>(data + charTable->keyToCharTableOffsets[j]);
for (quint32 k=0; k < charTable->keyToCharTableSize; k++) {
if (keyToChar[k] & kUCKeyOutputTestForIndexMask) {
long idx = keyToChar[k] & kUCKeyOutputGetIndexMask;
if (stateRec && idx < stateRec->keyStateRecordCount) {
UCKeyStateRecord* rec = reinterpret_cast<UCKeyStateRecord*>(data + stateRec->keyStateRecordOffsets[idx]);
if (rec->stateZeroCharData == ch) return k;
}
}
else if (!(keyToChar[k] & kUCKeyOutputSequenceIndexMask) && keyToChar[k] < 0xFFFE) {
if (keyToChar[k] == ch) return k;
}
} // for k
} // for j
} // for i
return 0;
} }
bool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods) bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods) {
{
Identifier id(nativeMods, nativeKey); if (!qxt_mac_handler_installed) {
if (!keyIDs.contains(id)) return false; EventTypeSpec t;
t.eventClass = kEventClassKeyboard;
t.eventKind = kEventHotKeyPressed;
InstallApplicationEventHandler(&qxt_mac_handle_hot_key, 1, &t, nullptr, nullptr);
}
EventHotKeyID keyID;
keyID.signature = 'cute';
keyID.id = ++hotKeySerial;
EventHotKeyRef ref = 0;
bool rv = !RegisterEventHotKey(nativeKey, nativeMods, keyID, GetApplicationEventTarget(), 0, &ref);
if (rv) {
keyIDs.insert(Identifier(nativeMods, nativeKey), keyID.id);
keyRefs.insert(keyID.id, ref);
}
return rv;
}
bool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods) {
Identifier id(nativeMods, nativeKey);
if (!keyIDs.contains(id)) return false;
EventHotKeyRef ref = keyRefs.take(keyIDs[id]);
keyIDs.remove(id);
return !UnregisterEventHotKey(ref);
EventHotKeyRef ref = keyRefs.take(keyIDs[id]);
keyIDs.remove(id);
return !UnregisterEventHotKey(ref);
} }

View File

@@ -1,4 +1,3 @@
#ifndef QXTGLOBALSHORTCUT_P_H
/**************************************************************************** /****************************************************************************
** Copyright (c) 2006 - 2011, the LibQxt project. ** Copyright (c) 2006 - 2011, the LibQxt project.
** See the Qxt AUTHORS file for a list of authors and copyright holders. ** See the Qxt AUTHORS file for a list of authors and copyright holders.
@@ -29,56 +28,45 @@
** <http://libqxt.org> <foundation@libqxt.org> ** <http://libqxt.org> <foundation@libqxt.org>
*****************************************************************************/ *****************************************************************************/
#ifndef QXTGLOBALSHORTCUT_P_H
#define QXTGLOBALSHORTCUT_P_H #define QXTGLOBALSHORTCUT_P_H
#include "qxtglobalshortcut.h" #include "qxtglobalshortcut.h"
#include <QAbstractEventDispatcher>
#include <QKeySequence>
#include <QHash> #include <QHash>
#include <QAbstractEventDispatcher>
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
#include <QAbstractNativeEventFilter> #include <QAbstractNativeEventFilter>
#endif #include <QKeySequence>
class QxtGlobalShortcutPrivate : public QxtPrivate<QxtGlobalShortcut>, public QAbstractNativeEventFilter {
class QxtGlobalShortcutPrivate : public QxtPrivate<QxtGlobalShortcut>
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
,public QAbstractNativeEventFilter
#endif
{
public: public:
QXT_DECLARE_PUBLIC(QxtGlobalShortcut) QXT_DECLARE_PUBLIC(QxtGlobalShortcut)
QxtGlobalShortcutPrivate(); QxtGlobalShortcutPrivate();
~QxtGlobalShortcutPrivate(); ~QxtGlobalShortcutPrivate();
bool enabled; bool enabled;
Qt::Key key; Qt::Key key;
Qt::KeyboardModifiers mods; Qt::KeyboardModifiers mods;
bool setShortcut(const QKeySequence& shortcut); bool setShortcut(const QKeySequence& shortcut);
bool unsetShortcut(); bool unsetShortcut();
static bool error; static bool error;
#ifndef Q_OS_MAC #ifndef Q_OS_MACOS
static int ref; static int ref;
#if QT_VERSION < QT_VERSION_CHECK(5,0,0) virtual bool nativeEventFilter(const QByteArray & eventType, void * message, long * result);
static QAbstractEventDispatcher::EventFilter prevEventFilter;
static bool eventFilter(void* message);
#else
virtual bool nativeEventFilter(const QByteArray & eventType, void * message, long * result);
#endif // QT_VERSION < QT_VERSION_CHECK(5,0,0)
#endif // Q_OS_MAC #endif // Q_OS_MAC
static void activateShortcut(quint32 nativeKey, quint32 nativeMods); static void activateShortcut(quint32 nativeKey, quint32 nativeMods);
private: private:
static quint32 nativeKeycode(Qt::Key keycode); static quint32 nativeKeycode(Qt::Key keycode);
static quint32 nativeModifiers(Qt::KeyboardModifiers modifiers); static quint32 nativeModifiers(Qt::KeyboardModifiers modifiers);
static bool registerShortcut(quint32 nativeKey, quint32 nativeMods); static bool registerShortcut(quint32 nativeKey, quint32 nativeMods);
static bool unregisterShortcut(quint32 nativeKey, quint32 nativeMods); static bool unregisterShortcut(quint32 nativeKey, quint32 nativeMods);
static QHash<QPair<quint32, quint32>, QxtGlobalShortcut*> shortcuts; static QHash<QPair<quint32, quint32>, QxtGlobalShortcut*> shortcuts;
}; };
#endif // QXTGLOBALSHORTCUT_P_H #endif // QXTGLOBALSHORTCUT_P_H

View File

@@ -31,217 +31,209 @@
#include <qt_windows.h> #include <qt_windows.h>
bool QxtGlobalShortcutPrivate::nativeEventFilter(const QByteArray & eventType, void * message, long * result) {
Q_UNUSED(eventType);
Q_UNUSED(result);
MSG* msg = static_cast<MSG*>(message);
if (msg->message == WM_HOTKEY) {
const quint32 keycode = HIWORD(msg->lParam);
const quint32 modifiers = LOWORD(msg->lParam);
activateShortcut(keycode, modifiers);
}
return false;
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
bool QxtGlobalShortcutPrivate::eventFilter(void* message)
{
#else
bool QxtGlobalShortcutPrivate::nativeEventFilter(const QByteArray & eventType,
void * message, long * result)
{
Q_UNUSED(eventType);
Q_UNUSED(result);
#endif
MSG* msg = static_cast<MSG*>(message);
if (msg->message == WM_HOTKEY)
{
const quint32 keycode = HIWORD(msg->lParam);
const quint32 modifiers = LOWORD(msg->lParam);
activateShortcut(keycode, modifiers);
}
return false;
} }
quint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers) quint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers) {
{
// MOD_ALT, MOD_CONTROL, (MOD_KEYUP), MOD_SHIFT, MOD_WIN // MOD_ALT, MOD_CONTROL, (MOD_KEYUP), MOD_SHIFT, MOD_WIN
quint32 native = 0; quint32 native = 0;
if (modifiers & Qt::ShiftModifier) if (modifiers & Qt::ShiftModifier)
native |= MOD_SHIFT; native |= MOD_SHIFT;
if (modifiers & Qt::ControlModifier) if (modifiers & Qt::ControlModifier)
native |= MOD_CONTROL; native |= MOD_CONTROL;
if (modifiers & Qt::AltModifier) if (modifiers & Qt::AltModifier)
native |= MOD_ALT; native |= MOD_ALT;
if (modifiers & Qt::MetaModifier) if (modifiers & Qt::MetaModifier)
native |= MOD_WIN; native |= MOD_WIN;
// TODO: resolve these? // TODO: resolve these?
//if (modifiers & Qt::KeypadModifier) //if (modifiers & Qt::KeypadModifier)
//if (modifiers & Qt::GroupSwitchModifier) //if (modifiers & Qt::GroupSwitchModifier)
return native; return native;
} }
quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key) quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key) {
{
switch (key)
{
case Qt::Key_Escape:
return VK_ESCAPE;
case Qt::Key_Tab:
case Qt::Key_Backtab:
return VK_TAB;
case Qt::Key_Backspace:
return VK_BACK;
case Qt::Key_Return:
case Qt::Key_Enter:
return VK_RETURN;
case Qt::Key_Insert:
return VK_INSERT;
case Qt::Key_Delete:
return VK_DELETE;
case Qt::Key_Pause:
return VK_PAUSE;
case Qt::Key_Print:
return VK_PRINT;
case Qt::Key_Clear:
return VK_CLEAR;
case Qt::Key_Home:
return VK_HOME;
case Qt::Key_End:
return VK_END;
case Qt::Key_Left:
return VK_LEFT;
case Qt::Key_Up:
return VK_UP;
case Qt::Key_Right:
return VK_RIGHT;
case Qt::Key_Down:
return VK_DOWN;
case Qt::Key_PageUp:
return VK_PRIOR;
case Qt::Key_PageDown:
return VK_NEXT;
case Qt::Key_F1:
return VK_F1;
case Qt::Key_F2:
return VK_F2;
case Qt::Key_F3:
return VK_F3;
case Qt::Key_F4:
return VK_F4;
case Qt::Key_F5:
return VK_F5;
case Qt::Key_F6:
return VK_F6;
case Qt::Key_F7:
return VK_F7;
case Qt::Key_F8:
return VK_F8;
case Qt::Key_F9:
return VK_F9;
case Qt::Key_F10:
return VK_F10;
case Qt::Key_F11:
return VK_F11;
case Qt::Key_F12:
return VK_F12;
case Qt::Key_F13:
return VK_F13;
case Qt::Key_F14:
return VK_F14;
case Qt::Key_F15:
return VK_F15;
case Qt::Key_F16:
return VK_F16;
case Qt::Key_F17:
return VK_F17;
case Qt::Key_F18:
return VK_F18;
case Qt::Key_F19:
return VK_F19;
case Qt::Key_F20:
return VK_F20;
case Qt::Key_F21:
return VK_F21;
case Qt::Key_F22:
return VK_F22;
case Qt::Key_F23:
return VK_F23;
case Qt::Key_F24:
return VK_F24;
case Qt::Key_Space:
return VK_SPACE;
case Qt::Key_Asterisk:
return VK_MULTIPLY;
case Qt::Key_Plus:
return VK_ADD;
case Qt::Key_Comma:
return VK_SEPARATOR;
case Qt::Key_Minus:
return VK_SUBTRACT;
case Qt::Key_Slash:
return VK_DIVIDE;
case Qt::Key_MediaNext:
return VK_MEDIA_NEXT_TRACK;
case Qt::Key_MediaPrevious:
return VK_MEDIA_PREV_TRACK;
case Qt::Key_MediaPlay:
return VK_MEDIA_PLAY_PAUSE;
case Qt::Key_MediaStop:
return VK_MEDIA_STOP;
// couldn't find those in VK_*
//case Qt::Key_MediaLast:
//case Qt::Key_MediaRecord:
case Qt::Key_VolumeDown:
return VK_VOLUME_DOWN;
case Qt::Key_VolumeUp:
return VK_VOLUME_UP;
case Qt::Key_VolumeMute:
return VK_VOLUME_MUTE;
// numbers switch (key) {
case Qt::Key_0: case Qt::Key_Escape:
case Qt::Key_1: return VK_ESCAPE;
case Qt::Key_2: case Qt::Key_Tab:
case Qt::Key_3: case Qt::Key_Backtab:
case Qt::Key_4: return VK_TAB;
case Qt::Key_5: case Qt::Key_Backspace:
case Qt::Key_6: return VK_BACK;
case Qt::Key_7: case Qt::Key_Return:
case Qt::Key_8: case Qt::Key_Enter:
case Qt::Key_9: return VK_RETURN;
return key; case Qt::Key_Insert:
return VK_INSERT;
case Qt::Key_Delete:
return VK_DELETE;
case Qt::Key_Pause:
return VK_PAUSE;
case Qt::Key_Print:
return VK_PRINT;
case Qt::Key_Clear:
return VK_CLEAR;
case Qt::Key_Home:
return VK_HOME;
case Qt::Key_End:
return VK_END;
case Qt::Key_Left:
return VK_LEFT;
case Qt::Key_Up:
return VK_UP;
case Qt::Key_Right:
return VK_RIGHT;
case Qt::Key_Down:
return VK_DOWN;
case Qt::Key_PageUp:
return VK_PRIOR;
case Qt::Key_PageDown:
return VK_NEXT;
case Qt::Key_F1:
return VK_F1;
case Qt::Key_F2:
return VK_F2;
case Qt::Key_F3:
return VK_F3;
case Qt::Key_F4:
return VK_F4;
case Qt::Key_F5:
return VK_F5;
case Qt::Key_F6:
return VK_F6;
case Qt::Key_F7:
return VK_F7;
case Qt::Key_F8:
return VK_F8;
case Qt::Key_F9:
return VK_F9;
case Qt::Key_F10:
return VK_F10;
case Qt::Key_F11:
return VK_F11;
case Qt::Key_F12:
return VK_F12;
case Qt::Key_F13:
return VK_F13;
case Qt::Key_F14:
return VK_F14;
case Qt::Key_F15:
return VK_F15;
case Qt::Key_F16:
return VK_F16;
case Qt::Key_F17:
return VK_F17;
case Qt::Key_F18:
return VK_F18;
case Qt::Key_F19:
return VK_F19;
case Qt::Key_F20:
return VK_F20;
case Qt::Key_F21:
return VK_F21;
case Qt::Key_F22:
return VK_F22;
case Qt::Key_F23:
return VK_F23;
case Qt::Key_F24:
return VK_F24;
case Qt::Key_Space:
return VK_SPACE;
case Qt::Key_Asterisk:
return VK_MULTIPLY;
case Qt::Key_Plus:
return VK_ADD;
case Qt::Key_Comma:
return VK_SEPARATOR;
case Qt::Key_Minus:
return VK_SUBTRACT;
case Qt::Key_Slash:
return VK_DIVIDE;
case Qt::Key_MediaNext:
return VK_MEDIA_NEXT_TRACK;
case Qt::Key_MediaPrevious:
return VK_MEDIA_PREV_TRACK;
case Qt::Key_MediaPlay:
return VK_MEDIA_PLAY_PAUSE;
case Qt::Key_MediaStop:
return VK_MEDIA_STOP;
// couldn't find those in VK_*
//case Qt::Key_MediaLast:
//case Qt::Key_MediaRecord:
case Qt::Key_VolumeDown:
return VK_VOLUME_DOWN;
case Qt::Key_VolumeUp:
return VK_VOLUME_UP;
case Qt::Key_VolumeMute:
return VK_VOLUME_MUTE;
// letters // numbers
case Qt::Key_A: case Qt::Key_0:
case Qt::Key_B: case Qt::Key_1:
case Qt::Key_C: case Qt::Key_2:
case Qt::Key_D: case Qt::Key_3:
case Qt::Key_E: case Qt::Key_4:
case Qt::Key_F: case Qt::Key_5:
case Qt::Key_G: case Qt::Key_6:
case Qt::Key_H: case Qt::Key_7:
case Qt::Key_I: case Qt::Key_8:
case Qt::Key_J: case Qt::Key_9:
case Qt::Key_K: return key;
case Qt::Key_L:
case Qt::Key_M: // letters
case Qt::Key_N: case Qt::Key_A:
case Qt::Key_O: case Qt::Key_B:
case Qt::Key_P: case Qt::Key_C:
case Qt::Key_Q: case Qt::Key_D:
case Qt::Key_R: case Qt::Key_E:
case Qt::Key_S: case Qt::Key_F:
case Qt::Key_T: case Qt::Key_G:
case Qt::Key_U: case Qt::Key_H:
case Qt::Key_V: case Qt::Key_I:
case Qt::Key_W: case Qt::Key_J:
case Qt::Key_X: case Qt::Key_K:
case Qt::Key_Y: case Qt::Key_L:
case Qt::Key_Z: case Qt::Key_M:
return key; case Qt::Key_N:
case Qt::Key_O:
case Qt::Key_P:
case Qt::Key_Q:
case Qt::Key_R:
case Qt::Key_S:
case Qt::Key_T:
case Qt::Key_U:
case Qt::Key_V:
case Qt::Key_W:
case Qt::Key_X:
case Qt::Key_Y:
case Qt::Key_Z:
return key;
default:
return 0;
}
default:
return 0;
}
} }
bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods) bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods) {
{ return RegisterHotKey(0, nativeMods ^ nativeKey, nativeMods, nativeKey);
return RegisterHotKey(0, nativeMods ^ nativeKey, nativeMods, nativeKey);
} }
bool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods) bool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods) {
{ return UnregisterHotKey(0, nativeMods ^ nativeKey);
return UnregisterHotKey(0, nativeMods ^ nativeKey);
} }

View File

@@ -1,4 +1,3 @@
#include "qxtglobalshortcut_p.h"
/**************************************************************************** /****************************************************************************
** Copyright (c) 2006 - 2011, the LibQxt project. ** Copyright (c) 2006 - 2011, the LibQxt project.
** See the Qxt AUTHORS file for a list of authors and copyright holders. ** See the Qxt AUTHORS file for a list of authors and copyright holders.
@@ -29,201 +28,176 @@
** <http://libqxt.org> <foundation@libqxt.org> ** <http://libqxt.org> <foundation@libqxt.org>
*****************************************************************************/ *****************************************************************************/
#if QT_VERSION < QT_VERSION_CHECK(5,0,0) #include "qxtglobalshortcut_p.h"
# include <QX11Info>
#else
# include <qpa/qplatformnativeinterface.h>
# include <xcb/xcb.h>
# include <QApplication>
#endif
#include <X11/X.h>
#include <X11/Xlib.h>
#include <xcb/xproto.h>
#include <QtGlobal> #include <QtGlobal>
#include <QByteArray> #include <QApplication>
#include <QGuiApplication> #include <QGuiApplication>
#include <QKeySequence> #include <QKeySequence>
#include <QByteArray>
#include <QString> #include <QString>
#include <QVector> #include <QVector>
#include <QX11Info>
#include <qpa/qplatformnativeinterface.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <xcb/xcb.h>
#include <xcb/xproto.h>
#include "keymapper_x11.h" #include "keymapper_x11.h"
namespace { namespace {
const QVector<quint32> maskModifiers = QVector<quint32>() const QVector<quint32> maskModifiers = QVector<quint32>() << 0 << Mod2Mask << LockMask << (Mod2Mask | LockMask);
<< 0 << Mod2Mask << LockMask << (Mod2Mask | LockMask);
typedef int (*X11ErrorHandler)(Display *display, XErrorEvent *event); typedef int (*X11ErrorHandler)(Display *display, XErrorEvent *event);
class QxtX11ErrorHandler { class QxtX11ErrorHandler {
public: public:
static bool error; static bool error;
static int qxtX11ErrorHandler(Display *display, XErrorEvent *event) static int qxtX11ErrorHandler(Display *display, XErrorEvent *event) {
{ Q_UNUSED(display);
Q_UNUSED(display); switch (event->error_code) {
switch (event->error_code) case BadAccess:
case BadValue:
case BadWindow:
if (event->request_code == 33 /* X_GrabKey */ ||
event->request_code == 34 /* X_UngrabKey */)
{ {
case BadAccess: error = true;
case BadValue: //TODO:
case BadWindow: //char errstr[256];
if (event->request_code == 33 /* X_GrabKey */ || //XGetErrorText(dpy, err->error_code, errstr, 256);
event->request_code == 34 /* X_UngrabKey */)
{
error = true;
//TODO:
//char errstr[256];
//XGetErrorText(dpy, err->error_code, errstr, 256);
}
} }
return 0;
} }
return 0;
}
QxtX11ErrorHandler() QxtX11ErrorHandler() {
{ error = false;
error = false; m_previousErrorHandler = XSetErrorHandler(qxtX11ErrorHandler);
m_previousErrorHandler = XSetErrorHandler(qxtX11ErrorHandler); }
}
~QxtX11ErrorHandler() ~QxtX11ErrorHandler() {
{ XSetErrorHandler(m_previousErrorHandler);
XSetErrorHandler(m_previousErrorHandler); }
}
private: private:
X11ErrorHandler m_previousErrorHandler; X11ErrorHandler m_previousErrorHandler;
}; };
bool QxtX11ErrorHandler::error = false; bool QxtX11ErrorHandler::error = false;
class QxtX11Data { class QxtX11Data {
public: public:
QxtX11Data() QxtX11Data() {
{ QPlatformNativeInterface *native = qApp->platformNativeInterface();
#if QT_VERSION < QT_VERSION_CHECK(5,0,0) //void *display = native->nativeResourceForScreen(QByteArray("display"), QGuiApplication::primaryScreen());
m_display = QX11Info::display(); //m_display = reinterpret_cast<Display *>(display);
#else m_display = QX11Info::display();
QPlatformNativeInterface *native = qApp->platformNativeInterface(); }
void *display = native->nativeResourceForScreen(QByteArray("display"),
QGuiApplication::primaryScreen()); bool isValid() {
m_display = reinterpret_cast<Display *>(display); return m_display != nullptr;
#endif }
Display *display() {
Q_ASSERT(isValid());
return m_display;
}
Window rootWindow() {
return DefaultRootWindow(display());
}
bool grabKey(quint32 keycode, quint32 modifiers, Window window) {
QxtX11ErrorHandler errorHandler;
for (int i = 0; !errorHandler.error && i < maskModifiers.size(); ++i) {
XGrabKey(display(), keycode, modifiers | maskModifiers[i], window, True, GrabModeAsync, GrabModeAsync);
} }
bool isValid() if (errorHandler.error) {
{ ungrabKey(keycode, modifiers, window);
return m_display != nullptr; return false;
} }
Display *display() return true;
{ }
Q_ASSERT(isValid());
return m_display; bool ungrabKey(quint32 keycode, quint32 modifiers, Window window) {
QxtX11ErrorHandler errorHandler;
foreach (quint32 maskMods, maskModifiers) {
XUngrabKey(display(), keycode, modifiers | maskMods, window);
} }
Window rootWindow() return !errorHandler.error;
{ }
return DefaultRootWindow(display());
}
bool grabKey(quint32 keycode, quint32 modifiers, Window window)
{
QxtX11ErrorHandler errorHandler;
for (int i = 0; !errorHandler.error && i < maskModifiers.size(); ++i) {
XGrabKey(display(), keycode, modifiers | maskModifiers[i], window, True,
GrabModeAsync, GrabModeAsync);
}
if (errorHandler.error) {
ungrabKey(keycode, modifiers, window);
return false;
}
return true;
}
bool ungrabKey(quint32 keycode, quint32 modifiers, Window window)
{
QxtX11ErrorHandler errorHandler;
foreach (quint32 maskMods, maskModifiers) {
XUngrabKey(display(), keycode, modifiers | maskMods, window);
}
return !errorHandler.error;
}
private: private:
Display *m_display; Display *m_display;
}; };
} // namespace } // namespace
#if QT_VERSION < QT_VERSION_CHECK(5,0,0) bool QxtGlobalShortcutPrivate::nativeEventFilter(const QByteArray & eventType, void *message, long *result) {
bool QxtGlobalShortcutPrivate::eventFilter(void *message)
{
XEvent *event = static_cast<XEvent *>(message);
if (event->type == KeyPress)
{
XKeyEvent *key = reinterpret_cast<XKeyEvent *>(event);
unsigned int keycode = key->keycode;
unsigned int keystate = key->state;
#else
bool QxtGlobalShortcutPrivate::nativeEventFilter(const QByteArray & eventType,
void *message, long *result)
{
Q_UNUSED(result);
xcb_key_press_event_t *kev = nullptr; Q_UNUSED(result);
if (eventType == "xcb_generic_event_t") {
xcb_generic_event_t *ev = static_cast<xcb_generic_event_t *>(message); xcb_key_press_event_t *kev = nullptr;
if ((ev->response_type & 127) == XCB_KEY_PRESS) if (eventType == "xcb_generic_event_t") {
kev = static_cast<xcb_key_press_event_t *>(message); xcb_generic_event_t *ev = static_cast<xcb_generic_event_t *>(message);
} if ((ev->response_type & 127) == XCB_KEY_PRESS)
kev = static_cast<xcb_key_press_event_t *>(message);
}
if (kev != nullptr) {
unsigned int keycode = kev->detail;
unsigned int keystate = 0;
if(kev->state & XCB_MOD_MASK_1)
keystate |= Mod1Mask;
if(kev->state & XCB_MOD_MASK_CONTROL)
keystate |= ControlMask;
if(kev->state & XCB_MOD_MASK_4)
keystate |= Mod4Mask;
if(kev->state & XCB_MOD_MASK_SHIFT)
keystate |= ShiftMask;
activateShortcut(keycode,
// Mod1Mask == Alt, Mod4Mask == Meta
keystate & (ShiftMask | ControlMask | Mod1Mask | Mod4Mask));
}
return false;
if (kev != nullptr) {
unsigned int keycode = kev->detail;
unsigned int keystate = 0;
if(kev->state & XCB_MOD_MASK_1)
keystate |= Mod1Mask;
if(kev->state & XCB_MOD_MASK_CONTROL)
keystate |= ControlMask;
if(kev->state & XCB_MOD_MASK_4)
keystate |= Mod4Mask;
if(kev->state & XCB_MOD_MASK_SHIFT)
keystate |= ShiftMask;
#endif
activateShortcut(keycode,
// Mod1Mask == Alt, Mod4Mask == Meta
keystate & (ShiftMask | ControlMask | Mod1Mask | Mod4Mask));
}
return false;
} }
quint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers) quint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers) {
{
// ShiftMask, LockMask, ControlMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, and Mod5Mask // ShiftMask, LockMask, ControlMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, and Mod5Mask
quint32 native = 0; quint32 native = 0;
if (modifiers & Qt::ShiftModifier) if (modifiers & Qt::ShiftModifier)
native |= ShiftMask; native |= ShiftMask;
if (modifiers & Qt::ControlModifier) if (modifiers & Qt::ControlModifier)
native |= ControlMask; native |= ControlMask;
if (modifiers & Qt::AltModifier) if (modifiers & Qt::AltModifier)
native |= Mod1Mask; native |= Mod1Mask;
if (modifiers & Qt::MetaModifier) if (modifiers & Qt::MetaModifier)
native |= Mod4Mask; native |= Mod4Mask;
// TODO: resolve these?
//if (modifiers & Qt::MetaModifier)
//if (modifiers & Qt::KeypadModifier)
//if (modifiers & Qt::GroupSwitchModifier)
return native;
// TODO: resolve these?
//if (modifiers & Qt::MetaModifier)
//if (modifiers & Qt::KeypadModifier)
//if (modifiers & Qt::GroupSwitchModifier)
return native;
} }
quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key) quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key) {
{
// (davidsansome) Try the table from QKeyMapper first - this seems to be // (davidsansome) Try the table from QKeyMapper first - this seems to be
// the only way to get Keysyms for the media keys. // the only way to get Keysyms for the media keys.
unsigned int keysym = 0; unsigned int keysym = 0;
@@ -238,9 +212,9 @@ quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key)
// If that didn't work then fall back on XStringToKeysym // If that didn't work then fall back on XStringToKeysym
if (!keysym) { if (!keysym) {
keysym = XStringToKeysym(QKeySequence(key).toString().toLatin1().data()); keysym = XStringToKeysym(QKeySequence(key).toString().toLatin1().data());
if (keysym == NoSymbol) if (keysym == NoSymbol)
keysym = static_cast<ushort>(key); keysym = static_cast<ushort>(key);
} }
QxtX11Data x11; QxtX11Data x11;
@@ -248,16 +222,15 @@ quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key)
return 0; return 0;
return XKeysymToKeycode(x11.display(), keysym); return XKeysymToKeycode(x11.display(), keysym);
} }
bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods) bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods) {
{ QxtX11Data x11;
QxtX11Data x11; return x11.isValid() && x11.grabKey(nativeKey, nativeMods, x11.rootWindow());
return x11.isValid() && x11.grabKey(nativeKey, nativeMods, x11.rootWindow());
} }
bool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods) bool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods) {
{ QxtX11Data x11;
QxtX11Data x11; return x11.isValid() && x11.ungrabKey(nativeKey, nativeMods, x11.rootWindow());
return x11.isValid() && x11.ungrabKey(nativeKey, nativeMods, x11.rootWindow());
} }