2
* Copyright (C) 2013-2016 Canonical, Ltd.
4
* This program is free software: you can redistribute it and/or modify it under
5
* the terms of the GNU Lesser General Public License version 3, as published by
6
* the Free Software Foundation.
8
* This program is distributed in the hope that it will be useful, but WITHOUT
9
* ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10
* SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
* Lesser General Public License for more details.
13
* You should have received a copy of the GNU Lesser General Public License
14
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17
#include "qteventfeeder.h"
20
#include "timestamp.h"
21
#include "tracepoints.h" // generated from tracepoints.tp
22
#include "screen.h" // NEEDED?
23
#include "screensmodel.h"
25
#include <qpa/qplatforminputcontext.h>
26
#include <qpa/qplatformintegration.h>
27
#include <QGuiApplication>
28
#include <private/qguiapplication_p.h>
32
#include <xkbcommon/xkbcommon.h>
33
#include <xkbcommon/xkbcommon-keysyms.h>
36
#include <debughelpers.h>
38
// XKB Keysyms which do not map directly to Qt types (i.e. Unicode points)
39
static const uint32_t KeyTable[] = {
41
XKB_KEY_Escape, Qt::Key_Escape,
42
XKB_KEY_Tab, Qt::Key_Tab,
43
XKB_KEY_ISO_Left_Tab, Qt::Key_Backtab,
44
XKB_KEY_BackSpace, Qt::Key_Backspace,
45
XKB_KEY_Return, Qt::Key_Return,
46
XKB_KEY_Insert, Qt::Key_Insert,
47
XKB_KEY_Delete, Qt::Key_Delete,
48
XKB_KEY_Clear, Qt::Key_Delete,
49
XKB_KEY_Pause, Qt::Key_Pause,
50
XKB_KEY_Print, Qt::Key_Print,
51
0x1005FF60, Qt::Key_SysReq, // hardcoded Sun SysReq
52
0x1007ff00, Qt::Key_SysReq, // hardcoded X386 SysReq
56
XKB_KEY_Home, Qt::Key_Home,
57
XKB_KEY_End, Qt::Key_End,
58
XKB_KEY_Left, Qt::Key_Left,
59
XKB_KEY_Up, Qt::Key_Up,
60
XKB_KEY_Right, Qt::Key_Right,
61
XKB_KEY_Down, Qt::Key_Down,
62
XKB_KEY_Prior, Qt::Key_PageUp,
63
XKB_KEY_Next, Qt::Key_PageDown,
67
XKB_KEY_Shift_L, Qt::Key_Shift,
68
XKB_KEY_Shift_R, Qt::Key_Shift,
69
XKB_KEY_Shift_Lock, Qt::Key_Shift,
70
XKB_KEY_Control_L, Qt::Key_Control,
71
XKB_KEY_Control_R, Qt::Key_Control,
72
XKB_KEY_Meta_L, Qt::Key_Meta,
73
XKB_KEY_Meta_R, Qt::Key_Meta,
74
XKB_KEY_Alt_L, Qt::Key_Alt,
75
XKB_KEY_Alt_R, Qt::Key_Alt,
76
XKB_KEY_Caps_Lock, Qt::Key_CapsLock,
77
XKB_KEY_Num_Lock, Qt::Key_NumLock,
78
XKB_KEY_Scroll_Lock, Qt::Key_ScrollLock,
79
XKB_KEY_Super_L, Qt::Key_Super_L,
80
XKB_KEY_Super_R, Qt::Key_Super_R,
81
XKB_KEY_Menu, Qt::Key_Menu,
82
XKB_KEY_Hyper_L, Qt::Key_Hyper_L,
83
XKB_KEY_Hyper_R, Qt::Key_Hyper_R,
84
XKB_KEY_Help, Qt::Key_Help,
85
0x1000FF74, Qt::Key_Backtab, // hardcoded HP backtab
86
0x1005FF10, Qt::Key_F11, // hardcoded Sun F36 (labeled F11)
87
0x1005FF11, Qt::Key_F12, // hardcoded Sun F37 (labeled F12)
89
// numeric and function keypad keys
91
XKB_KEY_KP_Space, Qt::Key_Space,
92
XKB_KEY_KP_Tab, Qt::Key_Tab,
93
XKB_KEY_KP_Enter, Qt::Key_Enter,
94
//XKB_KEY_KP_F1, Qt::Key_F1,
95
//XKB_KEY_KP_F2, Qt::Key_F2,
96
//XKB_KEY_KP_F3, Qt::Key_F3,
97
//XKB_KEY_KP_F4, Qt::Key_F4,
98
XKB_KEY_KP_Home, Qt::Key_Home,
99
XKB_KEY_KP_Left, Qt::Key_Left,
100
XKB_KEY_KP_Up, Qt::Key_Up,
101
XKB_KEY_KP_Right, Qt::Key_Right,
102
XKB_KEY_KP_Down, Qt::Key_Down,
103
XKB_KEY_KP_Prior, Qt::Key_PageUp,
104
XKB_KEY_KP_Next, Qt::Key_PageDown,
105
XKB_KEY_KP_End, Qt::Key_End,
106
XKB_KEY_KP_Begin, Qt::Key_Clear,
107
XKB_KEY_KP_Insert, Qt::Key_Insert,
108
XKB_KEY_KP_Delete, Qt::Key_Delete,
109
XKB_KEY_KP_Equal, Qt::Key_Equal,
110
XKB_KEY_KP_Multiply, Qt::Key_Asterisk,
111
XKB_KEY_KP_Add, Qt::Key_Plus,
112
XKB_KEY_KP_Separator, Qt::Key_Comma,
113
XKB_KEY_KP_Subtract, Qt::Key_Minus,
114
XKB_KEY_KP_Decimal, Qt::Key_Period,
115
XKB_KEY_KP_Divide, Qt::Key_Slash,
117
// International input method support keys
119
// International & multi-key character composition
120
XKB_KEY_ISO_Level3_Shift, Qt::Key_AltGr,
121
XKB_KEY_Multi_key, Qt::Key_Multi_key,
122
XKB_KEY_Codeinput, Qt::Key_Codeinput,
123
XKB_KEY_SingleCandidate, Qt::Key_SingleCandidate,
124
XKB_KEY_MultipleCandidate, Qt::Key_MultipleCandidate,
125
XKB_KEY_PreviousCandidate, Qt::Key_PreviousCandidate,
128
XKB_KEY_Mode_switch, Qt::Key_Mode_switch,
129
XKB_KEY_script_switch, Qt::Key_Mode_switch,
131
// Japanese keyboard support
132
XKB_KEY_Kanji, Qt::Key_Kanji,
133
XKB_KEY_Muhenkan, Qt::Key_Muhenkan,
134
//XKB_KEY_Henkan_Mode, Qt::Key_Henkan_Mode,
135
XKB_KEY_Henkan_Mode, Qt::Key_Henkan,
136
XKB_KEY_Henkan, Qt::Key_Henkan,
137
XKB_KEY_Romaji, Qt::Key_Romaji,
138
XKB_KEY_Hiragana, Qt::Key_Hiragana,
139
XKB_KEY_Katakana, Qt::Key_Katakana,
140
XKB_KEY_Hiragana_Katakana, Qt::Key_Hiragana_Katakana,
141
XKB_KEY_Zenkaku, Qt::Key_Zenkaku,
142
XKB_KEY_Hankaku, Qt::Key_Hankaku,
143
XKB_KEY_Zenkaku_Hankaku, Qt::Key_Zenkaku_Hankaku,
144
XKB_KEY_Touroku, Qt::Key_Touroku,
145
XKB_KEY_Massyo, Qt::Key_Massyo,
146
XKB_KEY_Kana_Lock, Qt::Key_Kana_Lock,
147
XKB_KEY_Kana_Shift, Qt::Key_Kana_Shift,
148
XKB_KEY_Eisu_Shift, Qt::Key_Eisu_Shift,
149
XKB_KEY_Eisu_toggle, Qt::Key_Eisu_toggle,
150
//XKB_KEY_Kanji_Bangou, Qt::Key_Kanji_Bangou,
151
//XKB_KEY_Zen_Koho, Qt::Key_Zen_Koho,
152
//XKB_KEY_Mae_Koho, Qt::Key_Mae_Koho,
153
XKB_KEY_Kanji_Bangou, Qt::Key_Codeinput,
154
XKB_KEY_Zen_Koho, Qt::Key_MultipleCandidate,
155
XKB_KEY_Mae_Koho, Qt::Key_PreviousCandidate,
157
#ifdef XKB_KEY_KOREAN
158
// Korean keyboard support
159
XKB_KEY_Hangul, Qt::Key_Hangul,
160
XKB_KEY_Hangul_Start, Qt::Key_Hangul_Start,
161
XKB_KEY_Hangul_End, Qt::Key_Hangul_End,
162
XKB_KEY_Hangul_Hanja, Qt::Key_Hangul_Hanja,
163
XKB_KEY_Hangul_Jamo, Qt::Key_Hangul_Jamo,
164
XKB_KEY_Hangul_Romaja, Qt::Key_Hangul_Romaja,
165
//XKB_KEY_Hangul_Codeinput, Qt::Key_Hangul_Codeinput,
166
XKB_KEY_Hangul_Codeinput, Qt::Key_Codeinput,
167
XKB_KEY_Hangul_Jeonja, Qt::Key_Hangul_Jeonja,
168
XKB_KEY_Hangul_Banja, Qt::Key_Hangul_Banja,
169
XKB_KEY_Hangul_PreHanja, Qt::Key_Hangul_PreHanja,
170
XKB_KEY_Hangul_PostHanja, Qt::Key_Hangul_PostHanja,
171
//XKB_KEY_Hangul_SingleCandidate,Qt::Key_Hangul_SingleCandidate,
172
//XKB_KEY_Hangul_MultipleCandidate,Qt::Key_Hangul_MultipleCandidate,
173
//XKB_KEY_Hangul_PreviousCandidate,Qt::Key_Hangul_PreviousCandidate,
174
XKB_KEY_Hangul_SingleCandidate, Qt::Key_SingleCandidate,
175
XKB_KEY_Hangul_MultipleCandidate,Qt::Key_MultipleCandidate,
176
XKB_KEY_Hangul_PreviousCandidate,Qt::Key_PreviousCandidate,
177
XKB_KEY_Hangul_Special, Qt::Key_Hangul_Special,
178
//XKB_KEY_Hangul_switch, Qt::Key_Hangul_switch,
179
XKB_KEY_Hangul_switch, Qt::Key_Mode_switch,
180
#endif // XKB_KEY_KOREAN
183
XKB_KEY_dead_grave, Qt::Key_Dead_Grave,
184
XKB_KEY_dead_acute, Qt::Key_Dead_Acute,
185
XKB_KEY_dead_circumflex, Qt::Key_Dead_Circumflex,
186
XKB_KEY_dead_tilde, Qt::Key_Dead_Tilde,
187
XKB_KEY_dead_macron, Qt::Key_Dead_Macron,
188
XKB_KEY_dead_breve, Qt::Key_Dead_Breve,
189
XKB_KEY_dead_abovedot, Qt::Key_Dead_Abovedot,
190
XKB_KEY_dead_diaeresis, Qt::Key_Dead_Diaeresis,
191
XKB_KEY_dead_abovering, Qt::Key_Dead_Abovering,
192
XKB_KEY_dead_doubleacute, Qt::Key_Dead_Doubleacute,
193
XKB_KEY_dead_caron, Qt::Key_Dead_Caron,
194
XKB_KEY_dead_cedilla, Qt::Key_Dead_Cedilla,
195
XKB_KEY_dead_ogonek, Qt::Key_Dead_Ogonek,
196
XKB_KEY_dead_iota, Qt::Key_Dead_Iota,
197
XKB_KEY_dead_voiced_sound, Qt::Key_Dead_Voiced_Sound,
198
XKB_KEY_dead_semivoiced_sound, Qt::Key_Dead_Semivoiced_Sound,
199
XKB_KEY_dead_belowdot, Qt::Key_Dead_Belowdot,
200
XKB_KEY_dead_hook, Qt::Key_Dead_Hook,
201
XKB_KEY_dead_horn, Qt::Key_Dead_Horn,
203
// Special keys from X.org - This include multimedia keys,
204
// wireless/bluetooth/uwb keys, special launcher keys, etc.
205
XKB_KEY_XF86Back, Qt::Key_Back,
206
XKB_KEY_XF86Forward, Qt::Key_Forward,
207
XKB_KEY_XF86Stop, Qt::Key_Stop,
208
XKB_KEY_XF86Refresh, Qt::Key_Refresh,
209
XKB_KEY_XF86Favorites, Qt::Key_Favorites,
210
XKB_KEY_XF86AudioMedia, Qt::Key_LaunchMedia,
211
XKB_KEY_XF86OpenURL, Qt::Key_OpenUrl,
212
XKB_KEY_XF86HomePage, Qt::Key_HomePage,
213
XKB_KEY_XF86Search, Qt::Key_Search,
214
XKB_KEY_XF86AudioLowerVolume, Qt::Key_VolumeDown,
215
XKB_KEY_XF86AudioMute, Qt::Key_VolumeMute,
216
XKB_KEY_XF86AudioRaiseVolume, Qt::Key_VolumeUp,
217
XKB_KEY_XF86AudioPlay, Qt::Key_MediaPlay,
218
XKB_KEY_XF86AudioStop, Qt::Key_MediaStop,
219
XKB_KEY_XF86AudioPrev, Qt::Key_MediaPrevious,
220
XKB_KEY_XF86AudioNext, Qt::Key_MediaNext,
221
XKB_KEY_XF86AudioRecord, Qt::Key_MediaRecord,
222
XKB_KEY_XF86AudioPause, Qt::Key_MediaPause,
223
XKB_KEY_XF86Mail, Qt::Key_LaunchMail,
224
XKB_KEY_XF86MyComputer, Qt::Key_Launch0, // ### Qt 6: remap properly
225
XKB_KEY_XF86Calculator, Qt::Key_Launch1,
226
XKB_KEY_XF86Memo, Qt::Key_Memo,
227
XKB_KEY_XF86ToDoList, Qt::Key_ToDoList,
228
XKB_KEY_XF86Calendar, Qt::Key_Calendar,
229
XKB_KEY_XF86PowerDown, Qt::Key_PowerDown,
230
XKB_KEY_XF86ContrastAdjust, Qt::Key_ContrastAdjust,
231
XKB_KEY_XF86Standby, Qt::Key_Standby,
232
XKB_KEY_XF86MonBrightnessUp, Qt::Key_MonBrightnessUp,
233
XKB_KEY_XF86MonBrightnessDown, Qt::Key_MonBrightnessDown,
234
XKB_KEY_XF86KbdLightOnOff, Qt::Key_KeyboardLightOnOff,
235
XKB_KEY_XF86KbdBrightnessUp, Qt::Key_KeyboardBrightnessUp,
236
XKB_KEY_XF86KbdBrightnessDown, Qt::Key_KeyboardBrightnessDown,
237
XKB_KEY_XF86PowerOff, Qt::Key_PowerOff,
238
XKB_KEY_XF86WakeUp, Qt::Key_WakeUp,
239
XKB_KEY_XF86Eject, Qt::Key_Eject,
240
XKB_KEY_XF86ScreenSaver, Qt::Key_ScreenSaver,
241
XKB_KEY_XF86WWW, Qt::Key_WWW,
242
XKB_KEY_XF86Sleep, Qt::Key_Sleep,
243
XKB_KEY_XF86LightBulb, Qt::Key_LightBulb,
244
XKB_KEY_XF86Shop, Qt::Key_Shop,
245
XKB_KEY_XF86History, Qt::Key_History,
246
XKB_KEY_XF86AddFavorite, Qt::Key_AddFavorite,
247
XKB_KEY_XF86HotLinks, Qt::Key_HotLinks,
248
XKB_KEY_XF86BrightnessAdjust, Qt::Key_BrightnessAdjust,
249
XKB_KEY_XF86Finance, Qt::Key_Finance,
250
XKB_KEY_XF86Community, Qt::Key_Community,
251
XKB_KEY_XF86AudioRewind, Qt::Key_AudioRewind,
252
XKB_KEY_XF86BackForward, Qt::Key_BackForward,
253
XKB_KEY_XF86ApplicationLeft, Qt::Key_ApplicationLeft,
254
XKB_KEY_XF86ApplicationRight, Qt::Key_ApplicationRight,
255
XKB_KEY_XF86Book, Qt::Key_Book,
256
XKB_KEY_XF86CD, Qt::Key_CD,
257
XKB_KEY_XF86Calculater, Qt::Key_Calculator,
258
XKB_KEY_XF86Clear, Qt::Key_Clear,
259
XKB_KEY_XF86ClearGrab, Qt::Key_ClearGrab,
260
XKB_KEY_XF86Close, Qt::Key_Close,
261
XKB_KEY_XF86Copy, Qt::Key_Copy,
262
XKB_KEY_XF86Cut, Qt::Key_Cut,
263
XKB_KEY_XF86Display, Qt::Key_Display,
264
XKB_KEY_XF86DOS, Qt::Key_DOS,
265
XKB_KEY_XF86Documents, Qt::Key_Documents,
266
XKB_KEY_XF86Excel, Qt::Key_Excel,
267
XKB_KEY_XF86Explorer, Qt::Key_Explorer,
268
XKB_KEY_XF86Game, Qt::Key_Game,
269
XKB_KEY_XF86Go, Qt::Key_Go,
270
XKB_KEY_XF86iTouch, Qt::Key_iTouch,
271
XKB_KEY_XF86LogOff, Qt::Key_LogOff,
272
XKB_KEY_XF86Market, Qt::Key_Market,
273
XKB_KEY_XF86Meeting, Qt::Key_Meeting,
274
XKB_KEY_XF86MenuKB, Qt::Key_MenuKB,
275
XKB_KEY_XF86MenuPB, Qt::Key_MenuPB,
276
XKB_KEY_XF86MySites, Qt::Key_MySites,
277
XKB_KEY_XF86New, Qt::Key_New,
278
XKB_KEY_XF86News, Qt::Key_News,
279
XKB_KEY_XF86OfficeHome, Qt::Key_OfficeHome,
280
XKB_KEY_XF86Open, Qt::Key_Open,
281
XKB_KEY_XF86Option, Qt::Key_Option,
282
XKB_KEY_XF86Paste, Qt::Key_Paste,
283
XKB_KEY_XF86Phone, Qt::Key_Phone,
284
XKB_KEY_XF86Reply, Qt::Key_Reply,
285
XKB_KEY_XF86Reload, Qt::Key_Reload,
286
XKB_KEY_XF86RotateWindows, Qt::Key_RotateWindows,
287
XKB_KEY_XF86RotationPB, Qt::Key_RotationPB,
288
XKB_KEY_XF86RotationKB, Qt::Key_RotationKB,
289
XKB_KEY_XF86Save, Qt::Key_Save,
290
XKB_KEY_XF86Send, Qt::Key_Send,
291
XKB_KEY_XF86Spell, Qt::Key_Spell,
292
XKB_KEY_XF86SplitScreen, Qt::Key_SplitScreen,
293
XKB_KEY_XF86Support, Qt::Key_Support,
294
XKB_KEY_XF86TaskPane, Qt::Key_TaskPane,
295
XKB_KEY_XF86Terminal, Qt::Key_Terminal,
296
XKB_KEY_XF86Tools, Qt::Key_Tools,
297
XKB_KEY_XF86Travel, Qt::Key_Travel,
298
XKB_KEY_XF86Video, Qt::Key_Video,
299
XKB_KEY_XF86Word, Qt::Key_Word,
300
XKB_KEY_XF86Xfer, Qt::Key_Xfer,
301
XKB_KEY_XF86ZoomIn, Qt::Key_ZoomIn,
302
XKB_KEY_XF86ZoomOut, Qt::Key_ZoomOut,
303
XKB_KEY_XF86Away, Qt::Key_Away,
304
XKB_KEY_XF86Messenger, Qt::Key_Messenger,
305
XKB_KEY_XF86WebCam, Qt::Key_WebCam,
306
XKB_KEY_XF86MailForward, Qt::Key_MailForward,
307
XKB_KEY_XF86Pictures, Qt::Key_Pictures,
308
XKB_KEY_XF86Music, Qt::Key_Music,
309
XKB_KEY_XF86Battery, Qt::Key_Battery,
310
XKB_KEY_XF86Bluetooth, Qt::Key_Bluetooth,
311
XKB_KEY_XF86WLAN, Qt::Key_WLAN,
312
XKB_KEY_XF86UWB, Qt::Key_UWB,
313
XKB_KEY_XF86AudioForward, Qt::Key_AudioForward,
314
XKB_KEY_XF86AudioRepeat, Qt::Key_AudioRepeat,
315
XKB_KEY_XF86AudioRandomPlay, Qt::Key_AudioRandomPlay,
316
XKB_KEY_XF86Subtitle, Qt::Key_Subtitle,
317
XKB_KEY_XF86AudioCycleTrack, Qt::Key_AudioCycleTrack,
318
XKB_KEY_XF86Time, Qt::Key_Time,
319
XKB_KEY_XF86Select, Qt::Key_Select,
320
XKB_KEY_XF86View, Qt::Key_View,
321
XKB_KEY_XF86TopMenu, Qt::Key_TopMenu,
322
XKB_KEY_XF86Red, Qt::Key_Red,
323
XKB_KEY_XF86Green, Qt::Key_Green,
324
XKB_KEY_XF86Yellow, Qt::Key_Yellow,
325
XKB_KEY_XF86Blue, Qt::Key_Blue,
326
XKB_KEY_XF86Bluetooth, Qt::Key_Bluetooth,
327
XKB_KEY_XF86Suspend, Qt::Key_Suspend,
328
XKB_KEY_XF86Hibernate, Qt::Key_Hibernate,
329
XKB_KEY_XF86TouchpadToggle, Qt::Key_TouchpadToggle,
330
XKB_KEY_XF86TouchpadOn, Qt::Key_TouchpadOn,
331
XKB_KEY_XF86TouchpadOff, Qt::Key_TouchpadOff,
332
XKB_KEY_XF86AudioMicMute, Qt::Key_MicMute,
333
XKB_KEY_XF86Launch0, Qt::Key_Launch2, // ### Qt 6: remap properly
334
XKB_KEY_XF86Launch1, Qt::Key_Launch3,
335
XKB_KEY_XF86Launch2, Qt::Key_Launch4,
336
XKB_KEY_XF86Launch3, Qt::Key_Launch5,
337
XKB_KEY_XF86Launch4, Qt::Key_Launch6,
338
XKB_KEY_XF86Launch5, Qt::Key_Launch7,
339
XKB_KEY_XF86Launch6, Qt::Key_Launch8,
340
XKB_KEY_XF86Launch7, Qt::Key_Launch9,
341
XKB_KEY_XF86Launch8, Qt::Key_LaunchA,
342
XKB_KEY_XF86Launch9, Qt::Key_LaunchB,
343
XKB_KEY_XF86LaunchA, Qt::Key_LaunchC,
344
XKB_KEY_XF86LaunchB, Qt::Key_LaunchD,
345
XKB_KEY_XF86LaunchC, Qt::Key_LaunchE,
346
XKB_KEY_XF86LaunchD, Qt::Key_LaunchF,
347
XKB_KEY_XF86LaunchE, Qt::Key_LaunchG,
348
XKB_KEY_XF86LaunchF, Qt::Key_LaunchH,
353
static uint32_t translateKeysym(uint32_t sym, const QString &text) {
356
QTextCodec *systemCodec = QTextCodec::codecForLocale();
357
if (sym < 128 || (sym < 256 && systemCodec->mibEnum() == 4)) {
358
// upper-case key, if known
359
code = isprint((int)sym) ? toupper((int)sym) : 0;
360
} else if (sym >= XKB_KEY_F1 && sym <= XKB_KEY_F35) {
361
return Qt::Key_F1 + (int(sym) - XKB_KEY_F1);
362
} else if (text.length() == 1 && text.unicode()->unicode() > 0x1f
363
&& text.unicode()->unicode() != 0x7f
364
&& !(sym >= XKB_KEY_dead_grave && sym <= XKB_KEY_dead_currency)) {
365
code = text.unicode()->toUpper().unicode();
367
for (int i = 0; KeyTable[i]; i += 2)
368
if (sym == KeyTable[i])
369
code = KeyTable[i + 1];
377
class QtWindowSystem : public QtEventFeeder::QtWindowSystemInterface
382
// because we're using QMetaObject::invoke with arguments of those types
383
qRegisterMetaType<Qt::KeyboardModifiers>("Qt::KeyboardModifiers");
384
qRegisterMetaType<Qt::MouseButtons>("Qt::MouseButtons");
387
void setScreensModel(const QSharedPointer<ScreensModel> &sc) override
392
virtual QWindow* focusedWindow() override
394
return QGuiApplication::focusWindow();
397
QWindow* getWindowForTouchPoint(const QPoint &point) override //FIXME: not efficient, not updating focused window
399
return m_screensModel->getWindowForPoint(point);
402
void registerTouchDevice(QTouchDevice *device) override
404
QWindowSystemInterface::registerTouchDevice(device);
407
void handleExtendedKeyEvent(QWindow *window, ulong timestamp, QEvent::Type type, int key,
408
Qt::KeyboardModifiers modifiers,
409
quint32 nativeScanCode, quint32 nativeVirtualKey,
410
quint32 nativeModifiers,
411
const QString& text, bool autorep, ushort count) override
413
QWindowSystemInterface::handleExtendedKeyEvent(window, timestamp, type, key, modifiers,
414
nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorep, count);
417
void handleTouchEvent(QWindow *window, ulong timestamp, QTouchDevice *device,
418
const QList<struct QWindowSystemInterface::TouchPoint> &points, Qt::KeyboardModifiers mods) override
420
QWindowSystemInterface::handleTouchEvent(window, timestamp, device, points, mods);
423
void handleMouseEvent(ulong timestamp, QPointF movement, Qt::MouseButtons buttons,
424
Qt::KeyboardModifiers modifiers) override
426
// Send to the first screen that handles the mouse event
427
// TODO: Have a mechanism to tell which screen currently has the logical mouse pointer
428
// (because they all might have their own separate graphical mouse pointer item)
429
// This will probably come once we implement the feature of having the mouse pointer
430
// crossing adjacent screens.
432
QList<Screen*> screens = m_screensModel->screens();
433
bool eventHandled = false;
435
while (i < screens.count() && !eventHandled) {
436
auto platformCursor = static_cast<qtmir::Cursor*>(screens[i]->cursor());
437
eventHandled = platformCursor->handleMouseEvent(timestamp, movement, buttons, modifiers);
442
void handleWheelEvent(ulong timestamp, QPoint angleDelta, Qt::KeyboardModifiers mods) override
444
// Send to the first screen that handles the mouse event
445
// TODO: Have a mechanism to tell which screen currently has the logical mouse pointer
446
// (because they all might have their own separate graphical mouse pointer item)
447
// This will probably come once we implement the feature of having the mouse pointer
448
// crossing adjacent screens.
450
QList<Screen*> screens = m_screensModel->screens();
451
bool eventHandled = false;
453
while (i < screens.count() && !eventHandled) {
454
auto platformCursor = static_cast<qtmir::Cursor*>(screens.at(i)->cursor());
455
eventHandled = platformCursor->handleWheelEvent(timestamp, angleDelta, mods);
461
QSharedPointer<ScreensModel> m_screensModel;
464
} // anonymous namespace
466
QtEventFeeder::QtEventFeeder(const QSharedPointer<ScreensModel> &screensModel)
467
: QtEventFeeder(screensModel, new QtWindowSystem)
471
QtEventFeeder::QtEventFeeder(const QSharedPointer<ScreensModel> &screensModel,
472
QtEventFeeder::QtWindowSystemInterface *windowSystem)
473
: mQtWindowSystem(windowSystem)
475
// Initialize touch device. Hardcoded just like in qtubuntu
476
// TODO: Create them from info gathered from Mir and store things like device id and source
477
// in a QTouchDevice-derived class created by us. So that we can properly assemble back
478
// MirEvents our of QTouchEvents to give to mir::scene::Surface::consume.
479
mTouchDevice = new QTouchDevice(); // Qt takes ownership of mTouchDevice with registerTouchDevice
480
mTouchDevice->setType(QTouchDevice::TouchScreen);
481
mTouchDevice->setCapabilities(
482
QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::Pressure |
483
QTouchDevice::NormalizedPosition);
484
mQtWindowSystem->setScreensModel(screensModel);
485
mQtWindowSystem->registerTouchDevice(mTouchDevice);
488
QtEventFeeder::~QtEventFeeder()
490
delete mQtWindowSystem;
493
bool QtEventFeeder::dispatch(MirEvent const& event)
495
auto type = mir_event_get_type(&event);
496
if (type != mir_event_type_input)
499
auto iev = mir_event_get_input_event(&event);
501
switch (mir_input_event_get_type(iev)) {
502
case mir_input_event_type_key:
505
case mir_input_event_type_touch:
508
case mir_input_event_type_pointer:
509
dispatchPointer(iev);
520
Qt::KeyboardModifiers getQtModifiersFromMir(MirInputEventModifiers modifiers)
522
Qt::KeyboardModifiers qtModifiers = Qt::NoModifier;
523
if (modifiers & mir_input_event_modifier_shift) {
524
qtModifiers |= Qt::ShiftModifier;
526
if (modifiers & mir_input_event_modifier_ctrl) {
527
qtModifiers |= Qt::ControlModifier;
529
if (modifiers & mir_input_event_modifier_alt) {
530
qtModifiers |= Qt::AltModifier;
532
if (modifiers & mir_input_event_modifier_meta) {
533
qtModifiers |= Qt::MetaModifier;
535
if (modifiers & mir_input_event_modifier_alt_right) {
536
qtModifiers |= Qt::GroupSwitchModifier;
541
Qt::MouseButtons getQtMouseButtonsfromMirPointerEvent(MirPointerEvent const* pev)
543
Qt::MouseButtons buttons = Qt::NoButton;
544
if (mir_pointer_event_button_state(pev, mir_pointer_button_primary))
545
buttons |= Qt::LeftButton;
546
if (mir_pointer_event_button_state(pev, mir_pointer_button_secondary))
547
buttons |= Qt::RightButton;
548
if (mir_pointer_event_button_state(pev, mir_pointer_button_tertiary))
549
buttons |= Qt::MiddleButton;
550
if (mir_pointer_event_button_state(pev, mir_pointer_button_back))
551
buttons |= Qt::BackButton;
552
if (mir_pointer_event_button_state(pev, mir_pointer_button_forward))
553
buttons |= Qt::ForwardButton;
559
void QtEventFeeder::dispatchPointer(MirInputEvent const* ev)
561
auto timestamp = qtmir::compressTimestamp<qtmir::Timestamp>(std::chrono::nanoseconds(mir_input_event_get_event_time(ev)));
562
auto pev = mir_input_event_get_pointer_event(ev);
563
auto action = mir_pointer_event_action(pev);
564
qCDebug(QTMIR_MIR_INPUT) << "Received" << qPrintable(mirPointerEventToString(pev));
566
auto modifiers = getQtModifiersFromMir(mir_pointer_event_modifiers(pev));
568
auto movement = QPointF(mir_pointer_event_axis_value(pev, mir_pointer_axis_relative_x),
569
mir_pointer_event_axis_value(pev, mir_pointer_axis_relative_y));
572
case mir_pointer_action_button_up:
573
case mir_pointer_action_button_down:
574
case mir_pointer_action_motion:
576
const float hDelta = mir_pointer_event_axis_value(pev, mir_pointer_axis_hscroll);
577
const float vDelta = mir_pointer_event_axis_value(pev, mir_pointer_axis_vscroll);
579
if (hDelta != 0 || vDelta != 0) {
580
const QPoint angleDelta = QPoint(hDelta * 15, vDelta * 15);
581
mQtWindowSystem->handleWheelEvent(timestamp.count(), angleDelta, modifiers);
583
auto buttons = getQtMouseButtonsfromMirPointerEvent(pev);
584
mQtWindowSystem->handleMouseEvent(timestamp.count(), movement, buttons, modifiers);
588
qCDebug(QTMIR_MIR_INPUT) << "Unrecognized pointer event";
592
void QtEventFeeder::dispatchKey(MirInputEvent const* event)
594
auto timestamp = qtmir::compressTimestamp<qtmir::Timestamp>(std::chrono::nanoseconds(mir_input_event_get_event_time(event)));
596
auto kev = mir_input_event_get_keyboard_event(event);
597
xkb_keysym_t xk_sym = mir_keyboard_event_key_code(kev);
599
// Key modifier and unicode index mapping.
600
auto modifiers = getQtModifiersFromMir(mir_keyboard_event_modifiers(kev));
603
QEvent::Type keyType = QEvent::KeyRelease;
604
bool is_auto_rep = false;
606
switch (mir_keyboard_event_action(kev))
608
case mir_keyboard_action_repeat:
609
is_auto_rep = true; // fall-through
610
case mir_keyboard_action_down:
611
keyType = QEvent::KeyPress;
613
case mir_keyboard_action_up:
614
keyType = QEvent::KeyRelease;
620
// Key event propagation.
622
QVarLengthArray<char, 32> chars(32);
624
int result = xkb_keysym_to_utf8(xk_sym, chars.data(), chars.size());
627
text = QString::fromUtf8(chars.constData());
630
int keyCode = translateKeysym(xk_sym, text);
632
QPlatformInputContext* context = QGuiApplicationPrivate::platformIntegration()->inputContext();
634
// TODO: consider event.repeat_count
635
QKeyEvent qKeyEvent(keyType, keyCode, modifiers,
636
mir_keyboard_event_scan_code(kev),
637
mir_keyboard_event_key_code(kev),
638
mir_keyboard_event_modifiers(kev),
640
qKeyEvent.setTimestamp(timestamp.count());
641
if (context->filterEvent(&qKeyEvent)) {
642
qCDebug(QTMIR_MIR_INPUT) << "Received" << qPrintable(mirKeyboardEventToString(kev))
643
<< "but not dispatching as it was filtered out by input context";
648
qCDebug(QTMIR_MIR_INPUT).nospace() << "Received" << qPrintable(mirKeyboardEventToString(kev))
649
<< ". Dispatching to " << mQtWindowSystem->focusedWindow();
651
mQtWindowSystem->handleExtendedKeyEvent(mQtWindowSystem->focusedWindow(),
652
timestamp.count(), keyType, keyCode, modifiers,
653
mir_keyboard_event_scan_code(kev), xk_sym,
654
mir_keyboard_event_modifiers(kev), text, is_auto_rep);
657
void QtEventFeeder::dispatchTouch(MirInputEvent const* event)
659
auto timestamp = qtmir::compressTimestamp<qtmir::Timestamp>(std::chrono::nanoseconds(mir_input_event_get_event_time(event)));
661
tracepoint(qtmirserver, touchEventDispatch_start, std::chrono::nanoseconds(timestamp).count());
663
auto tev = mir_input_event_get_touch_event(event);
664
qCDebug(QTMIR_MIR_INPUT) << "Received" << qPrintable(mirTouchEventToString(tev));
666
// FIXME(loicm) Max pressure is device specific. That one is for the Samsung Galaxy Nexus. That
667
// needs to be fixed as soon as the compat input lib adds query support.
668
const float kMaxPressure = 1.28;
669
const int kPointerCount = mir_touch_event_point_count(tev);
670
QList<QWindowSystemInterface::TouchPoint> touchPoints;
671
QWindow *window = nullptr;
673
if (kPointerCount > 0) {
674
window = mQtWindowSystem->getWindowForTouchPoint(
675
QPoint(mir_touch_event_axis_value(tev, 0, mir_touch_axis_x),
676
mir_touch_event_axis_value(tev, 0, mir_touch_axis_y)));
679
qCDebug(QTMIR_MIR_INPUT) << "REJECTING INPUT EVENT, no matching window";
683
const QRect kWindowGeometry = window->geometry();
685
// TODO: Is it worth setting the Qt::TouchPointStationary ones? Currently they are left
686
// as Qt::TouchPointMoved
687
for (int i = 0; i < kPointerCount; ++i) {
688
QWindowSystemInterface::TouchPoint touchPoint;
690
const float kX = mir_touch_event_axis_value(tev, i, mir_touch_axis_x);
691
const float kY = mir_touch_event_axis_value(tev, i, mir_touch_axis_y);
692
const float kW = mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_major);
693
const float kH = mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_minor);
694
const float kP = mir_touch_event_axis_value(tev, i, mir_touch_axis_pressure);
695
touchPoint.id = mir_touch_event_id(tev, i);
697
touchPoint.normalPosition = QPointF(kX / kWindowGeometry.width(), kY / kWindowGeometry.height());
698
touchPoint.area = QRectF(kX - (kW / 2.0), kY - (kH / 2.0), kW, kH);
699
touchPoint.pressure = kP / kMaxPressure;
700
switch (mir_touch_event_action(tev, i))
702
case mir_touch_action_up:
703
touchPoint.state = Qt::TouchPointReleased;
705
case mir_touch_action_down:
706
touchPoint.state = Qt::TouchPointPressed;
708
case mir_touch_action_change:
709
touchPoint.state = Qt::TouchPointMoved;
715
touchPoints.append(touchPoint);
719
// Qt needs a happy, sane stream of touch events. So let's make sure we're not forwarding
721
validateTouches(window, timestamp.count(), touchPoints);
723
// Touch event propagation.
724
qCDebug(QTMIR_MIR_INPUT) << "Sending to Qt" << qPrintable(touchesToString(touchPoints));
725
mQtWindowSystem->handleTouchEvent(window,
726
//scales down the nsec_t (int64) to fit a ulong, precision lost but time difference suitable
731
tracepoint(qtmirserver, touchEventDispatch_end, std::chrono::nanoseconds(timestamp).count());
734
void QtEventFeeder::start()
739
void QtEventFeeder::stop()
744
void QtEventFeeder::validateTouches(QWindow *window, ulong timestamp,
745
QList<QWindowSystemInterface::TouchPoint> &touchPoints)
747
QSet<int> updatedTouches;
751
while (i < touchPoints.count()) {
752
bool mustDiscardTouch = !validateTouch(touchPoints[i]);
753
if (mustDiscardTouch) {
754
touchPoints.removeAt(i);
756
updatedTouches.insert(touchPoints.at(i).id);
762
// Release all unmentioned touches, one by one.
763
QHash<int, QWindowSystemInterface::TouchPoint>::iterator it = mActiveTouches.begin();
764
while (it != mActiveTouches.end()) {
765
if (!updatedTouches.contains(it.key())) {
766
qCWarning(QTMIR_MIR_INPUT)
767
<< "There's a touch (id =" << it.key() << ") missing. Releasing it.";
768
sendActiveTouchRelease(window, timestamp, it.key());
769
it = mActiveTouches.erase(it);
775
// update mActiveTouches
776
for (int i = 0; i < touchPoints.count(); ++i) {
777
auto &touchPoint = touchPoints.at(i);
778
if (touchPoint.state == Qt::TouchPointReleased) {
779
mActiveTouches.remove(touchPoint.id);
781
mActiveTouches[touchPoint.id] = touchPoint;
786
void QtEventFeeder::sendActiveTouchRelease(QWindow *window, ulong timestamp, int id)
788
QList<QWindowSystemInterface::TouchPoint> touchPoints = mActiveTouches.values();
790
for (int i = 0; i < touchPoints.count(); ++i) {
791
QWindowSystemInterface::TouchPoint &touchPoint = touchPoints[i];
792
if (touchPoint.id == id) {
793
touchPoint.state = Qt::TouchPointReleased;
795
touchPoint.state = Qt::TouchPointStationary;
799
qCDebug(QTMIR_MIR_INPUT) << "Sending to Qt" << qPrintable(touchesToString(touchPoints));
800
mQtWindowSystem->handleTouchEvent(window, timestamp, mTouchDevice, touchPoints);
803
bool QtEventFeeder::validateTouch(QWindowSystemInterface::TouchPoint &touchPoint)
807
switch (touchPoint.state) {
808
case Qt::TouchPointPressed:
809
if (mActiveTouches.contains(touchPoint.id)) {
810
qCWarning(QTMIR_MIR_INPUT)
811
<< "Would press an already existing touch (id =" << touchPoint.id
812
<< "). Making it move instead.";
813
touchPoint.state = Qt::TouchPointMoved;
816
case Qt::TouchPointMoved:
817
if (!mActiveTouches.contains(touchPoint.id)) {
818
qCWarning(QTMIR_MIR_INPUT)
819
<< "Would move a touch that wasn't pressed before (id =" << touchPoint.id
820
<< "). Making it press instead.";
821
touchPoint.state = Qt::TouchPointPressed;
824
case Qt::TouchPointStationary:
825
if (!mActiveTouches.contains(touchPoint.id)) {
826
qCWarning(QTMIR_MIR_INPUT)
827
<< "There's an stationary touch that wasn't pressed before (id =" << touchPoint.id
828
<< "). Making it press instead.";
829
touchPoint.state = Qt::TouchPointPressed;
832
case Qt::TouchPointReleased:
833
if (!mActiveTouches.contains(touchPoint.id)) {
834
qCWarning(QTMIR_MIR_INPUT)
835
<< "Would release a touch that wasn't pressed before (id =" << touchPoint.id
836
<< "). Ignoring it.";
841
qFatal("QtEventFeeder: invalid touch state");
847
QString QtEventFeeder::touchesToString(const QList<struct QWindowSystemInterface::TouchPoint> &points)
850
for (int i = 0; i < points.count(); ++i) {
854
const struct QWindowSystemInterface::TouchPoint &point = points.at(i);
855
result.append(QString("(id=%1,state=%2,normalPosition=(%3,%4))")
857
.arg(touchPointStateToString(point.state))
858
.arg(point.normalPosition.x())
859
.arg(point.normalPosition.y())