Rabbit Remote Control 0.1.0-bate5
Loading...
Searching...
No Matches
NativeEventFilterUnix.cpp
1// Author: Kang Lin <kl222@126.com>
2
3#include "NativeEventFilterUnix.h"
4
5#if defined(Q_OS_WIN)
6#include <windows.h>
7#endif
8#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
9 #include <QtX11Extras/QX11Info>
10#endif
11
12#include <QApplication>
13#include <QLoggingCategory>
14#include <QKeyEvent>
15#include <QProcess>
16
17static Q_LOGGING_CATEGORY(log, "Plugin.Hook.NativeEventFilter")
18
19#include <xcb/xcb.h>
20#include <xcb/xcb_keysyms.h>
21#define XK_MISCELLANY
22// the X11 headers on some systems. See: [Xlib 键符号](https://www.x.org/releases/X11R7.7/doc/libX11/XKB/xkblib.html)
23#include <X11/keysymdef.h>
24
25/*
26void print_modifiers (uint32_t mask)
27{
28 const char **mod, *mods[] = {
29 "Shift", "Lock", "Ctrl", "Alt",
30 "Mod2", "Mod3", "Mod4", "Mod5",
31 "Button1", "Button2", "Button3", "Button4", "Button5"
32 };
33 qDebug(log) << "Modifier mask: ";
34 for (mod = mods ; mask; mask >>= 1, mod++)
35 if (mask & 1)
36 qDebug(log) << *mod;
37}
38//*/
39
40Qt::KeyboardModifiers GetModifiers(uint32_t mask)
41{
42 Qt::KeyboardModifiers modifiers = Qt::NoModifier;
43 if(XCB_KEY_BUT_MASK_SHIFT & mask)
44 modifiers |= Qt::ShiftModifier;
45 if(XCB_KEY_BUT_MASK_CONTROL & mask)
46 modifiers |= Qt::ControlModifier;
47 if(XCB_KEY_BUT_MASK_MOD_1 & mask)
48 modifiers |= Qt::AltModifier;
49 return modifiers;
50}
51
52bool CNativeEventFilterUnix::HandleKey(
53 xcb_keysym_t keysym, QEvent::Type type, Qt::KeyboardModifiers modifiers)
54{
55 int bRet = false;
56 if(!m_pParameterPlugin
57 || !m_pParameterPlugin->GetCaptureAllKeyboard()) {
58 qDebug(log) << "Native window receive keyboard.";
59 return false;
60 }
61
62 int key = 0;
63 switch (keysym) {
64 case XK_Tab:
65 key = Qt::Key_Tab;
66 bRet = true;
67 break;
68 case XK_Meta_L:
69 case XK_Meta_R:
70 key = Qt::Key_Meta;
71 bRet = true;
72 break;
73 case XK_Alt_L:
74 case XK_Alt_R:
75 key = Qt::Key_Alt;
76 bRet = true;
77 break;
78 case XK_Super_L:
79 key = Qt::Key_Super_L;
80 bRet = true;
81 break;
82 case XK_Super_R:
83 key = Qt::Key_Super_R;
84 bRet = true;
85 break;
86 default:
87 break;
88 }
89
90 if(bRet) {
91 CFrmViewer* focus = qobject_cast<CFrmViewer*>(QApplication::focusWidget());
92 if(focus) {
93
94 QKeyEvent* keyEvent = new QKeyEvent(type, key, modifiers);
95 /*
96 QApplication::postEvent(focus, keyEvent);
97 return true;//*/
98 switch(type)
99 {
100 case QEvent::KeyPress:
101 emit focus->sigKeyPressEvent(keyEvent);
102 break;
103 case QEvent::KeyRelease:
104 emit focus->sigKeyReleaseEvent(keyEvent);
105 break;
106 default:
107 break;
108 }
109 // Because the signals is `Qt::DirectConnection`,
110 // so than can delete it in here!
111 // See: CBackendDesktop::SetViewer
112 delete keyEvent;
113 return true;
114 }
115 /*
116 QKeyEvent* keyEvent = new QKeyEvent(type, key, modifiers);
117 qDebug(log) << "Process:" << keyEvent;
118 delete keyEvent;//*/
119 }
120 return false;
121}
122
123bool CNativeEventFilterUnix::HandleEvent(xcb_generic_event_t* event)
124{
125 bool bRet = false;
126
127 switch (event->response_type & ~0x80) {
128 case XCB_KEY_PRESS: {
129 xcb_key_press_event_t *ke = (xcb_key_press_event_t *)event;
130 //print_modifiers(ke->state);
131 int nRet = 0;
132 xcb_keysym_t keysym;
133 nRet = GetKeySym(ke, keysym);
134 if(nRet)
135 break;
136 /*
137 qDebug(log) << "Press Key:" << ke->detail << keysym << GetModifiers(ke->state) << "pressed in window " << ke->event
138 << "root:" << ke->root;//*/
139 bRet = HandleKey(keysym, QEvent::KeyPress, GetModifiers(ke->state));
140 break;
141 }
142 case XCB_KEY_RELEASE: {
143 xcb_key_release_event_t *ke = (xcb_key_release_event_t *)event;
144 //print_modifiers(ke->state);
145 int nRet = 0;
146 xcb_keysym_t keysym;
147 nRet = GetKeySym(ke, keysym);
148 if(nRet)
149 break;
150 /*
151 qDebug(log) << "Release Key:" << ke->detail << keysym << GetModifiers(ke->state) << "pressed in window " << ke->event
152 << "root:" << ke->root;//*/
153 bRet = HandleKey(keysym, QEvent::KeyRelease, GetModifiers(ke->state));
154 break;
155 }
156 default:
157 break;
158 }
159
160 return bRet;
161}
162
163int CNativeEventFilterUnix::GetKeySym(xcb_key_press_event_t *event, xcb_keysym_t &keysym)
164{
165 int nRet = 0;
166 // 将 keycode 转换为 keysym
167 keysym = xcb_key_symbols_get_keysym(m_pKeySymbols, event->detail, 0);
168 // 处理 Shift 组合键
169 if (event->state & XCB_MOD_MASK_SHIFT) {
170 keysym = xcb_key_symbols_get_keysym(m_pKeySymbols, event->detail, 1);
171 }
172 //qDebug(log) << "keycode:" << event->detail << "keySym:" << keysym;
173 return nRet;
174}
175
176void CNativeEventFilterUnix::DisableSuperKeyShortcuts()
177{
178 // GNOME
179 QProcess::execute("gsettings", {"set", "org.gnome.mutter", "overlay-key", ""});
180
181 // KDE (需要检测桌面环境)
182 QString desktop = qEnvironmentVariable("XDG_CURRENT_DESKTOP");
183 if (desktop.contains("KDE", Qt::CaseInsensitive)) {
184 QProcess::execute("kwriteconfig5", {"--file", "kwinrc", "--group", "ModifierOnlyShortcuts", "--key", "Meta", ""});
185 QProcess::execute("kwin_x11", {"--replace"});
186 }
187}
188
189void CNativeEventFilterUnix::RestoreSuperKeyShortcuts()
190{
191 // GNOME
192 QProcess::execute("gsettings", {"reset", "org.gnome.mutter", "overlay-key"});
193
194 // KDE (需要检测桌面环境)
195 QString desktop = qEnvironmentVariable("XDG_CURRENT_DESKTOP");
196 if (desktop.contains("KDE", Qt::CaseInsensitive)) {
197 QProcess::execute("kwriteconfig5", {"--file", "kwinrc", "--group", "ModifierOnlyShortcuts", "--key", "Meta", "org.kde.kglobalaccel,/component/kwin,,invokeShortcut,Show Desktop Grid"});
198 QProcess::execute("kwin_x11", {"--replace"});
199 }
200}
201
202CNativeEventFilterUnix::CNativeEventFilterUnix(CParameterPlugin *pPara)
203 : m_pParameterPlugin(pPara)
204 , m_pKeySymbols(nullptr)
205{
206 // See: https://doc.qt.io/qt-6/extras-changes-qt6.html#changes-to-qt-x11-extras
207 xcb_connection_t *connection = nullptr;
208#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
209 if (auto *x11Application = qGuiApp->nativeInterface<QNativeInterface::QX11Application>()) {
210 connection = x11Application->connection();
211 }
212#else
213 connection = QX11Info::connection();
214#endif
215 // 初始化 Key Symbols
216 m_pKeySymbols = xcb_key_symbols_alloc(connection);
217 if (!m_pKeySymbols) {
218 qCritical(log) << "Unable to allocate symbol table";
219 return;
220 }
221}
222
223CNativeEventFilterUnix::~CNativeEventFilterUnix()
224{
225 // 清理
226 if(m_pKeySymbols)
227 xcb_key_symbols_free(m_pKeySymbols);
228}
229
230#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
231bool CNativeEventFilterUnix::nativeEventFilter(const QByteArray &eventType, void *message, qintptr *result)
232#else
233bool CNativeEventFilterUnix::nativeEventFilter(const QByteArray &eventType, void *message, long *result)
234#endif
235{
236 //qDebug(log) << "eventType:" << eventType;
237
238 if (eventType == "xcb_generic_event_t") {
239 xcb_generic_event_t* e = static_cast<xcb_generic_event_t *>(message);
240 return HandleEvent(e);
241 }
242#if defined(Q_OS_WIN)
243 if (eventType == "windows_generic_MSG" || eventType == "windows_dispatcher_MSG")
244 {
245 MSG *pMsg = reinterpret_cast<MSG *>(message);
246
247 }
248#endif
249 return false;
250}
A widget which displays output image from a CConnectDesktop and sends input keypresses and mouse acti...
Definition FrmViewer.h:48
Global parameters of plugins.