Commit 495fa523 authored by abbycin's avatar abbycin

add error handling

NOTE: error message in Linux is hardcoded, since there's no way to get error from xcb_generic_error_t
parent 6030c156
......@@ -26,7 +26,7 @@ void QGlobalShortcut::initialize() {
}
QGlobalShortcut::~QGlobalShortcut() {
unsetKey();
}
QKeySequence QGlobalShortcut::key() const
......@@ -34,7 +34,7 @@ QKeySequence QGlobalShortcut::key() const
return keyseq_;
}
void QGlobalShortcut::setKey(const QKeySequence& keyseq)
bool QGlobalShortcut::setKey(const QKeySequence& keyseq)
{
if (!keyseq_.isEmpty()) {
unsetKey();
......@@ -43,22 +43,44 @@ void QGlobalShortcut::setKey(const QKeySequence& keyseq)
if (shortcuts_.count(keyid) == 0) {
quint32 keycode = toNativeKeycode(getKey(keyseq));
quint32 mods = toNativeModifiers(getMods(keyseq));
registerKey(keycode, mods, keyid);
#ifdef Q_OS_WIN
if(!registerKey(keycode, mods, keyid)) {
error(getErrorMsg());
return false;
}
#else
if(!registerKey(keycode, mods, keyid)) {
error("Hotkey already set");
return false;
}
#endif
}
this->keyseq_ = keyseq;
shortcuts_.insert(keyid, this);
return true;
}
void QGlobalShortcut::unsetKey() {
bool QGlobalShortcut::unsetKey() {
quint32 keyid = calcId(keyseq_);
if (shortcuts_.remove(keyid, this) > 0) {
if (shortcuts_.count(keyid) == 0) {
quint32 keycode = toNativeKeycode(getKey(keyseq_));
quint32 mods = toNativeModifiers(getMods(keyseq_));
unregisterKey(keycode, mods, keyid);
#ifdef Q_OS_WIN
if(!unregisterKey(keycode, mods, keyid)) {
error(getErrorMsg());
return false;
}
#else
if(!unregisterKey(keycode, mods, keyid)) {
error("No hotkey set");
return false;
}
#endif
keyseq_ = QKeySequence(); // clear
}
}
return true;
}
bool QGlobalShortcut::activate(quint32 id) {
......
......@@ -9,7 +9,7 @@
class GLOBAL_HOTKEY_EXPORT QGlobalShortcut : public QObject {
Q_OBJECT
Q_PROPERTY(QKeySequence key READ key WRITE setKey)
//Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled)
private:
class QGlobalShortcutEventFilter : public QAbstractNativeEventFilter {
......@@ -24,21 +24,21 @@ public:
bool nativeEventFilter(const QByteArray& event_type, void* message, long* result);
QKeySequence key() const;
void setKey(const QKeySequence& keyseq);
void unsetKey();
//bool isEnabled() const; void setEnabled(bool on);
// you must unset hot key explicitly
bool setKey(const QKeySequence& keyseq);
bool unsetKey();
signals:
void activated();
void error(QString);
private:
QKeySequence keyseq_;
void initialize();
private:
static QGlobalShortcutEventFilter global_shortcut_event_;
/* quint32 keyid
QGlobalShortcut* shortcut */
static QMultiHash<quint32, QGlobalShortcut*> shortcuts_;
static bool activate(quint32 id);
static inline quint32 calcId(const QKeySequence& keyseq);
......@@ -47,6 +47,9 @@ private:
static inline Qt::KeyboardModifiers getMods(const QKeySequence& keyseq);
static quint32 toNativeKeycode(Qt::Key k);
static quint32 toNativeModifiers(Qt::KeyboardModifiers m);
static void registerKey(quint32 k, quint32 m, quint32 id);
static void unregisterKey(quint32 k, quint32 m, quint32 id);
#ifdef Q_OS_WIN
static QString getErrorMsg();
#endif
static bool registerKey(quint32 k, quint32 m, quint32 id);
static bool unregisterKey(quint32 k, quint32 m, quint32 id);
};
......@@ -106,10 +106,26 @@ quint32 QGlobalShortcut::toNativeModifiers(Qt::KeyboardModifiers m) {
return mods;
}
void QGlobalShortcut::registerKey(quint32 k, quint32 m, quint32 id) {
RegisterHotKey(NULL, id, m, k);
QString QGlobalShortcut::getErrorMsg() {
DWORD errorMessageID = ::GetLastError();
if(errorMessageID == 0) {
return {};
}
LPSTR messageBuffer = nullptr;
size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, errorMessageID, LANG_USER_DEFAULT,
(LPSTR)&messageBuffer, 0, NULL);
std::string message{messageBuffer, size};
LocalFree(messageBuffer);
return QString::fromLocal8Bit(message.data(), message.size());
}
bool QGlobalShortcut::registerKey(quint32 k, quint32 m, quint32 id) {
return RegisterHotKey(NULL, id, m, k);
}
void QGlobalShortcut::unregisterKey(quint32 /*k*/, quint32 /*m*/, quint32 id) {
UnregisterHotKey(NULL, id);
bool QGlobalShortcut::unregisterKey(quint32 /*k*/, quint32 /*m*/, quint32 id) {
return UnregisterHotKey(NULL, id);
}
......@@ -6,13 +6,13 @@
#include <X11/keysym.h>
bool QGlobalShortcut::QGlobalShortcutEventFilter::nativeEventFilter(
const QByteArray& eventType, void* message, long* result)
const QByteArray& /*eventType*/, void* message, long*)
{
xcb_generic_event_t* e = static_cast<xcb_generic_event_t*>(message);
if ((e->response_type & ~0x80) == XCB_KEY_PRESS) {
xcb_key_press_event_t* ke = (xcb_key_press_event_t*)e;
xcb_get_keyboard_mapping_reply_t rep;
xcb_keysym_t* k = xcb_get_keyboard_mapping_keysyms(&rep);
/*xcb_keysym_t* k = */xcb_get_keyboard_mapping_keysyms(&rep);
quint32 keycode = ke->detail;
quint32 mods = ke->state & (ShiftMask|ControlMask|Mod1Mask|Mod3Mask);
return activate(calcId(keycode, mods));
......@@ -113,11 +113,21 @@ quint32 QGlobalShortcut::toNativeModifiers(Qt::KeyboardModifiers m) {
return mods;
}
void QGlobalShortcut::registerKey(quint32 k, quint32 m, quint32 id) {
xcb_grab_key(QX11Info::connection(), 1, QX11Info::appRootWindow(),
bool QGlobalShortcut::registerKey(quint32 k, quint32 m, quint32 /*id*/) {
xcb_void_cookie_t r = xcb_grab_key_checked(QX11Info::connection(), 1, QX11Info::appRootWindow(),
m, k, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
auto rsp = xcb_request_check(QX11Info::connection(), r);
if(!rsp) {
return true;
}
return rsp->error_code != 10;
}
void QGlobalShortcut::unregisterKey(quint32 k, quint32 m, quint32 id) {
xcb_ungrab_key(QX11Info::connection(), k, QX11Info::appRootWindow(), m);
bool QGlobalShortcut::unregisterKey(quint32 k, quint32 m, quint32 /*id*/) {
xcb_void_cookie_t r = xcb_ungrab_key_checked(QX11Info::connection(), k, QX11Info::appRootWindow(), m);
auto rsp = xcb_request_check(QX11Info::connection(), r);
if(!rsp) {
return true;
}
return rsp->error_code != 10;
}
......@@ -69,8 +69,6 @@ void MainWindow::initEditor()
connect(acc, &QPushButton::clicked, mEdit, [this] {
mEdit->hide();
mFull->setKey();
mHide->setKey();
});
connect(rej, &QPushButton::clicked, mEdit, [this] {
mHide->clear();
......@@ -90,6 +88,10 @@ void MainWindow::initEditor()
this->hide();
}
});
connect(mHide, &KeyEdit::error, [this](QString msg) {
QMessageBox::critical(this, "Error", msg);
mHide->clear();
});
connect(mFull, &KeyEdit::actived, [this] {
if(this->isFullScreen())
{
......@@ -100,10 +102,20 @@ void MainWindow::initEditor()
this->showFullScreen();
}
});
connect(mFull, &KeyEdit::error, [this](QString msg) {
QMessageBox::critical(this, "Error", msg);
});
mEdit->setLayout(g);
mEdit->resize(mEdit->sizeHint());
mEdit->hide();
#ifdef Q_OS_WIN
// test conflit with QQ
mHide->setKey(QKeySequence::fromString("Ctrl+Alt+A"));
#else
// test conflit with search
mHide->setKey(QKeySequence::fromString("Alt+Space"));
#endif
}
KeyEdit::KeyEdit(QWidget *parent)
......@@ -113,6 +125,10 @@ KeyEdit::KeyEdit(QWidget *parent)
connect(mGhk, &QGlobalShortcut::activated, [this] {
this->actived(mGhk->key());
});
connect(mGhk, &QGlobalShortcut::error, this, &KeyEdit::error);
connect(this, &KeyEdit::editingFinished, [this] {
mGhk->setKey(this->keySequence());
});
}
KeyEdit::~KeyEdit()
......@@ -122,12 +138,12 @@ KeyEdit::~KeyEdit()
void KeyEdit::clear()
{
mGhk->unsetKey();
QKeySequenceEdit::clear();
mGhk->unsetKey();
}
void KeyEdit::setKey()
void KeyEdit::setKey(QKeySequence key)
{
mGhk->unsetKey();
mGhk->setKey(this->keySequence());
QKeySequenceEdit::setKeySequence(key);
mGhk->setKey(key);
}
......@@ -16,10 +16,11 @@ public:
void clear();
void setKey();
void setKey(QKeySequence key);
signals:
void actived(QKeySequence key);
void error(QString);
private:
QGlobalShortcut* mGhk;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment