24
24
#include "orientationchangeevent_p.h"
27
#if !defined(QT_NO_DEBUG)
28
27
#include <QtCore/QThread>
30
28
#include <QtCore/qglobal.h>
31
29
#include <QtCore/QCoreApplication>
32
30
#include <private/qguiapplication_p.h>
33
31
#include <qpa/qplatforminputcontext.h>
34
32
#include <qpa/qwindowsysteminterface.h>
36
35
#include <xkbcommon/xkbcommon.h>
37
36
#include <xkbcommon/xkbcommon-keysyms.h>
39
38
#include <mir_toolkit/mir_client_library.h>
40
Q_LOGGING_CATEGORY(ubuntumirclientInput, "ubuntumirclient.input", QtWarningMsg)
43
45
// XKB Keysyms which do not map directly to Qt types (i.e. Unicode points)
44
46
static const uint32_t KeyTable[] = {
110
112
XKB_KEY_MultipleCandidate, Qt::Key_MultipleCandidate,
111
113
XKB_KEY_PreviousCandidate, Qt::Key_PreviousCandidate,
116
XKB_KEY_dead_grave, Qt::Key_Dead_Grave,
117
XKB_KEY_dead_acute, Qt::Key_Dead_Acute,
118
XKB_KEY_dead_circumflex, Qt::Key_Dead_Circumflex,
119
XKB_KEY_dead_tilde, Qt::Key_Dead_Tilde,
120
XKB_KEY_dead_macron, Qt::Key_Dead_Macron,
121
XKB_KEY_dead_breve, Qt::Key_Dead_Breve,
122
XKB_KEY_dead_abovedot, Qt::Key_Dead_Abovedot,
123
XKB_KEY_dead_diaeresis, Qt::Key_Dead_Diaeresis,
124
XKB_KEY_dead_abovering, Qt::Key_Dead_Abovering,
125
XKB_KEY_dead_doubleacute, Qt::Key_Dead_Doubleacute,
126
XKB_KEY_dead_caron, Qt::Key_Dead_Caron,
127
XKB_KEY_dead_cedilla, Qt::Key_Dead_Cedilla,
128
XKB_KEY_dead_ogonek, Qt::Key_Dead_Ogonek,
129
XKB_KEY_dead_iota, Qt::Key_Dead_Iota,
130
XKB_KEY_dead_voiced_sound, Qt::Key_Dead_Voiced_Sound,
131
XKB_KEY_dead_semivoiced_sound, Qt::Key_Dead_Semivoiced_Sound,
132
XKB_KEY_dead_belowdot, Qt::Key_Dead_Belowdot,
133
XKB_KEY_dead_hook, Qt::Key_Dead_Hook,
134
XKB_KEY_dead_horn, Qt::Key_Dead_Horn,
113
136
XKB_KEY_Mode_switch, Qt::Key_Mode_switch,
114
137
XKB_KEY_script_switch, Qt::Key_Mode_switch,
115
138
XKB_KEY_XF86AudioRaiseVolume, Qt::Key_VolumeUp,
146
Qt::WindowState mirSurfaceStateToWindowState(MirSurfaceState state)
149
case mir_surface_state_fullscreen:
150
return Qt::WindowFullScreen;
151
case mir_surface_state_maximized:
152
case mir_surface_state_vertmaximized:
153
case mir_surface_state_horizmaximized:
154
return Qt::WindowMaximized;
155
case mir_surface_state_minimized:
156
return Qt::WindowMinimized;
157
case mir_surface_state_hidden:
158
// We should be handling this state separately.
160
case mir_surface_state_restored:
161
case mir_surface_state_unknown:
163
return Qt::WindowNoState;
123
169
class UbuntuEvent : public QEvent
180
225
case mir_event_type_input:
181
226
return "mir_event_type_input";
183
DLOG("Invalid event type %d", t);
184
228
return "invalid";
187
#endif // LOG_EVENTS != 0
189
232
void UbuntuInput::customEvent(QEvent* event)
191
DASSERT(QThread::currentThread() == thread());
234
Q_ASSERT(QThread::currentThread() == thread());
192
235
UbuntuEvent* ubuntuEvent = static_cast<UbuntuEvent*>(event);
193
236
const MirEvent *nativeEvent = ubuntuEvent->nativeEvent;
195
238
if ((ubuntuEvent->window == nullptr) || (ubuntuEvent->window->window() == nullptr)) {
196
qWarning() << "Attempted to deliver an event to a non-existent window, ignoring.";
239
qCWarning(ubuntumirclient) << "Attempted to deliver an event to a non-existent window, ignoring.";
202
245
if (QWindowSystemInterface::handleNativeEvent(
203
246
ubuntuEvent->window->window(), mEventFilterType,
204
247
const_cast<void *>(static_cast<const void *>(nativeEvent)), &result) == true) {
205
DLOG("event filtered out by native interface");
248
qCDebug(ubuntumirclient, "event filtered out by native interface");
209
#if (LOG_EVENTS != 0)
210
LOG("UbuntuInput::customEvent(type=%s)", nativeEventTypeToStr(mir_event_get_type(nativeEvent)));
252
qCDebug(ubuntumirclientInput, "customEvent(type=%s)", nativeEventTypeToStr(mir_event_get_type(nativeEvent)));
213
254
// Event dispatching.
214
255
switch (mir_event_get_type(nativeEvent))
233
274
case mir_event_type_surface:
235
276
auto surfaceEvent = mir_event_get_surface_event(nativeEvent);
236
if (mir_surface_event_get_attribute(surfaceEvent) == mir_surface_attrib_focus) {
277
auto surfaceEventAttribute = mir_surface_event_get_attribute(surfaceEvent);
279
if (surfaceEventAttribute == mir_surface_attrib_focus) {
237
280
const bool focused = mir_surface_event_get_attribute_value(surfaceEvent) == mir_surface_focused;
238
281
// Mir may have sent a pair of focus lost/gained events, so we need to "peek" into the queue
239
282
// so that we don't deactivate windows prematurely.
241
284
mPendingFocusGainedEvents--;
242
285
ubuntuEvent->window->handleSurfaceFocused();
286
QWindowSystemInterface::handleWindowActivated(ubuntuEvent->window->window(), Qt::ActiveWindowFocusReason);
288
// NB: Since processing of system events is queued, never check qGuiApp->applicationState()
289
// as it might be outdated. Always call handleApplicationStateChanged() with the latest
291
QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive);
243
293
} else if(!mPendingFocusGainedEvents) {
244
DLOG("[ubuntumirclient QPA] No windows have focus");
294
qCDebug(ubuntumirclient, "No windows have focus");
245
295
QWindowSystemInterface::handleWindowActivated(nullptr, Qt::ActiveWindowFocusReason);
296
QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive);
298
} else if (surfaceEventAttribute == mir_surface_attrib_state) {
299
MirSurfaceState state = static_cast<MirSurfaceState>(mir_surface_event_get_attribute_value(surfaceEvent));
301
if (state == mir_surface_state_hidden) {
302
ubuntuEvent->window->handleSurfaceVisibilityChanged(false);
305
ubuntuEvent->window->handleSurfaceVisibilityChanged(true);
306
ubuntuEvent->window->handleSurfaceStateChanged(mirSurfaceStateToWindowState(state));
351
412
mTouchDevice, touchPoints);
354
static uint32_t translateKeysym(uint32_t sym, char *string, size_t size)
415
static uint32_t translateKeysym(uint32_t sym, const QString &text) {
359
if (sym >= XKB_KEY_F1 && sym <= XKB_KEY_F35)
418
QTextCodec *systemCodec = QTextCodec::codecForLocale();
419
if (sym < 128 || (sym < 256 && systemCodec->mibEnum() == 4)) {
420
// upper-case key, if known
421
code = isprint((int)sym) ? toupper((int)sym) : 0;
422
} else if (sym >= XKB_KEY_F1 && sym <= XKB_KEY_F35) {
360
423
return Qt::Key_F1 + (int(sym) - XKB_KEY_F1);
362
for (int i = 0; KeyTable[i]; i += 2) {
363
if (sym == KeyTable[i])
364
return KeyTable[i + 1];
424
} else if (text.length() == 1 && text.unicode()->unicode() > 0x1f
425
&& text.unicode()->unicode() != 0x7f
426
&& !(sym >= XKB_KEY_dead_grave && sym <= XKB_KEY_dead_currency)) {
427
code = text.unicode()->toUpper().unicode();
429
for (int i = 0; KeyTable[i]; i += 2)
430
if (sym == KeyTable[i])
431
code = KeyTable[i + 1];
397
465
ulong timestamp = mir_input_event_get_event_time(event) / 1000000;
398
466
xkb_keysym_t xk_sym = mir_keyboard_event_key_code(key_event);
467
quint32 scan_code = mir_keyboard_event_scan_code(key_event);
468
quint32 native_modifiers = mir_keyboard_event_modifiers(key_event);
400
470
// Key modifier and unicode index mapping.
401
471
auto modifiers = qt_modifiers_from_mir(mir_keyboard_event_modifiers(key_event));
407
477
if (action == mir_keyboard_action_down)
408
478
mLastFocusedWindow = window;
411
int sym = translateKeysym(xk_sym, s, sizeof(s));
412
QString text = QString::fromLatin1(s);
481
QVarLengthArray<char, 32> chars(32);
483
int result = xkb_keysym_to_utf8(xk_sym, chars.data(), chars.size());
486
text = QString::fromUtf8(chars.constData());
489
int sym = translateKeysym(xk_sym, text);
414
491
bool is_auto_rep = action == mir_keyboard_action_repeat;
416
493
QPlatformInputContext *context = QGuiApplicationPrivate::platformIntegration()->inputContext();
418
QKeyEvent qKeyEvent(keyType, sym, modifiers, text, is_auto_rep);
495
QKeyEvent qKeyEvent(keyType, sym, modifiers, scan_code, xk_sym, native_modifiers, text, is_auto_rep);
419
496
qKeyEvent.setTimestamp(timestamp);
420
497
if (context->filterEvent(&qKeyEvent)) {
421
DLOG("key event filtered out by input context");
498
qCDebug(ubuntumirclient, "key event filtered out by input context");
426
QWindowSystemInterface::handleKeyEvent(window->window(), timestamp, keyType, sym, modifiers, text, is_auto_rep);
503
QWindowSystemInterface::handleExtendedKeyEvent(window->window(), timestamp, keyType, sym, modifiers, scan_code, xk_sym, native_modifiers, text, is_auto_rep);
468
545
if (hDelta != 0 || vDelta != 0) {
469
546
const QPoint angleDelta = QPoint(hDelta * 15, vDelta * 15);
470
QWindowSystemInterface::handleWheelEvent(window, timestamp, localPoint, localPoint,
547
QWindowSystemInterface::handleWheelEvent(window, timestamp, localPoint, window->position() + localPoint,
471
548
QPoint(), angleDelta, modifiers, Qt::ScrollUpdate);
473
auto buttons = extract_buttons(pev);
474
if (buttons != Qt::NoButton)
475
mLastFocusedWindow = platformWindow;
476
QWindowSystemInterface::handleMouseEvent(window, timestamp, localPoint, localPoint /* Should we omit global point instead? */,
550
auto buttons = extract_buttons(pev);
551
QWindowSystemInterface::handleMouseEvent(window, timestamp, localPoint, window->position() + localPoint /* Should we omit global point instead? */,
481
555
case mir_pointer_action_enter:
482
QWindowSystemInterface::handleEnterEvent(window, localPoint, localPoint);
556
QWindowSystemInterface::handleEnterEvent(window, localPoint, window->position() + localPoint);
484
558
case mir_pointer_action_leave:
485
559
QWindowSystemInterface::handleLeaveEvent(window);
488
DLOG("Unrecognized pointer event");
562
qCDebug(ubuntumirclient, "Unrecognized pointer event");
492
#if (LOG_EVENTS != 0)
493
566
static const char* nativeOrientationDirectionToStr(MirOrientation orientation)
495
568
switch (orientation) {
509
582
return "INVALID!";
514
586
void UbuntuInput::dispatchOrientationEvent(QWindow *window, const MirOrientationEvent *event)
516
588
MirOrientation mir_orientation = mir_orientation_event_get_direction(event);
517
#if (LOG_EVENTS != 0)
518
// Orientation event logging.
519
LOG("ORIENTATION direction: %s", nativeOrientationDirectionToStr(mir_orientation));
589
qCDebug(ubuntumirclientInput, "orientation direction: %s", nativeOrientationDirectionToStr(mir_orientation));
522
591
if (!window->screen()) {
523
DLOG("Window has no associated screen, dropping orientation event");
592
qCDebug(ubuntumirclient, "Window has no associated screen, dropping orientation event");