From e673312be8b5b0bbc7fb29a091d258f5659cd4a0 Mon Sep 17 00:00:00 2001 From: reionwong Date: Wed, 18 Aug 2021 06:50:12 +0800 Subject: [PATCH] Refactored shortcut keys --- chotkeys/CMakeLists.txt | 12 +- chotkeys/application.cpp | 41 ++-- chotkeys/application.h | 10 +- chotkeys/hotkeys.cpp | 301 +++++++++++++++++++++++++++ chotkeys/hotkeys.h | 63 ++++++ chotkeys/main.cpp | 12 +- notificationd/main.qml | 0 notificationd/notification.cpp | 0 notificationd/notification.h | 0 notificationd/notificationserver.cpp | 0 notificationd/notificationserver.h | 0 notificationd/notificationsmodel.cpp | 0 notificationd/notificationsmodel.h | 0 13 files changed, 411 insertions(+), 28 deletions(-) create mode 100644 chotkeys/hotkeys.cpp create mode 100644 chotkeys/hotkeys.h create mode 100644 notificationd/main.qml create mode 100644 notificationd/notification.cpp create mode 100644 notificationd/notification.h create mode 100644 notificationd/notificationserver.cpp create mode 100644 notificationd/notificationserver.h create mode 100644 notificationd/notificationsmodel.cpp create mode 100644 notificationd/notificationsmodel.h diff --git a/chotkeys/CMakeLists.txt b/chotkeys/CMakeLists.txt index 62e8c66..188b802 100644 --- a/chotkeys/CMakeLists.txt +++ b/chotkeys/CMakeLists.txt @@ -1,9 +1,11 @@ -find_package(Qt5 COMPONENTS Core DBus REQUIRED) -find_package(KF5GlobalAccel REQUIRED) +find_package(Qt5 COMPONENTS Core Widgets DBus X11Extras REQUIRED) +find_package(XCB MODULE REQUIRED COMPONENTS XCB KEYSYMS) +find_package(X11) set(PROJECT_SOURCES main.cpp application.cpp + hotkeys.cpp ) add_executable(chotkeys @@ -13,8 +15,12 @@ add_executable(chotkeys target_link_libraries(chotkeys PRIVATE Qt5::Core + Qt5::Widgets Qt5::DBus - KF5::GlobalAccel + Qt5::X11Extras + ${XCB_LIBS} + ${X11_LIBRARIES} + XCB::KEYSYMS ) install(TARGETS chotkeys RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/chotkeys/application.cpp b/chotkeys/application.cpp index b37b3cc..01e7ccd 100644 --- a/chotkeys/application.cpp +++ b/chotkeys/application.cpp @@ -18,34 +18,41 @@ */ #include "application.h" -#include -#include +#include "hotkeys.h" + #include Application::Application(QObject *parent) : QObject(parent) + , m_hotKeys(new Hotkeys) { setupShortcuts(); + + connect(m_hotKeys, &Hotkeys::pressed, this, &Application::onPressed); + connect(m_hotKeys, &Hotkeys::released, this, &Application::onReleased); } void Application::setupShortcuts() { - QAction *a = addAction("Log Out"); - KGlobalAccel::self()->setGlobalShortcut(a, QList() << Qt::ALT + Qt::CTRL + Qt::Key_Delete); - connect(a, &QAction::triggered, this, [=] { QProcess::startDetached("cutefish-shutdown", QStringList()); }); - - a = addAction("Lock Screen"); - a->setProperty("isConfigurationAction", true); - KGlobalAccel::self()->setDefaultShortcut(a, QList() << Qt::META + Qt::Key_L); - KGlobalAccel::self()->setGlobalShortcut(a, QList() << Qt::META + Qt::Key_L); - connect(a, &QAction::triggered, this, [=] { QProcess::startDetached("cutefish-screenlocker", QStringList()); }); + m_hotKeys->registerKey(QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_Delete)); + m_hotKeys->registerKey(QKeySequence(Qt::META + Qt::Key_L)); + // m_hotKeys->registerKey(QKeySequence(Qt::Key_Super_L)); +} + +void Application::onPressed(QKeySequence keySeq) +{ + if (keySeq.toString() == "Ctrl+Alt+Del") { + QProcess::startDetached("cutefish-shutdown", QStringList()); + } + + if (keySeq.toString() == "Meta+L") { + QProcess::startDetached("cutefish-screenlocker", QStringList()); + } } -QAction *Application::addAction(const QString &name) +void Application::onReleased(QKeySequence keySeq) { - QAction *a = new QAction(this); - a->setProperty("componentDisplayName", QStringLiteral("KWin")); - a->setObjectName(name); - a->setText(name); - return a; + if (keySeq == QKeySequence(Qt::Key_Super_L)) { + QProcess::startDetached("cutefish-launcher", QStringList()); + } } diff --git a/chotkeys/application.h b/chotkeys/application.h index 28e5297..c81efe6 100644 --- a/chotkeys/application.h +++ b/chotkeys/application.h @@ -21,7 +21,7 @@ #define APPLICATION_H #include -#include +#include "hotkeys.h" class Application : public QObject { @@ -32,7 +32,13 @@ public: private: void setupShortcuts(); - QAction *addAction(const QString &name); + +private slots: + void onPressed(QKeySequence keySeq); + void onReleased(QKeySequence keySeq); + +private: + Hotkeys *m_hotKeys; }; #endif // APPLICATION_H diff --git a/chotkeys/hotkeys.cpp b/chotkeys/hotkeys.cpp new file mode 100644 index 0000000..a2b7d82 --- /dev/null +++ b/chotkeys/hotkeys.cpp @@ -0,0 +1,301 @@ +/* + * Copyright (C) 2021 CutefishOS Team. + * + * Author: Reion Wong + * + * 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 3 of the License, or + * 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 program. If not, see . + */ + +#include "hotkeys.h" + +#include +#include +#include +#include +#include + +// #include +// #include + +// XCB & X11 +#include +#include +#include + +#include + +Hotkeys::Hotkeys(QObject *parent) + : QObject(parent) +{ + qApp->installNativeEventFilter(this); +} + +Hotkeys::~Hotkeys() +{ + qApp->removeNativeEventFilter(this); +} + +bool Hotkeys::nativeEventFilter(const QByteArray &eventType, void *message, long *result) +{ + Q_UNUSED(result); + + if (eventType != "xcb_generic_event_t") { + return false; + } + + xcb_generic_event_t *e = static_cast(message); + + if (e->response_type == XCB_KEY_PRESS) { + xcb_key_press_event_t *keyEvent = static_cast(message); + quint32 keycode = keyEvent->detail; + quint32 mods = keyEvent->state; // & (ShiftMask | ControlMask | Mod1Mask | Mod3Mask); + quint32 id = keycode | mods; + +// int keyQt; +// KKeyServer::xcbKeyPressEventToQt(keyEvent, &keyQt); + +// bool found = false; +// for (QKeySequence &seq : m_shortcuts.values()) { +// if (seq == QKeySequence(keyQt)) { +// found = true; +// // emit pressed(seq); +// break; +// } +// } + +// if (!found && m_shortcuts.contains(id)) { +// // emit pressed(m_shortcuts[id]); +// } + +// // Keyboard needs to be ungrabed after XGrabKey() activates the grab, +// // otherwise it becomes frozen. +// xcb_connection_t *c = QX11Info::connection(); +// xcb_void_cookie_t cookie = xcb_ungrab_keyboard_checked(c, XCB_TIME_CURRENT_TIME); +// xcb_flush(c); + +// // xcb_flush() only makes sure that the ungrab keyboard request has been +// // sent, but is not enough to make sure that request has been fulfilled. Use +// // xcb_request_check() to make sure that the request has been processed. +// xcb_request_check(c, cookie); + +// int keyQt; +// if (!KKeyServer::xcbKeyPressEventToQt(keyEvent, &keyQt)) { +// qDebug() << "KKeyServer::xcbKeyPressEventToQt failed"; +// return false; +// } + +// // All that work for this hey... argh... +// if (NET::timestampCompare(keyEvent->time, QX11Info::appTime()) > 0) { +// QX11Info::setAppTime(keyEvent->time); +// } + +// bool found = false; +// for (QKeySequence &seq : m_shortcuts.values()) { +// if (seq == QKeySequence(keyQt)) { +// found = true; +// emit pressed(seq); +// break; +// } +// } + + if (m_shortcuts.contains(id)) { + emit pressed(m_shortcuts[id]); + } + + return true; + + } else if (e->response_type == XCB_KEY_RELEASE) { + xcb_key_release_event_t *keyEvent = static_cast(message); + quint32 keycode = keyEvent->detail; + quint32 mods = keyEvent->state; // & (ShiftMask | ControlMask | Mod1Mask | Mod3Mask); + quint32 id = keycode | mods; + + // META + if (id == 197) { + id = 133; + } + + if (m_shortcuts.contains(id)) { + emit released(m_shortcuts[id]); + } + + return true; + } + + return false; +} + +void Hotkeys::registerKey(QKeySequence keySequence) +{ + if (keySequence.isEmpty()) + return; + + quint32 keycode = nativeKeycode(getKey(keySequence)); + quint32 mods = nativeModifiers(getMods(keySequence)); + quint32 keyId = keycode | mods; + + // META + if (keycode == 204 && mods == 0) { + keycode = 133; + keyId = keycode | mods; + } + + if (!m_shortcuts.contains(keyId)) { + registerKey(keycode, mods); + m_shortcuts.insert(keyId, keySequence); + } +} + +void Hotkeys::registerKey(quint32 keycode) +{ + if (!m_shortcuts.contains(keycode)) { + registerKey(keycode, 0); + m_shortcuts.insert(keycode, QKeySequence(keycode | 0)); + } +} + +void Hotkeys::registerKey(quint32 key, quint32 mods) +{ + xcb_grab_key(QX11Info::connection(), + 1, + QX11Info::appRootWindow(), + mods, + key, + XCB_GRAB_MODE_ASYNC, + XCB_GRAB_MODE_ASYNC); + + xcb_grab_key(QX11Info::connection(), + 1, + QX11Info::appRootWindow(), + mods | XCB_MOD_MASK_2, + key, + XCB_GRAB_MODE_ASYNC, + XCB_GRAB_MODE_ASYNC); +} + +void Hotkeys::unregisterKey(quint32 key, quint32 mods) +{ + xcb_ungrab_key(QX11Info::connection(), key, QX11Info::appRootWindow(), mods); +} + +quint32 Hotkeys::nativeKeycode(Qt::Key k) +{ + /* keysymdef.h */ + quint32 key = 0; + if (k >= Qt::Key_F1 && k <= Qt::Key_F35) { + key = XK_F1 + (k - Qt::Key_F1); + } else if (k >= Qt::Key_Space && k <= Qt::Key_QuoteLeft) { + key = k; + } else if (k >= Qt::Key_BraceLeft && k <= Qt::Key_AsciiTilde) { + key = k; + } else if (k >= Qt::Key_nobreakspace && k <= Qt::Key_ydiaeresis) { + key = k; + } else { + switch (k) { + case Qt::Key_Escape: + key = XK_Escape; + break; + case Qt::Key_Tab: + case Qt::Key_Backtab: + key = XK_Tab; + break; + case Qt::Key_Backspace: + key = XK_BackSpace; + break; + case Qt::Key_Return: + case Qt::Key_Enter: + key = XK_Return; + break; + case Qt::Key_Insert: + key = XK_Insert; + break; + case Qt::Key_Delete: + key = XK_Delete; + break; + case Qt::Key_Pause: + key = XK_Pause; + break; + case Qt::Key_Print: + key = XK_Print; + break; + case Qt::Key_SysReq: + key = XK_Sys_Req; + break; + case Qt::Key_Clear: + key = XK_Clear; + break; + case Qt::Key_Home: + key = XK_Home; + break; + case Qt::Key_End: + key = XK_End; + break; + case Qt::Key_Left: + key = XK_Left; + break; + case Qt::Key_Up: + key = XK_Up; + break; + case Qt::Key_Right: + key = XK_Right; + break; + case Qt::Key_Down: + key = XK_Down; + break; + case Qt::Key_PageUp: + key = XK_Page_Up; + break; + case Qt::Key_PageDown: + key = XK_Page_Down; + break; + default: + key = 0; + } + } + return XKeysymToKeycode(QX11Info::display(), key); +} + +quint32 Hotkeys::nativeModifiers(Qt::KeyboardModifiers m) +{ + quint32 mods = Qt::NoModifier; + + if (m & Qt::ShiftModifier) + mods |= ShiftMask; + if (m & Qt::ControlModifier) + mods |= ControlMask; + if (m & Qt::AltModifier) + mods |= Mod1Mask; + if (m & Qt::MetaModifier) + mods |= Mod4Mask; + + return mods; +} + +Qt::Key Hotkeys::getKey(const QKeySequence &keyseq) +{ + if (keyseq.isEmpty()) { + return Qt::Key(0); + } + + return Qt::Key(keyseq[0] & ~Qt::KeyboardModifierMask); +} + +Qt::KeyboardModifiers Hotkeys::getMods(const QKeySequence &keyseq) +{ + if (keyseq.isEmpty()) { + return Qt::KeyboardModifiers(); + } + + return Qt::KeyboardModifiers(keyseq[0] & Qt::KeyboardModifierMask); +} diff --git a/chotkeys/hotkeys.h b/chotkeys/hotkeys.h new file mode 100644 index 0000000..ecc1537 --- /dev/null +++ b/chotkeys/hotkeys.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2021 CutefishOS Team. + * + * Author: Reion Wong + * + * 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 3 of the License, or + * 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 program. If not, see . + */ + +#ifndef HOTKEYS_H +#define HOTKEYS_H + +#include +#include +#include +#include +#include +#include + +#include + +class Hotkeys : public QObject, public QAbstractNativeEventFilter +{ + Q_OBJECT + +public: + explicit Hotkeys(QObject *parent = nullptr); + ~Hotkeys(); + + bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) override; + + void registerKey(QKeySequence keySequence); + void registerKey(quint32 keycode); + + void registerKey(quint32 key, quint32 mods); + void unregisterKey(quint32 key, quint32 mods); + + +signals: + void pressed(QKeySequence keySeq); + void released(QKeySequence keySeq); + +private: + quint32 nativeKeycode(Qt::Key k); + quint32 nativeModifiers(Qt::KeyboardModifiers m); + Qt::Key getKey(const QKeySequence& keyseq); + Qt::KeyboardModifiers getMods(const QKeySequence& keyseq); + +private: + QHash m_shortcuts; +}; + +#endif // HOTKEYS_H diff --git a/chotkeys/main.cpp b/chotkeys/main.cpp index f4ce134..6f4997b 100644 --- a/chotkeys/main.cpp +++ b/chotkeys/main.cpp @@ -26,13 +26,13 @@ int main(int argc, char *argv[]) QApplication a(argc, argv); a.setQuitOnLastWindowClosed(true); - if (!QDBusConnection::sessionBus().registerService("org.cutefish.Chotkeys")) { - return -1; - } +// if (!QDBusConnection::sessionBus().registerService("org.cutefish.Chotkeys")) { +// return -1; +// } - if (!QDBusConnection::sessionBus().registerObject("/Chotkeys", &a)) { - return -1; - } +// if (!QDBusConnection::sessionBus().registerObject("/Chotkeys", &a)) { +// return -1; +// } Application app; return a.exec(); diff --git a/notificationd/main.qml b/notificationd/main.qml new file mode 100644 index 0000000..e69de29 diff --git a/notificationd/notification.cpp b/notificationd/notification.cpp new file mode 100644 index 0000000..e69de29 diff --git a/notificationd/notification.h b/notificationd/notification.h new file mode 100644 index 0000000..e69de29 diff --git a/notificationd/notificationserver.cpp b/notificationd/notificationserver.cpp new file mode 100644 index 0000000..e69de29 diff --git a/notificationd/notificationserver.h b/notificationd/notificationserver.h new file mode 100644 index 0000000..e69de29 diff --git a/notificationd/notificationsmodel.cpp b/notificationd/notificationsmodel.cpp new file mode 100644 index 0000000..e69de29 diff --git a/notificationd/notificationsmodel.h b/notificationd/notificationsmodel.h new file mode 100644 index 0000000..e69de29