1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qlibinputkeyboard_p.h"
5#include <QtCore/QLoggingCategory>
6#include <QtGui/private/qguiapplication_p.h>
7#include <QtGui/private/qinputdevicemanager_p.h>
8#include <qpa/qwindowsysteminterface.h>
9#include <libinput.h>
10#if QT_CONFIG(xkbcommon)
11#include <xkbcommon/xkbcommon-keysyms.h>
12#include <xkbcommon/xkbcommon-names.h>
13#include <QtGui/private/qxkbcommon_p.h>
14#endif
15
16QT_BEGIN_NAMESPACE
17
18Q_DECLARE_LOGGING_CATEGORY(qLcLibInput)
19
20#if QT_CONFIG(xkbcommon)
21const int REPEAT_DELAY = 500;
22const int REPEAT_RATE = 100;
23#endif
24
25QLibInputKeyboard::QLibInputKeyboard()
26{
27#if QT_CONFIG(xkbcommon)
28 qCDebug(qLcLibInput) << "Using xkbcommon for key mapping";
29 m_ctx = xkb_context_new(flags: XKB_CONTEXT_NO_FLAGS);
30 if (!m_ctx) {
31 qWarning(msg: "Failed to create xkb context");
32 return;
33 }
34 m_keymap = xkb_keymap_new_from_names(context: m_ctx, names: nullptr, flags: XKB_KEYMAP_COMPILE_NO_FLAGS);
35 if (!m_keymap) {
36 qCWarning(qLcLibInput, "Failed to compile keymap");
37 return;
38 }
39 m_state = xkb_state_new(keymap: m_keymap);
40 if (!m_state) {
41 qCWarning(qLcLibInput, "Failed to create xkb state");
42 return;
43 }
44
45 m_repeatTimer.setSingleShot(true);
46 connect(sender: &m_repeatTimer, signal: &QTimer::timeout, context: this, slot: &QLibInputKeyboard::handleRepeat);
47#else
48 qCWarning(qLcLibInput) << "xkbcommon not available, not performing key mapping";
49#endif
50}
51
52QLibInputKeyboard::~QLibInputKeyboard()
53{
54#if QT_CONFIG(xkbcommon)
55 if (m_state)
56 xkb_state_unref(state: m_state);
57 if (m_keymap)
58 xkb_keymap_unref(keymap: m_keymap);
59 if (m_ctx)
60 xkb_context_unref(context: m_ctx);
61#endif
62}
63
64void QLibInputKeyboard::processKey(libinput_event_keyboard *e)
65{
66#if QT_CONFIG(xkbcommon)
67 if (!m_ctx || !m_keymap || !m_state)
68 return;
69
70 const uint32_t keycode = libinput_event_keyboard_get_key(event: e) + 8;
71 const xkb_keysym_t sym = xkb_state_key_get_one_sym(state: m_state, key: keycode);
72 const bool pressed = libinput_event_keyboard_get_key_state(event: e) == LIBINPUT_KEY_STATE_PRESSED;
73
74 // Modifiers here is the modifier state before the event, i.e. not
75 // including the current key in case it is a modifier. See the XOR
76 // logic in QKeyEvent::modifiers(). ### QTBUG-73826
77 Qt::KeyboardModifiers modifiers = QXkbCommon::modifiers(state: m_state);
78
79 const QString text = QXkbCommon::lookupString(state: m_state, code: keycode);
80 const int qtkey = QXkbCommon::keysymToQtKey(keysym: sym, modifiers, state: m_state, code: keycode);
81
82 xkb_state_update_key(state: m_state, key: keycode, direction: pressed ? XKB_KEY_DOWN : XKB_KEY_UP);
83
84 Qt::KeyboardModifiers modifiersAfterStateChange = QXkbCommon::modifiers(state: m_state, keysym: sym);
85 QGuiApplicationPrivate::inputDeviceManager()->setKeyboardModifiers(modifiersAfterStateChange);
86
87 QWindowSystemInterface::handleExtendedKeyEvent(window: nullptr,
88 type: pressed ? QEvent::KeyPress : QEvent::KeyRelease,
89 key: qtkey, modifiers, nativeScanCode: keycode, nativeVirtualKey: sym, nativeModifiers: modifiers, text);
90
91 if (pressed && xkb_keymap_key_repeats(keymap: m_keymap, key: keycode)) {
92 m_repeatData.qtkey = qtkey;
93 m_repeatData.mods = modifiers;
94 m_repeatData.nativeScanCode = keycode;
95 m_repeatData.virtualKey = sym;
96 m_repeatData.nativeMods = modifiers;
97 m_repeatData.unicodeText = text;
98 m_repeatData.repeatCount = 1;
99 m_repeatTimer.setInterval(REPEAT_DELAY);
100 m_repeatTimer.start();
101 } else if (m_repeatTimer.isActive()) {
102 m_repeatTimer.stop();
103 }
104
105#else
106 Q_UNUSED(e);
107#endif
108}
109
110#if QT_CONFIG(xkbcommon)
111void QLibInputKeyboard::handleRepeat()
112{
113 QWindowSystemInterface::handleExtendedKeyEvent(window: nullptr, type: QEvent::KeyPress,
114 key: m_repeatData.qtkey, modifiers: m_repeatData.mods,
115 nativeScanCode: m_repeatData.nativeScanCode, nativeVirtualKey: m_repeatData.virtualKey, nativeModifiers: m_repeatData.nativeMods,
116 text: m_repeatData.unicodeText, autorep: true, count: m_repeatData.repeatCount);
117 m_repeatData.repeatCount += 1;
118 m_repeatTimer.setInterval(REPEAT_RATE);
119 m_repeatTimer.start();
120}
121#endif
122
123QT_END_NAMESPACE
124

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

source code of qtbase/src/platformsupport/input/libinput/qlibinputkeyboard.cpp