新增全局热键示例

master
feiyangqingyun 2021-10-13 14:15:18 +08:00
parent 37e84dd117
commit 620fc4be30
80 changed files with 4147 additions and 14 deletions

BIN
0snap/hotkey.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -0,0 +1,20 @@
CONFIG += C++11
HEADERS += $$PWD/qhotkey.h
HEADERS += $$PWD/qhotkey_p.h
SOURCES += $$PWD/qhotkey.cpp
win32 {
LIBS += -luser32
SOURCES += $$PWD/qhotkey_win.cpp
}
unix:!macx {
QT += x11extras
LIBS += -lX11
SOURCES += $$PWD/qhotkey_x11.cpp
}
macx {
LIBS += -framework Carbon
SOURCES += $$PWD/qhotkey_mac.cpp
}

349
3rd_qhotkey/qhotkey.cpp Normal file
View File

@ -0,0 +1,349 @@
#include "qhotkey.h"
#include "qhotkey_p.h"
#include <QCoreApplication>
#include <QAbstractEventDispatcher>
#include <QMetaMethod>
#include <QThread>
#include <QDebug>
QHotkey::QHotkey(QObject *parent) : QObject(parent)
{
_keyCode = Qt::Key_unknown;
_modifiers = Qt::NoModifier;
_nativeShortcut = 0;
_registered = false;
}
QHotkey::QHotkey(const QKeySequence &sequence, bool autoRegister, QObject *parent) : QHotkey(parent)
{
setShortcut(sequence, autoRegister);
}
QHotkey::QHotkey(Qt::Key keyCode, Qt::KeyboardModifiers modifiers, bool autoRegister, QObject *parent) : QHotkey(parent)
{
setShortcut(keyCode, modifiers, autoRegister);
}
QHotkey::QHotkey(const QHotkey::NativeShortcut &shortcut, bool autoRegister, QObject *parent) : QHotkey(parent)
{
setNativeShortcut(shortcut, autoRegister);
}
QHotkey::~QHotkey()
{
if (_registered) {
QHotkeyPrivate::instance()->removeShortcut(this);
}
}
QKeySequence QHotkey::shortcut() const
{
if (_keyCode == Qt::Key_unknown) {
return QKeySequence();
} else {
return QKeySequence(_keyCode | _modifiers);
}
}
Qt::Key QHotkey::keyCode() const
{
return _keyCode;
}
Qt::KeyboardModifiers QHotkey::modifiers() const
{
return _modifiers;
}
QHotkey::NativeShortcut QHotkey::currentNativeShortcut() const
{
return _nativeShortcut;
}
bool QHotkey::isRegistered() const
{
return _registered;
}
bool QHotkey::setShortcut(const QKeySequence &shortcut, bool autoRegister)
{
if (shortcut.isEmpty()) {
return resetShortcut();
} else if (shortcut.count() > 1) {
qDebug() << "Keysequences with multiple shortcuts are not allowed Only the first shortcut will be used!";;
}
return setShortcut(Qt::Key(shortcut[0] & ~Qt::KeyboardModifierMask),
Qt::KeyboardModifiers(shortcut[0] & Qt::KeyboardModifierMask),
autoRegister);
}
bool QHotkey::setShortcut(Qt::Key keyCode, Qt::KeyboardModifiers modifiers, bool autoRegister)
{
if (_registered) {
if (autoRegister) {
if (!QHotkeyPrivate::instance()->removeShortcut(this)) {
return false;
}
} else {
return false;
}
}
if (keyCode == Qt::Key_unknown) {
_keyCode = Qt::Key_unknown;
_modifiers = Qt::NoModifier;
_nativeShortcut = NativeShortcut();
return true;
}
_keyCode = keyCode;
_modifiers = modifiers;
_nativeShortcut = QHotkeyPrivate::instance()->nativeShortcut(keyCode, modifiers);
if (_nativeShortcut.isValid()) {
if (autoRegister) {
return QHotkeyPrivate::instance()->addShortcut(this);
} else {
return true;
}
} else {
qDebug() << "Unable to map shortcut to native keys. Key:" << keyCode << "Modifiers:" << modifiers;
_keyCode = Qt::Key_unknown;
_modifiers = Qt::NoModifier;
_nativeShortcut = NativeShortcut();
return false;
}
}
bool QHotkey::resetShortcut()
{
if (_registered &&
!QHotkeyPrivate::instance()->removeShortcut(this)) {
return false;
}
_keyCode = Qt::Key_unknown;
_modifiers = Qt::NoModifier;
_nativeShortcut = NativeShortcut();
return true;
}
bool QHotkey::setNativeShortcut(QHotkey::NativeShortcut nativeShortcut, bool autoRegister)
{
if (_registered) {
if (autoRegister) {
if (!QHotkeyPrivate::instance()->removeShortcut(this)) {
return false;
}
} else {
return false;
}
}
if (nativeShortcut.isValid()) {
_keyCode = Qt::Key_unknown;
_modifiers = Qt::NoModifier;
_nativeShortcut = nativeShortcut;
if (autoRegister) {
return QHotkeyPrivate::instance()->addShortcut(this);
} else {
return true;
}
} else {
_keyCode = Qt::Key_unknown;
_modifiers = Qt::NoModifier;
_nativeShortcut = NativeShortcut();
return true;
}
}
bool QHotkey::setRegistered(bool registered)
{
if (_registered && !registered) {
return QHotkeyPrivate::instance()->removeShortcut(this);
} else if (!_registered && registered) {
if (!_nativeShortcut.isValid()) {
return false;
} else {
return QHotkeyPrivate::instance()->addShortcut(this);
}
} else {
return true;
}
}
// ---------- QHotkeyPrivate implementation ----------
QHotkeyPrivate::QHotkeyPrivate()
{
shortcuts = QMultiHash<QHotkey::NativeShortcut, QHotkey *>();
Q_ASSERT_X(qApp, Q_FUNC_INFO, "QHotkey requires QCoreApplication to be instantiated");
qApp->eventDispatcher()->installNativeEventFilter(this);
}
QHotkeyPrivate::~QHotkeyPrivate()
{
if (!shortcuts.isEmpty()) {
qDebug() << "QHotkeyPrivate destroyed with registered shortcuts!";
}
if (qApp && qApp->eventDispatcher()) {
qApp->eventDispatcher()->removeNativeEventFilter(this);
}
}
QHotkey::NativeShortcut QHotkeyPrivate::nativeShortcut(Qt::Key keycode, Qt::KeyboardModifiers modifiers)
{
Qt::ConnectionType conType = (QThread::currentThread() == thread() ?
Qt::DirectConnection :
Qt::BlockingQueuedConnection);
QHotkey::NativeShortcut res;
if (!QMetaObject::invokeMethod(this, "nativeShortcutInvoked", conType,
Q_RETURN_ARG(QHotkey::NativeShortcut, res),
Q_ARG(Qt::Key, keycode),
Q_ARG(Qt::KeyboardModifiers, modifiers))) {
return QHotkey::NativeShortcut();
} else {
return res;
}
}
bool QHotkeyPrivate::addShortcut(QHotkey *hotkey)
{
if (hotkey->_registered) {
return false;
}
Qt::ConnectionType conType = (QThread::currentThread() == thread() ?
Qt::DirectConnection :
Qt::BlockingQueuedConnection);
bool res = false;
if (!QMetaObject::invokeMethod(this, "addShortcutInvoked", conType,
Q_RETURN_ARG(bool, res),
Q_ARG(QHotkey *, hotkey))) {
return false;
} else {
if (res) {
emit hotkey->registeredChanged(true);
}
return res;
}
}
bool QHotkeyPrivate::removeShortcut(QHotkey *hotkey)
{
if (!hotkey->_registered) {
return false;
}
Qt::ConnectionType conType = (QThread::currentThread() == thread() ?
Qt::DirectConnection :
Qt::BlockingQueuedConnection);
bool res = false;
if (!QMetaObject::invokeMethod(this, "removeShortcutInvoked", conType,
Q_RETURN_ARG(bool, res),
Q_ARG(QHotkey *, hotkey))) {
return false;
} else {
if (res) {
emit hotkey->registeredChanged(false);
}
return res;
}
}
void QHotkeyPrivate::activateShortcut(QHotkey::NativeShortcut shortcut)
{
QMetaMethod signal = QMetaMethod::fromSignal(&QHotkey::activated);
foreach (QHotkey *hkey, shortcuts.values(shortcut)) {
signal.invoke(hkey, Qt::QueuedConnection);
}
}
bool QHotkeyPrivate::addShortcutInvoked(QHotkey *hotkey)
{
QHotkey::NativeShortcut shortcut = hotkey->_nativeShortcut;
if (!shortcuts.contains(shortcut)) {
if (!registerShortcut(shortcut)) {
return false;
}
}
shortcuts.insert(shortcut, hotkey);
hotkey->_registered = true;
return true;
}
bool QHotkeyPrivate::removeShortcutInvoked(QHotkey *hotkey)
{
QHotkey::NativeShortcut shortcut = hotkey->_nativeShortcut;
if (shortcuts.remove(shortcut, hotkey) == 0) {
return false;
}
hotkey->_registered = false;
emit hotkey->registeredChanged(true);
if (shortcuts.count(shortcut) == 0) {
return unregisterShortcut(shortcut);
} else {
return true;
}
}
QHotkey::NativeShortcut QHotkeyPrivate::nativeShortcutInvoked(Qt::Key keycode, Qt::KeyboardModifiers modifiers)
{
bool ok1, ok2 = false;
quint32 k = nativeKeycode(keycode, ok1);
quint32 m = nativeModifiers(modifiers, ok2);
if (ok1 && ok2) {
return QHotkey::NativeShortcut(k, m);
} else {
return QHotkey::NativeShortcut();
}
}
QHotkey::NativeShortcut::NativeShortcut()
{
this->key = Qt::Key_unknown;
this->modifier = Qt::NoModifier;
this->valid = false;
}
QHotkey::NativeShortcut::NativeShortcut(quint32 key, quint32 modifier)
{
this->key = key;
this->modifier = modifier;
this->valid = true;
}
bool QHotkey::NativeShortcut::isValid() const
{
return valid;
}
bool QHotkey::NativeShortcut::operator ==(const QHotkey::NativeShortcut &other) const
{
return (key == other.key) &&
(modifier == other.modifier) &&
valid == other.valid;
}
bool QHotkey::NativeShortcut::operator !=(const QHotkey::NativeShortcut &other) const
{
return (key != other.key) ||
(modifier != other.modifier) ||
valid != other.valid;
}
uint qHash(const QHotkey::NativeShortcut &key)
{
return qHash(key.key) ^ qHash(key.modifier);
}
uint qHash(const QHotkey::NativeShortcut &key, uint seed)
{
return qHash(key.key, seed) ^ qHash(key.modifier, seed);
}

111
3rd_qhotkey/qhotkey.h Normal file
View File

@ -0,0 +1,111 @@
#ifndef QHOTKEY_H
#define QHOTKEY_H
#include <QObject>
#include <QKeySequence>
#include <QPair>
#ifdef QHOTKEY_LIB
#ifdef QHOTKEY_LIB_BUILD
#define QHOTKEY_SHARED_EXPORT Q_DECL_EXPORT
#else
#define QHOTKEY_SHARED_EXPORT Q_DECL_IMPORT
#endif
#else
#define QHOTKEY_SHARED_EXPORT
#endif
//! A class to define global, systemwide Hotkeys
class QHOTKEY_SHARED_EXPORT QHotkey : public QObject
{
Q_OBJECT
friend class QHotkeyPrivate;
//! Specifies whether this hotkey is currently registered or not
Q_PROPERTY(bool registered READ isRegistered WRITE setRegistered NOTIFY registeredChanged)
//! Holds the shortcut this hotkey will be triggered on
Q_PROPERTY(QKeySequence shortcut READ shortcut WRITE setShortcut RESET resetShortcut)
public:
//! Defines shortcut with native keycodes
class QHOTKEY_SHARED_EXPORT NativeShortcut
{
public:
//! The native keycode
quint32 key;
//! The native modifiers
quint32 modifier;
//! Creates an invalid native shortcut
NativeShortcut();
//! Creates a valid native shortcut, with the given key and modifiers
NativeShortcut(quint32 key, quint32 modifier = 0);
//! Checks, whether this shortcut is valid or not
bool isValid() const;
//! Equality operator
bool operator ==(const NativeShortcut &other) const;
//! Inequality operator
bool operator !=(const NativeShortcut &other) const;
private:
bool valid;
};
//! Constructor
explicit QHotkey(QObject *parent = 0);
//! Constructs a hotkey with a shortcut and optionally registers it
explicit QHotkey(const QKeySequence &shortcut, bool autoRegister = false, QObject *parent = 0);
//! Constructs a hotkey with a key and modifiers and optionally registers it
explicit QHotkey(Qt::Key keyCode, Qt::KeyboardModifiers modifiers, bool autoRegister = false, QObject *parent = 0);
//! Constructs a hotkey from a native shortcut and optionally registers it
explicit QHotkey(const NativeShortcut &shortcut, bool autoRegister = false, QObject *parent = 0);
//! Destructor
~QHotkey();
//! READ-Accessor for QHotkey::registered
bool isRegistered() const;
//! READ-Accessor for QHotkey::shortcut - the key and modifiers as a QKeySequence
QKeySequence shortcut() const;
//! READ-Accessor for QHotkey::shortcut - the key only
Qt::Key keyCode() const;
//! READ-Accessor for QHotkey::shortcut - the modifiers only
Qt::KeyboardModifiers modifiers() const;
//! Get the current native shortcut
NativeShortcut currentNativeShortcut() const;
public slots:
//! WRITE-Accessor for QHotkey::registered
bool setRegistered(bool registered);
//! WRITE-Accessor for QHotkey::shortcut
bool setShortcut(const QKeySequence &shortcut, bool autoRegister = false);
//! WRITE-Accessor for QHotkey::shortcut
bool setShortcut(Qt::Key keyCode, Qt::KeyboardModifiers modifiers, bool autoRegister = false);
//! RESET-Accessor for QHotkey::shortcut
bool resetShortcut();
//! Set this hotkey to a native shortcut
bool setNativeShortcut(NativeShortcut nativeShortcut, bool autoRegister = false);
signals:
//! Will be emitted if the shortcut is pressed
void activated();
//! NOTIFY-Accessor for QHotkey::registered
void registeredChanged(bool registered);
private:
Qt::Key _keyCode;
Qt::KeyboardModifiers _modifiers;
NativeShortcut _nativeShortcut;
bool _registered;
};
uint QHOTKEY_SHARED_EXPORT qHash(const QHotkey::NativeShortcut &key);
uint QHOTKEY_SHARED_EXPORT qHash(const QHotkey::NativeShortcut &key, uint seed);
#endif // QHOTKEY_H

268
3rd_qhotkey/qhotkey_mac.cpp Normal file
View File

@ -0,0 +1,268 @@
#include "qhotkey.h"
#include "qhotkey_p.h"
#include <Carbon/Carbon.h>
#include <QDebug>
class QHotkeyPrivateMac : public QHotkeyPrivate
{
public:
// QAbstractNativeEventFilter interface
bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) Q_DECL_OVERRIDE;
static OSStatus hotkeyEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *data);
protected:
// QHotkeyPrivate interface
quint32 nativeKeycode(Qt::Key keycode, bool &ok) Q_DECL_OVERRIDE;
quint32 nativeModifiers(Qt::KeyboardModifiers modifiers, bool &ok) Q_DECL_OVERRIDE;
bool registerShortcut(QHotkey::NativeShortcut shortcut) Q_DECL_OVERRIDE;
bool unregisterShortcut(QHotkey::NativeShortcut shortcut) Q_DECL_OVERRIDE;
private:
static bool isHotkeyHandlerRegistered;
static QHash<QHotkey::NativeShortcut, EventHotKeyRef> hotkeyRefs;
};
NATIVE_INSTANCE(QHotkeyPrivateMac)
bool QHotkeyPrivateMac::isHotkeyHandlerRegistered = false;
QHash<QHotkey::NativeShortcut, EventHotKeyRef> QHotkeyPrivateMac::hotkeyRefs;
bool QHotkeyPrivateMac::nativeEventFilter(const QByteArray &eventType, void *message, long *result)
{
Q_UNUSED(eventType);
Q_UNUSED(message);
Q_UNUSED(result);
return false;
}
quint32 QHotkeyPrivateMac::nativeKeycode(Qt::Key keycode, bool &ok)
{
// Constants found in NSEvent.h from AppKit.framework
ok = true;
switch (keycode) {
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_Escape:
return kVK_Escape;
case Qt::Key_CapsLock:
return kVK_CapsLock;
case Qt::Key_Option:
return kVK_Option;
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:
ok = false;
break;
}
UTF16Char ch = keycode;
CFDataRef currentLayoutData;
TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
if (currentKeyboard == NULL) {
return 0;
}
currentLayoutData = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
CFRelease(currentKeyboard);
if (currentLayoutData == NULL) {
return 0;
}
UCKeyboardLayout *header = (UCKeyboardLayout *)CFDataGetBytePtr(currentLayoutData);
UCKeyboardTypeHeader *table = header->keyboardTypeList;
uint8_t *data = (uint8_t *)header;
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) {
ok = true;
return k;
}
}
} else if (!(keyToChar[k] & kUCKeyOutputSequenceIndexMask) && keyToChar[k] < 0xFFFE) {
if (keyToChar[k] == ch) {
ok = true;
return k;
}
}
}
}
}
return 0;
}
quint32 QHotkeyPrivateMac::nativeModifiers(Qt::KeyboardModifiers modifiers, bool &ok)
{
quint32 nMods = 0;
if (modifiers & Qt::ShiftModifier) {
nMods |= shiftKey;
}
if (modifiers & Qt::ControlModifier) {
nMods |= cmdKey;
}
if (modifiers & Qt::AltModifier) {
nMods |= optionKey;
}
if (modifiers & Qt::MetaModifier) {
nMods |= controlKey;
}
if (modifiers & Qt::KeypadModifier) {
nMods |= kEventKeyModifierNumLockMask;
}
ok = true;
return nMods;
}
bool QHotkeyPrivateMac::registerShortcut(QHotkey::NativeShortcut shortcut)
{
if (!this->isHotkeyHandlerRegistered) {
EventTypeSpec eventSpec;
eventSpec.eventClass = kEventClassKeyboard;
eventSpec.eventKind = kEventHotKeyPressed;
InstallApplicationEventHandler(&QHotkeyPrivateMac::hotkeyEventHandler, 1, &eventSpec, NULL, NULL);
}
EventHotKeyID hkeyID;
hkeyID.signature = shortcut.key;
hkeyID.id = shortcut.modifier;
EventHotKeyRef eventRef = 0;
OSStatus status = RegisterEventHotKey(shortcut.key,
shortcut.modifier,
hkeyID,
GetApplicationEventTarget(),
0,
&eventRef);
if (status != noErr) {
qDebug() << "Failed to register hotkey. Error:" << status;
return false;
} else {
this->hotkeyRefs.insert(shortcut, eventRef);
return true;
}
}
bool QHotkeyPrivateMac::unregisterShortcut(QHotkey::NativeShortcut shortcut)
{
EventHotKeyRef eventRef = QHotkeyPrivateMac::hotkeyRefs.value(shortcut);
OSStatus status = UnregisterEventHotKey(eventRef);
if (status != noErr) {
qDebug() << "Failed to unregister hotkey. Error:" << status;
return false;
} else {
this->hotkeyRefs.remove(shortcut);
return true;
}
}
OSStatus QHotkeyPrivateMac::hotkeyEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *data)
{
Q_UNUSED(nextHandler);
Q_UNUSED(data);
if (GetEventClass(event) == kEventClassKeyboard &&
GetEventKind(event) == kEventHotKeyPressed) {
EventHotKeyID hkeyID;
GetEventParameter(event,
kEventParamDirectObject,
typeEventHotKeyID,
NULL,
sizeof(EventHotKeyID),
NULL,
&hkeyID);
hotkeyPrivate->activateShortcut(QHotkey::NativeShortcut(hkeyID.signature, hkeyID.id));
}
return noErr;
}

49
3rd_qhotkey/qhotkey_p.h Normal file
View File

@ -0,0 +1,49 @@
#ifndef QHOTKEY_P_H
#define QHOTKEY_P_H
#include "qhotkey.h"
#include <QAbstractNativeEventFilter>
#include <QMultiHash>
#include <QMutex>
#include <QGlobalStatic>
class QHOTKEY_SHARED_EXPORT QHotkeyPrivate : public QObject, public QAbstractNativeEventFilter
{
Q_OBJECT
public: QHotkeyPrivate();//singleton!!!
~QHotkeyPrivate();
static QHotkeyPrivate *instance();
QHotkey::NativeShortcut nativeShortcut(Qt::Key keycode, Qt::KeyboardModifiers modifiers);
bool addShortcut(QHotkey *hotkey);
bool removeShortcut(QHotkey *hotkey);
protected:
void activateShortcut(QHotkey::NativeShortcut shortcut);
virtual quint32 nativeKeycode(Qt::Key keycode, bool &ok) = 0;//platform implement
virtual quint32 nativeModifiers(Qt::KeyboardModifiers modifiers, bool &ok) = 0;//platform implement
virtual bool registerShortcut(QHotkey::NativeShortcut shortcut) = 0;//platform implement
virtual bool unregisterShortcut(QHotkey::NativeShortcut shortcut) = 0;//platform implement
private:
QMultiHash<QHotkey::NativeShortcut, QHotkey *> shortcuts;
Q_INVOKABLE bool addShortcutInvoked(QHotkey *hotkey);
Q_INVOKABLE bool removeShortcutInvoked(QHotkey *hotkey);
Q_INVOKABLE QHotkey::NativeShortcut nativeShortcutInvoked(Qt::Key keycode, Qt::KeyboardModifiers modifiers);
};
#define NATIVE_INSTANCE(ClassName) \
Q_GLOBAL_STATIC(ClassName, hotkeyPrivate) \
\
QHotkeyPrivate *QHotkeyPrivate::instance()\
{\
return hotkeyPrivate;\
}
#endif // QHOTKEY_P_H

274
3rd_qhotkey/qhotkey_win.cpp Normal file
View File

@ -0,0 +1,274 @@
#include "qhotkey.h"
#include "qhotkey_p.h"
#include <qt_windows.h>
#include <QDebug>
#define HKEY_ID(nativeShortcut) (((nativeShortcut.key ^ (nativeShortcut.modifier << 8)) & 0x0FFF) | 0x7000)
class QHotkeyPrivateWin : public QHotkeyPrivate
{
public:
// QAbstractNativeEventFilter interface
bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) Q_DECL_OVERRIDE;
protected:
// QHotkeyPrivate interface
quint32 nativeKeycode(Qt::Key keycode, bool &ok) Q_DECL_OVERRIDE;
quint32 nativeModifiers(Qt::KeyboardModifiers modifiers, bool &ok) Q_DECL_OVERRIDE;
bool registerShortcut(QHotkey::NativeShortcut shortcut) Q_DECL_OVERRIDE;
bool unregisterShortcut(QHotkey::NativeShortcut shortcut) Q_DECL_OVERRIDE;
private:
static QString formatWinError(DWORD winError);
};
NATIVE_INSTANCE(QHotkeyPrivateWin)
bool QHotkeyPrivateWin::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) {
this->activateShortcut(QHotkey::NativeShortcut(HIWORD(msg->lParam), LOWORD(msg->lParam)));
}
return false;
}
quint32 QHotkeyPrivateWin::nativeKeycode(Qt::Key keycode, bool &ok)
{
ok = true;
if (keycode <= 0xFFFF) { //Try to obtain the key from it's "character"
const SHORT vKey = VkKeyScanW(keycode);
if (vKey > -1) {
return LOBYTE(vKey);
}
}
//find key from switch/case --> Only finds a very small subset of keys
switch (keycode) {
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_CapsLock:
return VK_CAPITAL;
case Qt::Key_NumLock:
return VK_NUMLOCK;
case Qt::Key_ScrollLock:
return VK_SCROLL;
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_Menu:
return VK_APPS;
case Qt::Key_Help:
return VK_HELP;
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;
case Qt::Key_VolumeDown:
return VK_VOLUME_DOWN;
case Qt::Key_VolumeUp:
return VK_VOLUME_UP;
case Qt::Key_VolumeMute:
return VK_VOLUME_MUTE;
case Qt::Key_Mode_switch:
return VK_MODECHANGE;
case Qt::Key_Select:
return VK_SELECT;
case Qt::Key_Printer:
return VK_PRINT;
case Qt::Key_Execute:
return VK_EXECUTE;
case Qt::Key_Sleep:
return VK_SLEEP;
case Qt::Key_Period:
return VK_DECIMAL;
case Qt::Key_Play:
return VK_PLAY;
case Qt::Key_Cancel:
return VK_CANCEL;
case Qt::Key_Forward:
return VK_BROWSER_FORWARD;
case Qt::Key_Refresh:
return VK_BROWSER_REFRESH;
case Qt::Key_Stop:
return VK_BROWSER_STOP;
case Qt::Key_Search:
return VK_BROWSER_SEARCH;
case Qt::Key_Favorites:
return VK_BROWSER_FAVORITES;
case Qt::Key_HomePage:
return VK_BROWSER_HOME;
case Qt::Key_LaunchMail:
return VK_LAUNCH_MAIL;
case Qt::Key_LaunchMedia:
return VK_LAUNCH_MEDIA_SELECT;
case Qt::Key_Launch0:
return VK_LAUNCH_APP1;
case Qt::Key_Launch1:
return VK_LAUNCH_APP2;
case Qt::Key_Massyo:
return VK_OEM_FJ_MASSHOU;
case Qt::Key_Touroku:
return VK_OEM_FJ_TOUROKU;
default:
ok = false;
return 0;
}
}
quint32 QHotkeyPrivateWin::nativeModifiers(Qt::KeyboardModifiers modifiers, bool &ok)
{
quint32 nMods = 0;
if (modifiers & Qt::ShiftModifier) {
nMods |= MOD_SHIFT;
}
if (modifiers & Qt::ControlModifier) {
nMods |= MOD_CONTROL;
}
if (modifiers & Qt::AltModifier) {
nMods |= MOD_ALT;
}
if (modifiers & Qt::MetaModifier) {
nMods |= MOD_WIN;
}
ok = true;
return nMods;
}
bool QHotkeyPrivateWin::registerShortcut(QHotkey::NativeShortcut shortcut)
{
BOOL ok = RegisterHotKey(NULL,
HKEY_ID(shortcut),
shortcut.modifier,
shortcut.key);
if (ok) {
return true;
} else {
qDebug() << "Failed to register hotkey. Error:"
<< qPrintable(QHotkeyPrivateWin::formatWinError(::GetLastError()));
return false;
}
}
bool QHotkeyPrivateWin::unregisterShortcut(QHotkey::NativeShortcut shortcut)
{
BOOL ok = UnregisterHotKey(NULL, HKEY_ID(shortcut));
if (ok) {
return true;
} else {
qDebug() << "Failed to unregister hotkey. Error:"
<< qPrintable(QHotkeyPrivateWin::formatWinError(::GetLastError()));
return false;
}
}
QString QHotkeyPrivateWin::formatWinError(DWORD winError)
{
wchar_t *buffer = NULL;
DWORD num = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
winError,
0,
(LPWSTR)&buffer,
0,
NULL);
if (buffer) {
QString res = QString::fromWCharArray(buffer, num);
LocalFree(buffer);
return res;
} else {
return QString();
}
}

201
3rd_qhotkey/qhotkey_x11.cpp Normal file
View File

@ -0,0 +1,201 @@
#include "qhotkey.h"
#include "qhotkey_p.h"
#include <QDebug>
#include <QX11Info>
#include <QThreadStorage>
#include <X11/Xlib.h>
#include <xcb/xcb.h>
class QHotkeyPrivateX11 : public QHotkeyPrivate
{
public:
// QAbstractNativeEventFilter interface
bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) Q_DECL_OVERRIDE;
protected:
// QHotkeyPrivate interface
quint32 nativeKeycode(Qt::Key keycode, bool &ok) Q_DECL_OVERRIDE;
quint32 nativeModifiers(Qt::KeyboardModifiers modifiers, bool &ok) Q_DECL_OVERRIDE;
bool registerShortcut(QHotkey::NativeShortcut shortcut) Q_DECL_OVERRIDE;
bool unregisterShortcut(QHotkey::NativeShortcut shortcut) Q_DECL_OVERRIDE;
private:
static const QVector<quint32> specialModifiers;
static const quint32 validModsMask;
static QString formatX11Error(Display *display, int errorCode);
class HotkeyErrorHandler
{
public:
HotkeyErrorHandler();
~HotkeyErrorHandler();
static bool hasError;
static QString errorString;
private:
XErrorHandler prevHandler;
static int handleError(Display *display, XErrorEvent *error);
};
};
NATIVE_INSTANCE(QHotkeyPrivateX11)
const QVector<quint32> QHotkeyPrivateX11::specialModifiers = {0, Mod2Mask, LockMask, (Mod2Mask | LockMask)};
const quint32 QHotkeyPrivateX11::validModsMask = ShiftMask | ControlMask | Mod1Mask | Mod4Mask;
bool QHotkeyPrivateX11::nativeEventFilter(const QByteArray &eventType, void *message, long *result)
{
Q_UNUSED(eventType);
Q_UNUSED(result);
xcb_generic_event_t *genericEvent = static_cast<xcb_generic_event_t *>(message);
if (genericEvent->response_type == XCB_KEY_PRESS) {
xcb_key_press_event_t *keyEvent = static_cast<xcb_key_press_event_t *>(message);
this->activateShortcut(QHotkey::NativeShortcut(keyEvent->detail, keyEvent->state & QHotkeyPrivateX11::validModsMask));
}
return false;
}
quint32 QHotkeyPrivateX11::nativeKeycode(Qt::Key keycode, bool &ok)
{
KeySym keysym = XStringToKeysym(QKeySequence(keycode).toString(QKeySequence::NativeText).toLatin1().constData());
if (keysym == NoSymbol) {
//not found -> just use the key
if (keycode <= 0xFFFF) {
keysym = keycode;
} else {
return 0;
}
}
Display *display = QX11Info::display();
if (display) {
auto res = XKeysymToKeycode(QX11Info::display(), keysym);
if (res != 0) {
ok = true;
}
return res;
} else {
return 0;
}
}
quint32 QHotkeyPrivateX11::nativeModifiers(Qt::KeyboardModifiers modifiers, bool &ok)
{
quint32 nMods = 0;
if (modifiers & Qt::ShiftModifier) {
nMods |= ShiftMask;
}
if (modifiers & Qt::ControlModifier) {
nMods |= ControlMask;
}
if (modifiers & Qt::AltModifier) {
nMods |= Mod1Mask;
}
if (modifiers & Qt::MetaModifier) {
nMods |= Mod4Mask;
}
ok = true;
return nMods;
}
bool QHotkeyPrivateX11::registerShortcut(QHotkey::NativeShortcut shortcut)
{
Display *display = QX11Info::display();
if (!display) {
return false;
}
HotkeyErrorHandler errorHandler;
foreach (quint32 specialMod, QHotkeyPrivateX11::specialModifiers) {
XGrabKey(display,
shortcut.key,
shortcut.modifier | specialMod,
DefaultRootWindow(display),
True,
GrabModeAsync,
GrabModeAsync);
}
XSync(display, False);
if (errorHandler.hasError) {
qDebug() << "Failed to register hotkey. Error:" << qPrintable(errorHandler.errorString);
this->unregisterShortcut(shortcut);
return false;
} else {
return true;
}
}
bool QHotkeyPrivateX11::unregisterShortcut(QHotkey::NativeShortcut shortcut)
{
Display *display = QX11Info::display();
if (!display) {
return false;
}
HotkeyErrorHandler errorHandler;
foreach (quint32 specialMod, QHotkeyPrivateX11::specialModifiers) {
XUngrabKey(display,
shortcut.key,
shortcut.modifier | specialMod,
DefaultRootWindow(display));
}
XSync(display, False);
if (errorHandler.hasError) {
qDebug() << "Failed to unregister hotkey. Error:" << qPrintable(errorHandler.errorString);
return false;
} else {
return true;
}
}
QString QHotkeyPrivateX11::formatX11Error(Display *display, int errorCode)
{
char errStr[256];
XGetErrorText(display, errorCode, errStr, 256);
return QString::fromLatin1(errStr);
}
// ---------- QHotkeyPrivateX11::HotkeyErrorHandler implementation ----------
bool QHotkeyPrivateX11::HotkeyErrorHandler::hasError = false;
QString QHotkeyPrivateX11::HotkeyErrorHandler::errorString;
QHotkeyPrivateX11::HotkeyErrorHandler::HotkeyErrorHandler()
{
prevHandler = XSetErrorHandler(&HotkeyErrorHandler::handleError);
}
QHotkeyPrivateX11::HotkeyErrorHandler::~HotkeyErrorHandler()
{
XSetErrorHandler(prevHandler);
hasError = false;
errorString.clear();
}
int QHotkeyPrivateX11::HotkeyErrorHandler::handleError(Display *display, XErrorEvent *error)
{
QT_WARNING_PUSH
QT_WARNING_DISABLE_GCC("-Wimplicit-fallthrough")
switch (error->error_code) {
case BadAccess:
case BadValue:
case BadWindow:
if (error->request_code == 33 || //grab key
error->request_code == 34) {// ungrab key
hasError = true;
errorString = QHotkeyPrivateX11::formatX11Error(display, error->error_code);
return 1;
}
default:
return 0;
}
QT_WARNING_POP
}

View File

@ -0,0 +1,29 @@
DEFINES += BUILD_QXT_CORE BUILD_QXT_GUI
HEADERS += $$PWD/qxtglobal.h
HEADERS += $$PWD/qxtglobalshortcut_p.h
HEADERS += $$PWD/qxtglobalshortcut.h
SOURCES += $$PWD/qxtglobal.cpp
SOURCES += $$PWD/qxtglobalshortcut.cpp
unix:!macx {
CONFIG += X11
QT += x11extras
HEADERS += $$PWD/x11info.h
SOURCES += $$PWD/qxtwindowsystem_x11.cpp
SOURCES += $$PWD/qxtglobalshortcut_x11.cpp
}
macx {
QMAKE_LFLAGS += -framework Carbon -framework CoreFoundation
HEADERS += $$PWD/qxtwindowsystem_mac.h
SOURCES += $$PWD/qxtwindowsystem_mac.cpp
SOURCES += $$PWD/qxtglobalshortcut_mac.cpp
}
win32 {
LIBS += -luser32
SOURCES += $$PWD/qxtwindowsystem_win.cpp
SOURCES += $$PWD/qxtglobalshortcut_win.cpp
}

View File

@ -0,0 +1,251 @@
/****************************************************************************
** Copyright (c) 2006 - 2011, the LibQxt project.
** See the Qxt AUTHORS file for a list of authors and copyright holders.
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** * Neither the name of the LibQxt project nor the
** names of its contributors may be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
** <http://libqxt.org> <foundation@libqxt.org>
*****************************************************************************/
#include "qxtglobal.h"
/*!
\headerfile <QxtGlobal>
\title Global Qxt Declarations
\inmodule QxtCore
\brief The <QxtGlobal> header provides basic declarations and
is included by all other Qxt headers.
*/
/*!
\macro QXT_VERSION
\relates <QxtGlobal>
This macro expands a numeric value of the form 0xMMNNPP (MM =
major, NN = minor, PP = patch) that specifies Qxt's version
number. For example, if you compile your application against Qxt
0.4.0, the QXT_VERSION macro will expand to 0x000400.
You can use QXT_VERSION to use the latest Qt features where
available. For example:
\code
#if QXT_VERSION >= 0x000400
qxtTabWidget->setTabMovementMode(QxtTabWidget::InPlaceMovement);
#endif
\endcode
\sa QXT_VERSION_STR, qxtVersion()
*/
/*!
\macro QXT_VERSION_STR
\relates <QxtGlobal>
This macro expands to a string that specifies Qxt's version number
(for example, "0.4.0"). This is the version against which the
application is compiled.
\sa qxtVersion(), QXT_VERSION
*/
/*!
\relates <QxtGlobal>
Returns the version number of Qxt at run-time as a string (for
example, "0.4.0"). This may be a different version than the
version the application was compiled against.
\sa QXT_VERSION_STR
*/
const char * qxtVersion()
{
return QXT_VERSION_STR;
}
/*!
\headerfile <QxtPimpl>
\title The Qxt private implementation
\inmodule QxtCore
\brief The <QxtPimpl> header provides tools for hiding
details of a class.
Application code generally doesn't have to be concerned about hiding its
implementation details, but when writing library code it is important to
maintain a constant interface, both source and binary. Maintaining a constant
source interface is easy enough, but keeping the binary interface constant
means moving implementation details into a private class. The PIMPL, or
d-pointer, idiom is a common method of implementing this separation. QxtPimpl
offers a convenient way to connect the public and private sides of your class.
\section1 Getting Started
Before you declare the public class, you need to make a forward declaration
of the private class. The private class must have the same name as the public
class, followed by the word Private. For example, a class named MyTest would
declare the private class with:
\code
class MyTestPrivate;
\endcode
\section1 The Public Class
Generally, you shouldn't keep any data members in the public class without a
good reason. Functions that are part of the public interface should be declared
in the public class, and functions that need to be available to subclasses (for
calling or overriding) should be in the protected section of the public class.
To connect the private class to the public class, include the
QXT_DECLARE_PRIVATE macro in the private section of the public class. In the
example above, the private class is connected as follows:
\code
private:
QXT_DECLARE_PRIVATE(MyTest)
\endcode
Additionally, you must include the QXT_INIT_PRIVATE macro in the public class's
constructor. Continuing with the MyTest example, your constructor might look
like this:
\code
MyTest::MyTest() {
// initialization
QXT_INIT_PRIVATE(MyTest);
}
\endcode
\section1 The Private Class
As mentioned above, data members should usually be kept in the private class.
This allows the memory layout of the private class to change without breaking
binary compatibility for the public class. Functions that exist only as
implementation details, or functions that need access to private data members,
should be implemented here.
To define the private class, inherit from the template QxtPrivate class, and
include the QXT_DECLARE_PUBLIC macro in its public section. The template
parameter should be the name of the public class. For example:
\code
class MyTestPrivate : public QxtPrivate<MyTest> {
public:
MyTestPrivate();
QXT_DECLARE_PUBLIC(MyTest)
};
\endcode
\section1 Accessing Private Members
Use the qxt_d() function (actually a function-like object) from functions in
the public class to access the private class. Similarly, functions in the
private class can invoke functions in the public class by using the qxt_p()
function (this one's actually a function).
For example, assume that MyTest has methods named getFoobar and doBaz(),
and MyTestPrivate has a member named foobar and a method named doQuux().
The code might resemble this example:
\code
int MyTest::getFoobar() {
return qxt_d().foobar;
}
void MyTestPrivate::doQuux() {
qxt_p().doBaz(foobar);
}
\endcode
*/
/*!
* \macro QXT_DECLARE_PRIVATE(PUB)
* \relates <QxtPimpl>
* Declares that a public class has a related private class.
*
* This shuold be put in the private section of the public class. The
* parameter \a PUB must be the name of the public class.
*/
/*!
* \macro QXT_DECLARE_PUBLIC(PUB)
* \relates <QxtPimpl>
* Declares that a private class has a related public class named \a PUB.
*
* This may be put anywhere in the declaration of the private class. The parameter is the name of the public class.
*/
/*!
* \macro QXT_INIT_PRIVATE(PUB)
* \relates <QxtPimpl>
* Initializes resources owned by the private class.
*
* This should be called from the public class's constructor,
* before qxt_d() is used for the first time. The parameter \a PUB must be
* the name of the public class.
*/
/*!
* \macro QXT_D(PUB)
* \relates <QxtPimpl>
* Returns a reference in the current scope named "d" to the private class
* associated with the public class \a PUB.
*
* This function is only available in a class using QXT_DECLARE_PRIVATE().
*/
/*!
* \macro QXT_P(PUB)
* \relates <QxtPimpl>
* Creates a reference in the current scope named "q" to the public class
* named \a PUB.
*
* This macro only works in a class using QXT_DECLARE_PUBLIC().
*/
/*!
* \fn QxtPrivate<PUB>& PUB::qxt_d()
* \relates <QxtPimpl>
* Returns a reference to the private class.
*
* This function is only available in a class using \a QXT_DECLARE_PRIVATE.
*/
/*!
* \fn const QxtPrivate<PUB>& PUB::qxt_d() const
* \relates <QxtPimpl>
* Returns a const reference to the private class.
*
* This function is only available in a class using \a QXT_DECLARE_PRIVATE.
* This overload will be automatically used in const functions.
*/
/*!
* \fn PUB& QxtPrivate::qxt_p()
* \relates <QxtPimpl>
* Returns a reference to the public class.
*
* This function is only available in a class using QXT_DECLARE_PUBLIC().
*/
/*!
* \fn const PUB& QxtPrivate::qxt_p() const
* \relates <QxtPimpl>
* Returns a const reference to the public class.
*
* This function is only available in a class using QXT_DECLARE_PUBLIC().
* This overload will be automatically used in const functions.
*/

View File

@ -0,0 +1,229 @@
/****************************************************************************
** Copyright (c) 2006 - 2011, the LibQxt project.
** See the Qxt AUTHORS file for a list of authors and copyright holders.
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** * Neither the name of the LibQxt project nor the
** names of its contributors may be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
** <http://libqxt.org> <foundation@libqxt.org>
*****************************************************************************/
#ifndef QXTGLOBAL_H
#define QXTGLOBAL_H
#include <QtGlobal>
#define QXT_VERSION 0x000700
#define QXT_VERSION_STR "0.7.0"
//--------------------------global macros------------------------------
#ifndef QXT_NO_MACROS
#endif // QXT_NO_MACROS
//--------------------------export macros------------------------------
#define QXT_DLLEXPORT DO_NOT_USE_THIS_ANYMORE
#if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN)
# if defined(BUILD_QXT_CORE)
# define QXT_CORE_EXPORT Q_DECL_EXPORT
# else
# define QXT_CORE_EXPORT Q_DECL_IMPORT
# endif
#else
# define QXT_CORE_EXPORT
#endif // BUILD_QXT_CORE
#if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN)
# if defined(BUILD_QXT_GUI)
# define QXT_GUI_EXPORT Q_DECL_EXPORT
# else
# define QXT_GUI_EXPORT Q_DECL_IMPORT
# endif
#else
# define QXT_GUI_EXPORT
#endif // BUILD_QXT_GUI
#if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN)
# if defined(BUILD_QXT_NETWORK)
# define QXT_NETWORK_EXPORT Q_DECL_EXPORT
# else
# define QXT_NETWORK_EXPORT Q_DECL_IMPORT
# endif
#else
# define QXT_NETWORK_EXPORT
#endif // BUILD_QXT_NETWORK
#if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN)
# if defined(BUILD_QXT_SQL)
# define QXT_SQL_EXPORT Q_DECL_EXPORT
# else
# define QXT_SQL_EXPORT Q_DECL_IMPORT
# endif
#else
# define QXT_SQL_EXPORT
#endif // BUILD_QXT_SQL
#if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN)
# if defined(BUILD_QXT_WEB)
# define QXT_WEB_EXPORT Q_DECL_EXPORT
# else
# define QXT_WEB_EXPORT Q_DECL_IMPORT
# endif
#else
# define QXT_WEB_EXPORT
#endif // BUILD_QXT_WEB
#if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN)
# if defined(BUILD_QXT_BERKELEY)
# define QXT_BERKELEY_EXPORT Q_DECL_EXPORT
# else
# define QXT_BERKELEY_EXPORT Q_DECL_IMPORT
# endif
#else
# define QXT_BERKELEY_EXPORT
#endif // BUILD_QXT_BERKELEY
#if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN)
# if defined(BUILD_QXT_ZEROCONF)
# define QXT_ZEROCONF_EXPORT Q_DECL_EXPORT
# else
# define QXT_ZEROCONF_EXPORT Q_DECL_IMPORT
# endif
#else
# define QXT_ZEROCONF_EXPORT
#endif // QXT_ZEROCONF_EXPORT
#if defined(BUILD_QXT_CORE) || defined(BUILD_QXT_GUI) || defined(BUILD_QXT_SQL) || defined(BUILD_QXT_NETWORK) || defined(BUILD_QXT_WEB) || defined(BUILD_QXT_BERKELEY) || defined(BUILD_QXT_ZEROCONF)
# define BUILD_QXT
#endif
QXT_CORE_EXPORT const char* qxtVersion();
#ifndef QT_BEGIN_NAMESPACE
#define QT_BEGIN_NAMESPACE
#endif
#ifndef QT_END_NAMESPACE
#define QT_END_NAMESPACE
#endif
#ifndef QT_FORWARD_DECLARE_CLASS
#define QT_FORWARD_DECLARE_CLASS(Class) class Class;
#endif
/****************************************************************************
** This file is derived from code bearing the following notice:
** The sole author of this file, Adam Higerd, has explicitly disclaimed all
** copyright interest and protection for the content within. This file has
** been placed in the public domain according to United States copyright
** statute and case law. In jurisdictions where this public domain dedication
** is not legally recognized, anyone who receives a copy of this file is
** permitted to use, modify, duplicate, and redistribute this file, in whole
** or in part, with no restrictions or conditions. In these jurisdictions,
** this file shall be copyright (C) 2006-2008 by Adam Higerd.
****************************************************************************/
#define QXT_DECLARE_PRIVATE(PUB) friend class PUB##Private; QxtPrivateInterface<PUB, PUB##Private> qxt_d;
#define QXT_DECLARE_PUBLIC(PUB) friend class PUB;
#define QXT_INIT_PRIVATE(PUB) qxt_d.setPublic(this);
#define QXT_D(PUB) PUB##Private& d = qxt_d()
#define QXT_P(PUB) PUB& p = qxt_p()
template <typename PUB>
class QxtPrivate
{
public:
virtual ~QxtPrivate()
{}
inline void QXT_setPublic(PUB* pub)
{
qxt_p_ptr = pub;
}
protected:
inline PUB& qxt_p()
{
return *qxt_p_ptr;
}
inline const PUB& qxt_p() const
{
return *qxt_p_ptr;
}
inline PUB* qxt_ptr()
{
return qxt_p_ptr;
}
inline const PUB* qxt_ptr() const
{
return qxt_p_ptr;
}
private:
PUB* qxt_p_ptr;
};
template <typename PUB, typename PVT>
class QxtPrivateInterface
{
friend class QxtPrivate<PUB>;
public:
QxtPrivateInterface()
{
pvt = new PVT;
}
~QxtPrivateInterface()
{
delete pvt;
}
inline void setPublic(PUB* pub)
{
pvt->QXT_setPublic(pub);
}
inline PVT& operator()()
{
return *static_cast<PVT*>(pvt);
}
inline const PVT& operator()() const
{
return *static_cast<PVT*>(pvt);
}
inline PVT * operator->()
{
return static_cast<PVT*>(pvt);
}
inline const PVT * operator->() const
{
return static_cast<PVT*>(pvt);
}
private:
QxtPrivateInterface(const QxtPrivateInterface&) { }
QxtPrivateInterface& operator=(const QxtPrivateInterface&) { }
QxtPrivate<PUB>* pvt;
};
#endif // QXT_GLOBAL

View File

@ -0,0 +1,223 @@
#include "qxtglobalshortcut.h"
/****************************************************************************
** Copyright (c) 2006 - 2011, the LibQxt project.
** See the Qxt AUTHORS file for a list of authors and copyright holders.
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** * Neither the name of the LibQxt project nor the
** names of its contributors may be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
** <http://libqxt.org> <foundation@libqxt.org>
*****************************************************************************/
#include "qxtglobalshortcut_p.h"
#include <QAbstractEventDispatcher>
#include <QtDebug>
#ifndef Q_OS_MAC
int QxtGlobalShortcutPrivate::ref = 0;
# if QT_VERSION < QT_VERSION_CHECK(5,0,0)
QAbstractEventDispatcher::EventFilter QxtGlobalShortcutPrivate::prevEventFilter = 0;
# endif
#endif // Q_OS_MAC
QHash<QPair<quint32, quint32>, QxtGlobalShortcut*> QxtGlobalShortcutPrivate::shortcuts;
QxtGlobalShortcutPrivate::QxtGlobalShortcutPrivate() : enabled(true), key(Qt::Key(0)), mods(Qt::NoModifier)
{
#ifndef Q_OS_MAC
if (ref == 0) {
# if QT_VERSION < QT_VERSION_CHECK(5,0,0)
prevEventFilter = QAbstractEventDispatcher::instance()->setEventFilter(eventFilter);
# else
QAbstractEventDispatcher::instance()->installNativeEventFilter(this);
#endif
}
++ref;
#endif // Q_OS_MAC
}
QxtGlobalShortcutPrivate::~QxtGlobalShortcutPrivate()
{
#ifndef Q_OS_MAC
--ref;
if (ref == 0) {
QAbstractEventDispatcher *ed = QAbstractEventDispatcher::instance();
if (ed != 0) {
# if QT_VERSION < QT_VERSION_CHECK(5,0,0)
ed->setEventFilter(prevEventFilter);
# else
ed->removeNativeEventFilter(this);
# endif
}
}
#endif // Q_OS_MAC
}
bool QxtGlobalShortcutPrivate::setShortcut(const QKeySequence& shortcut)
{
Qt::KeyboardModifiers allMods = Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier;
key = shortcut.isEmpty() ? Qt::Key(0) : Qt::Key((shortcut[0] ^ allMods) & shortcut[0]);
mods = shortcut.isEmpty() ? Qt::KeyboardModifiers(0) : Qt::KeyboardModifiers(shortcut[0] & allMods);
const quint32 nativeKey = nativeKeycode(key);
const quint32 nativeMods = nativeModifiers(mods);
const bool res = registerShortcut(nativeKey, nativeMods);
if (res)
shortcuts.insert(qMakePair(nativeKey, nativeMods), &qxt_p());
else
qWarning() << "QxtGlobalShortcut failed to register:" << QKeySequence(key + mods).toString();
return res;
}
bool QxtGlobalShortcutPrivate::unsetShortcut()
{
bool res = false;
const quint32 nativeKey = nativeKeycode(key);
const quint32 nativeMods = nativeModifiers(mods);
if (shortcuts.value(qMakePair(nativeKey, nativeMods)) == &qxt_p())
res = unregisterShortcut(nativeKey, nativeMods);
if (res)
shortcuts.remove(qMakePair(nativeKey, nativeMods));
else
qWarning() << "QxtGlobalShortcut failed to unregister:" << QKeySequence(key + mods).toString();
key = Qt::Key(0);
mods = Qt::KeyboardModifiers(0);
return res;
}
void QxtGlobalShortcutPrivate::activateShortcut(quint32 nativeKey, quint32 nativeMods)
{
QxtGlobalShortcut* shortcut = shortcuts.value(qMakePair(nativeKey, nativeMods));
if (shortcut && shortcut->isEnabled())
emit shortcut->activated();
}
/*!
\class QxtGlobalShortcut
\inmodule QxtWidgets
\brief The QxtGlobalShortcut class provides a global shortcut aka "hotkey".
A global shortcut triggers even if the application is not active. This
makes it easy to implement applications that react to certain shortcuts
still if some other application is active or if the application is for
example minimized to the system tray.
Example usage:
\code
QxtGlobalShortcut* shortcut = new QxtGlobalShortcut(window);
connect(shortcut, SIGNAL(activated()), window, SLOT(toggleVisibility()));
shortcut->setShortcut(QKeySequence("Ctrl+Shift+F12"));
\endcode
\bold {Note:} Since Qxt 0.6 QxtGlobalShortcut no more requires QxtApplication.
*/
/*!
\fn QxtGlobalShortcut::activated()
This signal is emitted when the user types the shortcut's key sequence.
\sa shortcut
*/
/*!
Constructs a new QxtGlobalShortcut with \a parent.
*/
QxtGlobalShortcut::QxtGlobalShortcut(QObject* parent)
: QObject(parent)
{
QXT_INIT_PRIVATE(QxtGlobalShortcut);
}
/*!
Constructs a new QxtGlobalShortcut with \a shortcut and \a parent.
*/
QxtGlobalShortcut::QxtGlobalShortcut(const QKeySequence& shortcut, QObject* parent)
: QObject(parent)
{
QXT_INIT_PRIVATE(QxtGlobalShortcut);
setShortcut(shortcut);
}
/*!
Destructs the QxtGlobalShortcut.
*/
QxtGlobalShortcut::~QxtGlobalShortcut()
{
if (qxt_d().key != 0)
qxt_d().unsetShortcut();
}
/*!
\property QxtGlobalShortcut::shortcut
\brief the shortcut key sequence
\bold {Note:} Notice that corresponding key press and release events are not
delivered for registered global shortcuts even if they are disabled.
Also, comma separated key sequences are not supported.
Only the first part is used:
\code
qxtShortcut->setShortcut(QKeySequence("Ctrl+Alt+A,Ctrl+Alt+B"));
Q_ASSERT(qxtShortcut->shortcut() == QKeySequence("Ctrl+Alt+A"));
\endcode
*/
QKeySequence QxtGlobalShortcut::shortcut() const
{
return QKeySequence(qxt_d().key | qxt_d().mods);
}
bool QxtGlobalShortcut::setShortcut(const QKeySequence& shortcut)
{
if (qxt_d().key != 0)
qxt_d().unsetShortcut();
return qxt_d().setShortcut(shortcut);
}
/*!
\property QxtGlobalShortcut::enabled
\brief whether the shortcut is enabled
A disabled shortcut does not get activated.
The default value is \c true.
\sa setDisabled()
*/
bool QxtGlobalShortcut::isEnabled() const
{
return qxt_d().enabled;
}
void QxtGlobalShortcut::setEnabled(bool enabled)
{
qxt_d().enabled = enabled;
}
/*!
Sets the shortcut \a disabled.
\sa enabled
*/
void QxtGlobalShortcut::setDisabled(bool disabled)
{
qxt_d().enabled = !disabled;
}

View File

@ -0,0 +1,64 @@
#ifndef QXTGLOBALSHORTCUT_H
/****************************************************************************
** Copyright (c) 2006 - 2011, the LibQxt project.
** See the Qxt AUTHORS file for a list of authors and copyright holders.
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** * Neither the name of the LibQxt project nor the
** names of its contributors may be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
** <http://libqxt.org> <foundation@libqxt.org>
*****************************************************************************/
#define QXTGLOBALSHORTCUT_H
#include "qxtglobal.h"
#include <QObject>
#include <QKeySequence>
class QxtGlobalShortcutPrivate;
class QXT_GUI_EXPORT QxtGlobalShortcut : public QObject
{
Q_OBJECT
QXT_DECLARE_PRIVATE(QxtGlobalShortcut)
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled)
Q_PROPERTY(QKeySequence shortcut READ shortcut WRITE setShortcut)
public:
explicit QxtGlobalShortcut(QObject* parent = 0);
explicit QxtGlobalShortcut(const QKeySequence& shortcut, QObject* parent = 0);
virtual ~QxtGlobalShortcut();
QKeySequence shortcut() const;
bool setShortcut(const QKeySequence& shortcut);
bool isEnabled() const;
public Q_SLOTS:
void setEnabled(bool enabled = true);
void setDisabled(bool disabled = true);
Q_SIGNALS:
void activated();
};
#endif // QXTGLOBALSHORTCUT_H

View File

@ -0,0 +1,258 @@
#include <Carbon/Carbon.h>
/****************************************************************************
** Copyright (c) 2006 - 2011, the LibQxt project.
** See the Qxt AUTHORS file for a list of authors and copyright holders.
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** * Neither the name of the LibQxt project nor the
** names of its contributors may be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
** <http://libqxt.org> <foundation@libqxt.org>
*****************************************************************************/
#include "qxtglobalshortcut_p.h"
#include <QMap>
#include <QHash>
#include <QtDebug>
#include <QApplication>
typedef QPair<uint, uint> Identifier;
static QMap<quint32, EventHotKeyRef> keyRefs;
static QHash<Identifier, quint32> keyIDs;
static quint32 hotKeySerial = 0;
static bool qxt_mac_handler_installed = false;
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, NULL, sizeof(keyID), NULL, &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 == NULL)
return 0;
currentLayoutData = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
CFRelease(currentKeyboard);
if (currentLayoutData == NULL)
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, NULL, NULL);
}
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);
}

View File

@ -0,0 +1,84 @@
#ifndef QXTGLOBALSHORTCUT_P_H
/****************************************************************************
** Copyright (c) 2006 - 2011, the LibQxt project.
** See the Qxt AUTHORS file for a list of authors and copyright holders.
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** * Neither the name of the LibQxt project nor the
** names of its contributors may be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
** <http://libqxt.org> <foundation@libqxt.org>
*****************************************************************************/
#define QXTGLOBALSHORTCUT_P_H
#include "qxtglobalshortcut.h"
#include <QAbstractEventDispatcher>
#include <QKeySequence>
#include <QHash>
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
#include <QAbstractNativeEventFilter>
#endif
class QxtGlobalShortcutPrivate : public QxtPrivate<QxtGlobalShortcut>
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) && !defined(Q_OS_MAC)
,public QAbstractNativeEventFilter
#endif
{
public:
QXT_DECLARE_PUBLIC(QxtGlobalShortcut)
QxtGlobalShortcutPrivate();
~QxtGlobalShortcutPrivate();
bool enabled;
Qt::Key key;
Qt::KeyboardModifiers mods;
bool setShortcut(const QKeySequence& shortcut);
bool unsetShortcut();
static bool error;
#ifndef Q_OS_MAC
static int ref;
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
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
static void activateShortcut(quint32 nativeKey, quint32 nativeMods);
private:
static quint32 nativeKeycode(Qt::Key keycode);
static quint32 nativeModifiers(Qt::KeyboardModifiers modifiers);
static bool registerShortcut(quint32 nativeKey, quint32 nativeMods);
static bool unregisterShortcut(quint32 nativeKey, quint32 nativeMods);
static QHash<QPair<quint32, quint32>, QxtGlobalShortcut*> shortcuts;
};
#endif // QXTGLOBALSHORTCUT_P_H

View File

@ -0,0 +1,252 @@
#include "qxtglobalshortcut_p.h"
/****************************************************************************
** Copyright (c) 2006 - 2011, the LibQxt project.
** See the Qxt AUTHORS file for a list of authors and copyright holders.
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** * Neither the name of the LibQxt project nor the
** names of its contributors may be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
** <http://libqxt.org> <foundation@libqxt.org>
*****************************************************************************/
#include <qt_windows.h>
#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);
}
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
return prevEventFilter ? prevEventFilter(message) : false;
#else
return false;
#endif
}
quint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers)
{
// MOD_ALT, MOD_CONTROL, (MOD_KEYUP), MOD_SHIFT, MOD_WIN
quint32 native = 0;
if (modifiers & Qt::ShiftModifier)
native |= MOD_SHIFT;
if (modifiers & Qt::ControlModifier)
native |= MOD_CONTROL;
if (modifiers & Qt::AltModifier)
native |= MOD_ALT;
if (modifiers & Qt::MetaModifier)
native |= MOD_WIN;
// TODO: resolve these?
//if (modifiers & Qt::KeypadModifier)
//if (modifiers & Qt::GroupSwitchModifier)
return native;
}
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
case Qt::Key_0:
case Qt::Key_1:
case Qt::Key_2:
case Qt::Key_3:
case Qt::Key_4:
case Qt::Key_5:
case Qt::Key_6:
case Qt::Key_7:
case Qt::Key_8:
case Qt::Key_9:
return key;
// letters
case Qt::Key_A:
case Qt::Key_B:
case Qt::Key_C:
case Qt::Key_D:
case Qt::Key_E:
case Qt::Key_F:
case Qt::Key_G:
case Qt::Key_H:
case Qt::Key_I:
case Qt::Key_J:
case Qt::Key_K:
case Qt::Key_L:
case Qt::Key_M:
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;
}
}
bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods)
{
return RegisterHotKey(0, nativeMods ^ nativeKey, nativeMods, nativeKey);
}
bool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods)
{
return UnregisterHotKey(0, nativeMods ^ nativeKey);
}

View File

@ -0,0 +1,241 @@
#include "qxtglobalshortcut_p.h"
/****************************************************************************
** Copyright (c) 2006 - 2011, the LibQxt project.
** See the Qxt AUTHORS file for a list of authors and copyright holders.
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** * Neither the name of the LibQxt project nor the
** names of its contributors may be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
** <http://libqxt.org> <foundation@libqxt.org>
*****************************************************************************/
#include <QVector>
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
# include <QX11Info>
#else
# include <QApplication>
//# include <qpa/qplatformnativeinterface.h>
# include <xcb/xcb.h>
#endif
#include <X11/Xlib.h>
#include "QX11Info"
namespace {
const QVector<quint32> maskModifiers = QVector<quint32>()
<< 0 << Mod2Mask << LockMask << (Mod2Mask | LockMask);
typedef int (*X11ErrorHandler)(Display *display, XErrorEvent *event);
class QxtX11ErrorHandler {
public:
static bool error;
static int qxtX11ErrorHandler(Display *display, XErrorEvent *event)
{
Q_UNUSED(display);
switch (event->error_code)
{
case BadAccess:
case BadValue:
case BadWindow:
if (event->request_code == 33 /* X_GrabKey */ ||
event->request_code == 34 /* X_UngrabKey */)
{
error = true;
//TODO:
//char errstr[256];
//XGetErrorText(dpy, err->error_code, errstr, 256);
}
}
return 0;
}
QxtX11ErrorHandler()
{
error = false;
m_previousErrorHandler = XSetErrorHandler(qxtX11ErrorHandler);
}
~QxtX11ErrorHandler()
{
XSetErrorHandler(m_previousErrorHandler);
}
private:
X11ErrorHandler m_previousErrorHandler;
};
bool QxtX11ErrorHandler::error = false;
class QxtX11Data {
public:
QxtX11Data()
{
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
m_display = QX11Info::display();
#else
m_display = QX11Info::display();
#endif
}
bool isValid()
{
return m_display != 0;
}
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);
}
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:
Display *m_display;
};
} // namespace
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
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 = 0;
if (eventType == "xcb_generic_event_t") {
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 != 0) {
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));
}
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
return prevEventFilter ? prevEventFilter(message) : false;
#else
return false;
#endif
}
quint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers)
{
// ShiftMask, LockMask, ControlMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, and Mod5Mask
quint32 native = 0;
if (modifiers & Qt::ShiftModifier)
native |= ShiftMask;
if (modifiers & Qt::ControlModifier)
native |= ControlMask;
if (modifiers & Qt::AltModifier)
native |= Mod1Mask;
if (modifiers & Qt::MetaModifier)
native |= Mod4Mask;
// TODO: resolve these?
//if (modifiers & Qt::MetaModifier)
//if (modifiers & Qt::KeypadModifier)
//if (modifiers & Qt::GroupSwitchModifier)
return native;
}
quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key)
{
QxtX11Data x11;
if (!x11.isValid())
return 0;
KeySym keysym = XStringToKeysym(QKeySequence(key).toString().toLatin1().data());
if (keysym == NoSymbol)
keysym = static_cast<ushort>(key);
return XKeysymToKeycode(x11.display(), keysym);
}
bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods)
{
QxtX11Data x11;
return x11.isValid() && x11.grabKey(nativeKey, nativeMods, x11.rootWindow());
}
bool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods)
{
QxtX11Data x11;
return x11.isValid() && x11.ungrabKey(nativeKey, nativeMods, x11.rootWindow());
}

View File

@ -0,0 +1,153 @@
#include "qxtwindowsystem.h"
/****************************************************************************
** Copyright (c) 2006 - 2011, the LibQxt project.
** See the Qxt AUTHORS file for a list of authors and copyright holders.
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** * Neither the name of the LibQxt project nor the
** names of its contributors may be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
** <http://libqxt.org> <foundation@libqxt.org>
*****************************************************************************/
#include <QStringList>
/*!
\class QxtWindowSystem
\inmodule QxtWidgets
\brief The QxtWindowSystem class provides means for accessing native windows.
\bold {Note:} The underlying window system might or might not allow one to alter
states of windows belonging to other processes.
\warning QxtWindowSystem is portable in principle, but be careful while
using it since you are probably about to do something non-portable.
\section1 Advanced example usage:
\code
class NativeWindow : public QWidget {
public:
NativeWindow(WId wid) {
QWidget::create(wid, false, false); // window, initializeWindow, destroyOldWindow
}
~NativeWindow() {
QWidget::destroy(false, false); // destroyWindow, destroySubWindows
}
};
\endcode
\code
WindowList windows = QxtWindowSystem::windows();
QStringList titles = QxtWindowSystem::windowTitles();
bool ok = false;
QString title = QInputDialog::getItem(0, "Choose Window", "Choose a window to be hid:", titles, 0, false, &ok);
if (ok)
{
int index = titles.indexOf(title);
if (index != -1)
{
NativeWindow window(windows.at(index));
window.hide();
}
}
\endcode
\bold {Note:} Currently supported platforms are \bold X11 and \bold Windows.
*/
/*!
\fn QxtWindowSystem::windows()
Returns the list of native window system identifiers.
\sa QApplication::topLevelWidgets(), windowTitles()
*/
/*!
\fn QxtWindowSystem::activeWindow()
Returns the native window system identifier of the active window if any.
\sa QApplication::activeWindow()
*/
/*!
\fn QxtWindowSystem::findWindow(const QString& title)
Returns the native window system identifier of the window if any with given \a title.
Example usage:
\code
WId wid = QxtWindowSystem::findWindow("Mail - Kontact");
QPixmap screenshot = QPixmap::grabWindow(wid);
\endcode
\sa QWidget::find()
*/
/*!
\fn QxtWindowSystem::windowAt(const QPoint& pos)
Returns the native window system identifier of the window if any at \a pos.
\sa QApplication::widgetAt()
*/
/*!
\fn QxtWindowSystem::windowTitle(WId window)
Returns the title of the native \a window.
\sa QWidget::windowTitle(), windowTitles()
*/
/*!
\fn QxtWindowSystem::windowTitles()
Returns a list of native window titles.
\sa QWidget::windowTitle(), windowTitle(), windows()
*/
/*!
\fn QxtWindowSystem::windowGeometry(WId window)
Returns the geometry of the native \a window.
\sa QWidget::frameGeometry()
*/
/*!
\fn QxtWindowSystem::idleTime()
Returns the system "idle time" ie. the time since last user input
in milliseconds.
*/
QStringList QxtWindowSystem::windowTitles()
{
WindowList windows = QxtWindowSystem::windows();
QStringList titles;
foreach(WId window, windows)
titles += QxtWindowSystem::windowTitle(window);
return titles;
}

View File

@ -0,0 +1,53 @@
#ifndef QXTWINDOWSYSTEM_H
/****************************************************************************
** Copyright (c) 2006 - 2011, the LibQxt project.
** See the Qxt AUTHORS file for a list of authors and copyright holders.
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** * Neither the name of the LibQxt project nor the
** names of its contributors may be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
** <http://libqxt.org> <foundation@libqxt.org>
*****************************************************************************/
#define QXTWINDOWSYSTEM_H
#include <QWidget>
#include "qxtglobal.h"
typedef QList<WId> WindowList;
class /*QXT_GUI_EXPORT*/ QxtWindowSystem
{
public:
static WindowList windows();
static WId activeWindow();
static WId findWindow(const QString& title);
static WId windowAt(const QPoint& pos);
static QString windowTitle(WId window);
static QStringList windowTitles();
static QRect windowGeometry(WId window);
static uint idleTime();
};
#endif // QXTWINDOWSYSTEM_H

View File

@ -0,0 +1,158 @@
#ifndef QXTWINDOWSYSTEM_MAC_CPP
#define QXTWINDOWSYSTEM_MAC_CPP
#include "qxtwindowsystem.h"
#include "qxtwindowsystem_mac.h"
// WId to return when error
#define WINDOW_NOT_FOUND (WId)(0)
WindowList qxt_getWindowsForPSN(ProcessSerialNumber *psn)
{
static CGSConnection connection = _CGSDefaultConnection();
WindowList wlist;
if (!psn) return wlist;
CGError err((CGError)noErr);
// get onnection for given process psn
CGSConnection procConnection;
err = CGSGetConnectionIDForPSN(connection, psn, &procConnection);
if (err != noErr) return wlist;
/* get number of windows open by given process
in Mac OS X an application may have multiple windows, which generally
represent documents. It is also possible that there is no window even
though there is an application, it can simply not have any documents open. */
int windowCount(0);
err = CGSGetOnScreenWindowCount(connection, procConnection, &windowCount);
// if there are no windows open by this application, skip
if (err != noErr || windowCount == 0) return wlist;
// get list of windows
int windowList[windowCount];
int outCount(0);
err = CGSGetOnScreenWindowList(connection, procConnection, windowCount, windowList, &outCount);
if (err != noErr || outCount == 0) return wlist;
for (int i=0; i<outCount; ++i)
{
wlist += windowList[i];
}
return wlist;
}
WindowList QxtWindowSystem::windows()
{
WindowList wlist;
ProcessSerialNumber psn = {0, kNoProcess};
// iterate over list of processes
OSErr err;
while ((err = ::GetNextProcess(&psn)) == noErr)
{
wlist += qxt_getWindowsForPSN(&psn);
}
return wlist;
}
WId QxtWindowSystem::activeWindow()
{
ProcessSerialNumber psn;
OSErr err(noErr);
err = ::GetFrontProcess(&psn);
if (err != noErr) return WINDOW_NOT_FOUND;
// in Mac OS X, first window for given PSN is always the active one
WindowList wlist = qxt_getWindowsForPSN(&psn);
if (wlist.count() > 0)
return wlist.at(0);
return WINDOW_NOT_FOUND;
}
QString QxtWindowSystem::windowTitle(WId window)
{
CGSValue windowTitle;
CGError err((CGError)noErr);
static CGSConnection connection = _CGSDefaultConnection();
// This code is so dirty I had to wash my hands after writing it.
// most of CoreGraphics private definitions ask for CGSValue as key but since
// converting strings to/from CGSValue was dropped in 10.5, I use CFString, which
// apparently also works.
// FIXME: Not public API function. Can't compile with OS X 10.8
// err = CGSGetWindowProperty(connection, window, (CGSValue)CFSTR("kCGSWindowTitle"), &windowTitle);
if (err != noErr) return QString();
// this is UTF8 encoded
return QCFString::toQString((CFStringRef)windowTitle);
}
QRect QxtWindowSystem::windowGeometry(WId window)
{
CGRect rect;
static CGSConnection connection = _CGSDefaultConnection();
CGError err = CGSGetWindowBounds(connection, window, &rect);
if (err != noErr) return QRect();
return QRect(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
}
/* This method is the only one that is not a complete hack
from Quartz Event Services
http://developer.apple.com/library/mac/#documentation/Carbon/Reference/QuartzEventServicesRef/Reference/reference.html
*/
uint QxtWindowSystem::idleTime()
{
// CGEventSourceSecondsSinceLastEventType returns time in seconds as a double
// also has extremely long name
double idle = 1000 * ::CGEventSourceSecondsSinceLastEventType(kCGEventSourceStateCombinedSessionState, kCGAnyInputEventType);
return (uint)idle;
}
// these are copied from X11 implementation
WId QxtWindowSystem::findWindow(const QString& title)
{
WId result = 0;
WindowList list = windows();
foreach(const WId &wid, list)
{
if (windowTitle(wid) == title)
{
result = wid;
break;
}
}
return result;
}
WId QxtWindowSystem::windowAt(const QPoint& pos)
{
WId result = 0;
WindowList list = windows();
for (int i = list.size() - 1; i >= 0; --i)
{
WId wid = list.at(i);
if (windowGeometry(wid).contains(pos))
{
result = wid;
break;
}
}
return result;
}
#endif // QXTWINDOWSYSTEM_MAC_CPP

View File

@ -0,0 +1,148 @@
/****************************************************************************
** Copyright (c) 2006 - 2011, the LibQxt project.
** See the Qxt AUTHORS file for a list of authors and copyright holders.
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** * Neither the name of the LibQxt project nor the
** names of its contributors may be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
** <http://libqxt.org> <foundation@libqxt.org>
*****************************************************************************/
/****************************************************************************
**
** Copyright (C) Marcin Jakubowski <mjakubowski (at) gmail (dot) com
**
** Defines some of required CoreGraphics private parts. This code may
** break at any time and uses *undocumented* features of Mac OS X.
**
** Also defines QCFString, part of Qt code found in src/corelib/kernel
** qcoremac_p.h file.
****************************************************************************/
#ifndef QXTWINDOWSYSTEM_MAC_H
#define QXTWINDOWSYSTEM_MAC_H
//
// CGSPrivate.h
// Header file for undocumented CoreGraphics SPI
//
// Arranged by Nicholas Jitkoff
// Based on CGSPrivate.h by Richard Wareham
//
// Contributors:
// Austin Sarner: Shadows
// Jason Harris: Filters, Shadows, Regions
// Kevin Ballard: Warping
// Steve Voida: Workspace notifications
// Tony Arnold: Workspaces notifications enum filters
// Ben Gertzfield: CGSRemoveConnectionNotifyProc
//
// Changes:
// 2.3 - Added the CGSRemoveConnectionNotifyProc method with the help of Ben Gertzfield
// 2.2 - Moved back to CGSPrivate, added more enums to the CGSConnectionNotifyEvent
// 2.1 - Added spaces notifications
// 2.0 - Original Release
#include <Carbon/Carbon.h>
#define CGSConnectionID CGSConnection
#define CGSWindowID CGSWindow
#define CGSDefaultConnection _CGSDefaultConnection()
#ifdef __cplusplus
extern "C" {
#endif
typedef int CGSConnection;
typedef int CGSWindow;
typedef int CGSWorkspace;
typedef void* CGSValue;
/* Get the default connection for the current process. */
extern CGSConnection _CGSDefaultConnection(void);
/* /MJakubowski/ Get connection for given PSN */
extern CGError CGSGetConnectionIDForPSN(const CGSConnection connection, ProcessSerialNumber * psn, CGSConnection * targetConnection);
// Get on-screen window counts and lists.
extern CGError CGSGetOnScreenWindowCount(const CGSConnection cid, CGSConnection targetCID, int* outCount);
extern CGError CGSGetOnScreenWindowList(const CGSConnection cid, CGSConnection targetCID, int count, int* list, int* outCount);
// Position
extern CGError CGSGetWindowBounds(CGSConnection cid, CGSWindowID wid, CGRect *outBounds);
extern CGError CGSGetScreenRectForWindow(const CGSConnection cid, CGSWindow wid, CGRect *outRect);
// Properties
extern CGError CGSGetWindowProperty(const CGSConnection cid, CGSWindow wid, CGSValue key, CGSValue *outValue);
#ifdef __cplusplus
}
#endif
/* QCFString from Qt */
#include <QString>
template <typename T>
class QCFType
{
public:
inline QCFType(const T &t = 0) : type(t) {}
inline QCFType(const QCFType &helper) : type(helper.type) { if (type) CFRetain(type); }
inline ~QCFType() { if (type) CFRelease(type); }
inline operator T() { return type; }
inline QCFType operator =(const QCFType &helper)
{
if (helper.type)
CFRetain(helper.type);
CFTypeRef type2 = type;
type = helper.type;
if (type2)
CFRelease(type2);
return *this;
}
inline T *operator&() { return &type; }
static QCFType constructFromGet(const T &t)
{
CFRetain(t);
return QCFType<T>(t);
}
protected:
T type;
};
class QCFString : public QCFType<CFStringRef>
{
public:
inline QCFString(const QString &str) : QCFType<CFStringRef>(0), string(str) {}
inline QCFString(const CFStringRef cfstr = 0) : QCFType<CFStringRef>(cfstr) {}
inline QCFString(const QCFType<CFStringRef> &other) : QCFType<CFStringRef>(other) {}
operator QString() const;
operator CFStringRef() const;
static QString toQString(CFStringRef cfstr);
static CFStringRef toCFStringRef(const QString &str);
private:
QString string;
};
#endif // QXTWINDOWSYSTEM_MAC_H

View File

@ -0,0 +1,127 @@
#include "qxtwindowsystem.h"
/****************************************************************************
** Copyright (c) 2006 - 2011, the LibQxt project.
** See the Qxt AUTHORS file for a list of authors and copyright holders.
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** * Neither the name of the LibQxt project nor the
** names of its contributors may be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
** <http://libqxt.org> <foundation@libqxt.org>
*****************************************************************************/
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0500
#endif
#include <qt_windows.h>
#include <qglobal.h> // QT_WA
static WindowList qxt_Windows;
BOOL CALLBACK qxt_EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
Q_UNUSED(lParam);
if (::IsWindowVisible(hwnd))
qxt_Windows += (WId)hwnd;
return true;
}
WindowList QxtWindowSystem::windows()
{
qxt_Windows.clear();
HDESK hdesk = ::OpenInputDesktop(0, false, DESKTOP_READOBJECTS);
::EnumDesktopWindows(hdesk, qxt_EnumWindowsProc, 0);
::CloseDesktop(hdesk);
return qxt_Windows;
}
WId QxtWindowSystem::activeWindow()
{
return (WId)::GetForegroundWindow();
}
WId QxtWindowSystem::findWindow(const QString& title)
{
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
QT_WA({
return (WId)::FindWindow(NULL, (TCHAR*)title.utf16());
}, {
return (WId)::FindWindowA(NULL, title.toLocal8Bit());
});
#else
return (WId)::FindWindow(NULL, (TCHAR*)title.utf16());
#endif
}
WId QxtWindowSystem::windowAt(const QPoint& pos)
{
POINT pt;
pt.x = pos.x();
pt.y = pos.y();
return (WId)::WindowFromPoint(pt);
}
QString QxtWindowSystem::windowTitle(WId window)
{
QString title;
int len = ::GetWindowTextLength((HWND)window);
if (len >= 0)
{
TCHAR* buf = new TCHAR[len+1];
len = ::GetWindowText((HWND)window, buf, len+1);
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
QT_WA({
title = QString::fromUtf16((const ushort*)buf, len);
}, {
title = QString::fromLocal8Bit((const char*)buf, len);
});
#else
title = QString::fromUtf16((const ushort*)buf, len);
#endif
delete[] buf;
}
return title;
}
QRect QxtWindowSystem::windowGeometry(WId window)
{
RECT rc;
QRect rect;
if (::GetWindowRect((HWND)window, &rc))
{
rect.setTop(rc.top);
rect.setBottom(rc.bottom);
rect.setLeft(rc.left);
rect.setRight(rc.right);
}
return rect;
}
uint QxtWindowSystem::idleTime()
{
uint idle = -1;
LASTINPUTINFO info;
info.cbSize = sizeof(LASTINPUTINFO);
if (::GetLastInputInfo(&info))
idle = ::GetTickCount() - info.dwTime;
return idle;
}

View File

@ -0,0 +1,189 @@
#include "qxtwindowsystem.h"
/****************************************************************************
** Copyright (c) 2006 - 2011, the LibQxt project.
** See the Qxt AUTHORS file for a list of authors and copyright holders.
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** * Neither the name of the LibQxt project nor the
** names of its contributors may be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
** <http://libqxt.org> <foundation@libqxt.org>
*****************************************************************************/
#include <QLibrary>
#include <QX11Info>
#include <X11/Xutil.h>
static WindowList qxt_getWindows(Atom prop)
{
WindowList res;
Atom type = 0;
int format = 0;
uchar* data = 0;
ulong count, after;
Display* display = QX11Info::display();
Window window = QX11Info::appRootWindow();
if (XGetWindowProperty(display, window, prop, 0, 1024 * sizeof(Window) / 4, False, AnyPropertyType,
&type, &format, &count, &after, &data) == Success)
{
Window* list = reinterpret_cast<Window*>(data);
for (uint i = 0; i < count; ++i)
res += list[i];
if (data)
XFree(data);
}
return res;
}
WindowList QxtWindowSystem::windows()
{
static Atom net_clients = 0;
if (!net_clients)
net_clients = XInternAtom(QX11Info::display(), "_NET_CLIENT_LIST_STACKING", True);
return qxt_getWindows(net_clients);
}
WId QxtWindowSystem::activeWindow()
{
static Atom net_active = 0;
if (!net_active)
net_active = XInternAtom(QX11Info::display(), "_NET_ACTIVE_WINDOW", True);
return qxt_getWindows(net_active).value(0);
}
WId QxtWindowSystem::findWindow(const QString& title)
{
Window result = 0;
WindowList list = windows();
foreach (const Window &wid, list)
{
if (windowTitle(wid) == title)
{
result = wid;
break;
}
}
return result;
}
WId QxtWindowSystem::windowAt(const QPoint& pos)
{
Window result = 0;
WindowList list = windows();
for (int i = list.size() - 1; i >= 0; --i)
{
WId wid = list.at(i);
if (windowGeometry(wid).contains(pos))
{
result = wid;
break;
}
}
return result;
}
QString QxtWindowSystem::windowTitle(WId window)
{
QString name;
char* str = 0;
if (XFetchName(QX11Info::display(), window, &str))
name = QString::fromLatin1(str);
if (str)
XFree(str);
return name;
}
QRect QxtWindowSystem::windowGeometry(WId window)
{
int x, y;
uint width, height, border, depth;
Window root, child;
Display* display = QX11Info::display();
XGetGeometry(display, window, &root, &x, &y, &width, &height, &border, &depth);
XTranslateCoordinates(display, window, root, x, y, &x, &y, &child);
static Atom net_frame = 0;
if (!net_frame)
net_frame = XInternAtom(QX11Info::display(), "_NET_FRAME_EXTENTS", True);
QRect rect(x, y, width, height);
Atom type = 0;
int format = 0;
uchar* data = 0;
ulong count, after;
if (XGetWindowProperty(display, window, net_frame, 0, 4, False, AnyPropertyType,
&type, &format, &count, &after, &data) == Success)
{
// _NET_FRAME_EXTENTS, left, right, top, bottom, CARDINAL[4]/32
if (count == 4)
{
long* extents = reinterpret_cast<long*>(data);
rect.adjust(-extents[0], -extents[2], extents[1], extents[3]);
}
if (data)
XFree(data);
}
return rect;
}
typedef struct {
Window window; /* screen saver window - may not exist */
int state; /* ScreenSaverOff, ScreenSaverOn, ScreenSaverDisabled*/
int kind; /* ScreenSaverBlanked, ...Internal, ...External */
unsigned long til_or_since; /* time til or since screen saver */
unsigned long idle; /* total time since last user input */
unsigned long eventMask; /* currently selected events for this client */
} XScreenSaverInfo;
typedef XScreenSaverInfo* (*XScreenSaverAllocInfo)();
typedef Status (*XScreenSaverQueryInfo)(Display* display, Drawable drawable, XScreenSaverInfo* info);
static XScreenSaverAllocInfo _xScreenSaverAllocInfo = 0;
static XScreenSaverQueryInfo _xScreenSaverQueryInfo = 0;
uint QxtWindowSystem::idleTime()
{
static bool xssResolved = false;
if (!xssResolved) {
QLibrary xssLib(QLatin1String("Xss"), 1);
if (xssLib.load()) {
_xScreenSaverAllocInfo = (XScreenSaverAllocInfo) xssLib.resolve("XScreenSaverAllocInfo");
_xScreenSaverQueryInfo = (XScreenSaverQueryInfo) xssLib.resolve("XScreenSaverQueryInfo");
xssResolved = true;
}
}
uint idle = 0;
if (xssResolved)
{
XScreenSaverInfo* info = _xScreenSaverAllocInfo();
const int screen = QX11Info::appScreen();
unsigned long rootWindow = (unsigned long)QX11Info::appRootWindow(screen);
_xScreenSaverQueryInfo(QX11Info::display(), (Drawable) rootWindow, info);
idle = info->idle;
if (info)
XFree(info);
}
return idle;
}

View File

@ -0,0 +1,77 @@
/*
* Copyright (C) 2013 Il'inykh Sergey (rion)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include "x11info.h"
#ifdef HAVE_QT5
# include <X11/Xlib.h>
# include <xcb/xcb.h>
# include <QtGlobal>
#else
# include <QX11Info>
#endif
Display* X11Info::display()
{
#ifdef HAVE_QT5
if (!_display) {
_display = XOpenDisplay(NULL);
}
return _display;
#else
return QX11Info::display();
#endif
}
unsigned long X11Info::appRootWindow(int screen)
{
#ifdef HAVE_QT5
return screen == -1?
XDefaultRootWindow(display()) :
XRootWindowOfScreen(XScreenOfDisplay(display(), screen));
#else
return QX11Info::appRootWindow(screen);
#endif
}
int X11Info::appScreen()
{
#ifdef HAVE_QT5
#error X11Info::appScreen not implemented for Qt5! You must skip this plugin.
#else
return QX11Info::appScreen();
#endif
}
#ifdef HAVE_QT5
xcb_connection_t *X11Info::xcbConnection()
{
if (!_xcb) {
_xcb = xcb_connect(NULL, &_xcbPreferredScreen);
Q_ASSERT(_xcb);
}
return _xcb;
}
xcb_connection_t* X11Info::_xcb = 0;
#endif
Display* X11Info::_display = 0;
int X11Info::_xcbPreferredScreen = 0;

View File

@ -0,0 +1,46 @@
/*
* Copyright (C) 2013 Il'inykh Sergey (rion)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef X11INFO_H
#define X11INFO_H
typedef struct _XDisplay Display;
#ifdef HAVE_QT5
typedef struct xcb_connection_t xcb_connection_t;
#endif
class X11Info
{
static Display *_display;
#ifdef HAVE_QT5
static xcb_connection_t *_xcb;
#endif
static int _xcbPreferredScreen;
public:
static Display* display();
static unsigned long appRootWindow(int screen = -1);
static int appScreen();
#ifdef HAVE_QT5
static xcb_connection_t* xcbConnection();
static inline int xcbPreferredScreen() { return _xcbPreferredScreen; }
#endif
};
#endif // X11INFO_H

View File

@ -38,6 +38,7 @@ SUBDIRS += netserver #网络中转服务器
SUBDIRS += base64helper #图片文字base64互换
SUBDIRS += smoothcurve #平滑曲线
SUBDIRS += moneytool #存款计算器
SUBDIRS += hotkey #全局热键示例 目前只支持Qt5
#限定windows系统加载下面的项目
win32 {
@ -64,4 +65,5 @@ SUBDIRS += qwtdemo #qwt的源码版本无需插件直接源码集
#6.0到6.2之间的版本还有点问题等待正式发布的时候再试试
greaterThan(QT_MAJOR_VERSION, 5) {
SUBDIRS -= emailtool
SUBDIRS -= hotkey
}

View File

@ -51,6 +51,7 @@
| 42 | base64 | 图片文字base64互换 |
| 43 | smoothcurve | 平滑曲线 |
| 44 | moneytool | 存款计算器 |
| 45 | hotkey | 全局热键示例 |
#### 二、学习群
1. **Qt交流大会群 853086607(雨田哥)**
@ -104,3 +105,4 @@
![avatar](https://gitee.com/feiyangqingyun/QWidgetDemo/raw/master/0snap/smoothcurve.gif)
![avatar](https://gitee.com/feiyangqingyun/QWidgetDemo/raw/master/0snap/frameless.gif)
![avatar](https://gitee.com/feiyangqingyun/QWidgetDemo/raw/master/0snap/moneytool.jpg)
![avatar](https://gitee.com/feiyangqingyun/QWidgetDemo/raw/master/0snap/hotkey.gif)

BIN
bin/base64helper.exe Normal file

Binary file not shown.

BIN
bin/battery.exe Normal file

Binary file not shown.

BIN
bin/bgdemo.exe Normal file

Binary file not shown.

BIN
bin/colorwidget.exe Normal file

Binary file not shown.

BIN
bin/comtool.exe Normal file

Binary file not shown.

BIN
bin/countcode.exe Normal file

Binary file not shown.

BIN
bin/dbpage.exe Normal file

Binary file not shown.

BIN
bin/devicebutton.exe Normal file

Binary file not shown.

BIN
bin/devicesizetable.exe Normal file

Binary file not shown.

BIN
bin/emailtool.exe Normal file

Binary file not shown.

BIN
bin/ffmpegdemo.exe Normal file

Binary file not shown.

BIN
bin/flatui.exe Normal file

Binary file not shown.

BIN
bin/framelesswidget.exe Normal file

Binary file not shown.

BIN
bin/gifwidget.exe Normal file

Binary file not shown.

BIN
bin/hotkey.exe Normal file

Binary file not shown.

BIN
bin/imageswitch.exe Normal file

Binary file not shown.

BIN
bin/ipaddress.exe Normal file

Binary file not shown.

BIN
bin/lightbutton.exe Normal file

Binary file not shown.

BIN
bin/lineeditnext.exe Normal file

Binary file not shown.

BIN
bin/lunarcalendarwidget.exe Normal file

Binary file not shown.

BIN
bin/maskwidget.exe Normal file

Binary file not shown.

BIN
bin/miniblink.exe Normal file

Binary file not shown.

BIN
bin/moneytool.exe Normal file

Binary file not shown.

BIN
bin/mouseline.exe Normal file

Binary file not shown.

BIN
bin/movewidget.exe Normal file

Binary file not shown.

BIN
bin/mpvdemo.exe Normal file

Binary file not shown.

BIN
bin/navbutton.exe Normal file

Binary file not shown.

BIN
bin/netserver.exe Normal file

Binary file not shown.

BIN
bin/nettool.exe Normal file

Binary file not shown.

BIN
bin/ntpclient.exe Normal file

Binary file not shown.

BIN
bin/pngtool.exe Normal file

Binary file not shown.

BIN
bin/qwtdemo.exe Normal file

Binary file not shown.

BIN
bin/savelog.exe Normal file

Binary file not shown.

BIN
bin/saveruntime.exe Normal file

Binary file not shown.

BIN
bin/screenwidget.exe Normal file

Binary file not shown.

BIN
bin/smoothcurve.exe Normal file

Binary file not shown.

BIN
bin/styledemo.exe Normal file

Binary file not shown.

BIN
bin/videopanel.exe Normal file

Binary file not shown.

BIN
bin/videowidget.exe Normal file

Binary file not shown.

BIN
bin/vlcdemo.exe Normal file

Binary file not shown.

BIN
bin/zhtopy.exe Normal file

Binary file not shown.

38
hotkey/frmhotkey.cpp Normal file
View File

@ -0,0 +1,38 @@
#include "frmhotkey.h"
#include "ui_frmhotkey.h"
#include "qhotkey.h"
#include "qdatetime.h"
#include "qdebug.h"
frmHotKey::frmHotKey(QWidget *parent) : QWidget(parent), ui(new Ui::frmHotKey)
{
ui->setupUi(this);
this->initForm();
}
frmHotKey::~frmHotKey()
{
delete ui;
}
void frmHotKey::initForm()
{
//实例化热键类
QHotkey *hotkey = new QHotkey(QKeySequence("ctrl+x"), true, this);
connect(hotkey, SIGNAL(activated()), this, SLOT(shortcut()));
}
void frmHotKey::shortcut()
{
#if 1
//如果是最小化则显示,否则最小化
if (this->isMinimized()) {
this->showNormal();
this->activateWindow();
} else {
this->showMinimized();
}
#else
ui->label->setText("activated " + QTime::currentTime().toString("hh:mm:ss zzz"));
#endif
}

26
hotkey/frmhotkey.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef FRMHOTKEY_H
#define FRMHOTKEY_H
#include <QWidget>
namespace Ui {
class frmHotKey;
}
class frmHotKey : public QWidget
{
Q_OBJECT
public:
explicit frmHotKey(QWidget *parent = 0);
~frmHotKey();
private:
Ui::frmHotKey *ui;
private slots:
void initForm();
void shortcut();
};
#endif // FRMHOTKEY_H

31
hotkey/frmhotkey.ui Normal file
View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>frmHotKey</class>
<widget class="QWidget" name="frmHotKey">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>全局热键示例</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>按 ctrl+x 最小化,再次按显示</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

16
hotkey/hotkey.pro Normal file
View File

@ -0,0 +1,16 @@
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
greaterThan(QT_MAJOR_VERSION, 5): QT += core5compat
TARGET = hotkey
TEMPLATE = app
DESTDIR = $$PWD/../bin
CONFIG += warn_off
SOURCES += main.cpp
SOURCES += frmhotkey.cpp
HEADERS += frmhotkey.h
FORMS += frmhotkey.ui
INCLUDEPATH += $$PWD/../3rd_qhotkey
include($$PWD/../3rd_qhotkey/3rd_qhotkey.pri)

10
hotkey/main.cpp Normal file
View File

@ -0,0 +1,10 @@
#include "frmhotkey.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
frmHotKey w;
w.show();
return a.exec();
}

View File

@ -12,10 +12,10 @@
#define QDATE qPrintable(QDate::currentDate().toString("yyyy-MM-dd"))
//日志重定向
#if (QT_VERSION < QT_VERSION_CHECK(5,0,0))
void Log(QtMsgType type, const char *msg)
#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0))
void Log(QtMsgType type, const QMessageLogContext &context, const QString &msg)
#else
void Log(QtMsgType type, const QMessageLogContext &, const QString &msg)
void Log(QtMsgType type, const char *msg)
#endif
{
//加锁,防止多线程中qdebug太频繁导致崩溃
@ -42,6 +42,19 @@ void Log(QtMsgType type, const QMessageLogContext &, const QString &msg)
break;
}
//加上打印代码所在代码文件、行号、函数名
#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0))
if (SaveLog::Instance()->getUseContext()) {
int line = context.line;
QString file = context.file;
QString function = context.function;
if (line > 0) {
content = QString("行号: %1 文件: %2 函数: %3\n%4").arg(line).arg(file).arg(function).arg(content);
}
}
#endif
//将内容传给函数进行处理
SaveLog::Instance()->save(content);
}
@ -67,6 +80,8 @@ SaveLog::SaveLog(QObject *parent) : QObject(parent)
file = new QFile(this);
toNet = false;
useContext = true;
//默认取应用程序根目录
path = qApp->applicationDirPath();
//默认取应用程序可执行文件名称
@ -81,23 +96,28 @@ SaveLog::~SaveLog()
file->close();
}
bool SaveLog::getUseContext()
{
return this->useContext;
}
//安装日志钩子,输出调试信息到文件,便于调试
void SaveLog::start()
{
#if (QT_VERSION < QT_VERSION_CHECK(5,0,0))
qInstallMsgHandler(Log);
#else
#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0))
qInstallMessageHandler(Log);
#else
qInstallMsgHandler(Log);
#endif
}
//卸载日志钩子
void SaveLog::stop()
{
#if (QT_VERSION < QT_VERSION_CHECK(5,0,0))
qInstallMsgHandler(0);
#else
#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0))
qInstallMessageHandler(0);
#else
qInstallMsgHandler(0);
#endif
}
@ -135,6 +155,11 @@ void SaveLog::setToNet(bool toNet)
this->toNet = toNet;
}
void SaveLog::setUseContext(bool useContext)
{
this->useContext = useContext;
}
void SaveLog::setPath(const QString &path)
{
this->path = path;

View File

@ -6,9 +6,10 @@
* 1.
* 2.
* 3.
* 4. Qt4+Qt5+Qt6
* 5. 线
* 6. 使start
* 4.
* 5. Qt4+Qt5+Qt6
* 6. 线
* 7. 使start
*/
#include <QObject>
@ -37,6 +38,8 @@ private:
QFile *file;
//是否重定向到网络
bool toNet;
//是否输出日志上下文
bool useContext;
//日志文件路径
QString path;
//日志文件名称
@ -44,6 +47,9 @@ private:
//日志文件完整名称
QString fileName;
public:
bool getUseContext();
Q_SIGNALS:
//发送内容信号
void send(const QString &content);
@ -58,6 +64,8 @@ public Q_SLOTS:
//设置是否重定向到网络
void setToNet(bool toNet);
//设置是否输出日志上下文
void setUseContext(bool useContext);
//设置日志文件存放路径
void setPath(const QString &path);
//设置日志文件名称

38
shortcut/frmshortcut.cpp Normal file
View File

@ -0,0 +1,38 @@
#include "frmshortcut.h"
#include "ui_frmshortcut.h"
#include "qxtglobalshortcut.h"
#include "qdatetime.h"
#include "qdebug.h"
frmShortCut::frmShortCut(QWidget *parent) : QWidget(parent), ui(new Ui::frmShortCut)
{
ui->setupUi(this);
this->initForm();
}
frmShortCut::~frmShortCut()
{
delete ui;
}
void frmShortCut::initForm()
{
//实例化热键类
QxtGlobalShortcut *shortcut = new QxtGlobalShortcut(QKeySequence("ctrl+x"), this);
connect(shortcut, SIGNAL(activated()), this, SLOT(shortcut()));
}
void frmShortCut::shortcut()
{
#if 1
//如果是最小化则显示,否则最小化
if (this->isMinimized()) {
this->showNormal();
this->activateWindow();
} else {
this->showMinimized();
}
#else
ui->label->setText("activated " + QTime::currentTime().toString("hh:mm:ss zzz"));
#endif
}

26
shortcut/frmshortcut.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef FRMSHORTCUT_H
#define FRMSHORTCUT_H
#include <QWidget>
namespace Ui {
class frmShortCut;
}
class frmShortCut : public QWidget
{
Q_OBJECT
public:
explicit frmShortCut(QWidget *parent = 0);
~frmShortCut();
private:
Ui::frmShortCut *ui;
private slots:
void initForm();
void shortcut();
};
#endif // FRMSHORTCUT_H

31
shortcut/frmshortcut.ui Normal file
View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>frmShortCut</class>
<widget class="QWidget" name="frmShortCut">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>全局热键示例</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>按 ctrl+x 最小化,再次按显示</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

10
shortcut/main.cpp Normal file
View File

@ -0,0 +1,10 @@
#include "frmshortcut.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
frmShortCut w;
w.show();
return a.exec();
}

16
shortcut/shortcut.pro Normal file
View File

@ -0,0 +1,16 @@
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
greaterThan(QT_MAJOR_VERSION, 5): QT += core5compat
TARGET = shortcut
TEMPLATE = app
DESTDIR = $$PWD/../bin
CONFIG += warn_off
SOURCES += main.cpp
SOURCES += frmshortcut.cpp
HEADERS += frmshortcut.h
FORMS += frmshortcut.ui
INCLUDEPATH += $$PWD/../3rd_qxtglobalshortcut
include($$PWD/../3rd_qxtglobalshortcut/3rd_qxtglobalshortcut.pri)