1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the plugins module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qlibinputkeyboard_p.h"
41#include <QtCore/QTextCodec>
42#include <QtCore/QLoggingCategory>
43#include <QtGui/private/qguiapplication_p.h>
44#include <QtGui/private/qinputdevicemanager_p.h>
45#include <qpa/qwindowsysteminterface.h>
46#include <libinput.h>
47#if QT_CONFIG(xkbcommon)
48#include <xkbcommon/xkbcommon-keysyms.h>
49#include <xkbcommon/xkbcommon-names.h>
50#include <QtXkbCommonSupport/private/qxkbcommon_p.h>
51#endif
52
53QT_BEGIN_NAMESPACE
54
55Q_DECLARE_LOGGING_CATEGORY(qLcLibInput)
56
57const int REPEAT_DELAY = 500;
58const int REPEAT_RATE = 100;
59
60QLibInputKeyboard::QLibInputKeyboard()
61{
62#if QT_CONFIG(xkbcommon)
63 qCDebug(qLcLibInput) << "Using xkbcommon for key mapping";
64 m_ctx = xkb_context_new(flags: XKB_CONTEXT_NO_FLAGS);
65 if (!m_ctx) {
66 qWarning(msg: "Failed to create xkb context");
67 return;
68 }
69 m_keymap = xkb_keymap_new_from_names(context: m_ctx, names: nullptr, flags: XKB_KEYMAP_COMPILE_NO_FLAGS);
70 if (!m_keymap) {
71 qCWarning(qLcLibInput, "Failed to compile keymap");
72 return;
73 }
74 m_state = xkb_state_new(keymap: m_keymap);
75 if (!m_state) {
76 qCWarning(qLcLibInput, "Failed to create xkb state");
77 return;
78 }
79
80 m_repeatTimer.setSingleShot(true);
81 connect(sender: &m_repeatTimer, signal: &QTimer::timeout, receiver: this, slot: &QLibInputKeyboard::handleRepeat);
82#else
83 qCWarning(qLcLibInput) << "xkbcommon not available, not performing key mapping";
84#endif
85}
86
87QLibInputKeyboard::~QLibInputKeyboard()
88{
89#if QT_CONFIG(xkbcommon)
90 if (m_state)
91 xkb_state_unref(state: m_state);
92 if (m_keymap)
93 xkb_keymap_unref(keymap: m_keymap);
94 if (m_ctx)
95 xkb_context_unref(context: m_ctx);
96#endif
97}
98
99void QLibInputKeyboard::processKey(libinput_event_keyboard *e)
100{
101#if QT_CONFIG(xkbcommon)
102 if (!m_ctx || !m_keymap || !m_state)
103 return;
104
105 const uint32_t keycode = libinput_event_keyboard_get_key(event: e) + 8;
106 const xkb_keysym_t sym = xkb_state_key_get_one_sym(state: m_state, key: keycode);
107 const bool pressed = libinput_event_keyboard_get_key_state(event: e) == LIBINPUT_KEY_STATE_PRESSED;
108
109 // Modifiers here is the modifier state before the event, i.e. not
110 // including the current key in case it is a modifier. See the XOR
111 // logic in QKeyEvent::modifiers(). ### QTBUG-73826
112 Qt::KeyboardModifiers modifiers = QXkbCommon::modifiers(state: m_state);
113
114 const QString text = QXkbCommon::lookupString(state: m_state, code: keycode);
115 const int qtkey = QXkbCommon::keysymToQtKey(keysym: sym, modifiers, state: m_state, code: keycode);
116
117 xkb_state_update_key(state: m_state, key: keycode, direction: pressed ? XKB_KEY_DOWN : XKB_KEY_UP);
118
119 Qt::KeyboardModifiers modifiersAfterStateChange = QXkbCommon::modifiers(state: m_state);
120 QGuiApplicationPrivate::inputDeviceManager()->setKeyboardModifiers(modifiersAfterStateChange);
121
122 QWindowSystemInterface::handleExtendedKeyEvent(window: nullptr,
123 type: pressed ? QEvent::KeyPress : QEvent::KeyRelease,
124 key: qtkey, modifiers, nativeScanCode: keycode, nativeVirtualKey: sym, nativeModifiers: modifiers, text);
125
126 if (pressed && xkb_keymap_key_repeats(keymap: m_keymap, key: keycode)) {
127 m_repeatData.qtkey = qtkey;
128 m_repeatData.mods = modifiers;
129 m_repeatData.nativeScanCode = keycode;
130 m_repeatData.virtualKey = sym;
131 m_repeatData.nativeMods = modifiers;
132 m_repeatData.unicodeText = text;
133 m_repeatData.repeatCount = 1;
134 m_repeatTimer.setInterval(REPEAT_DELAY);
135 m_repeatTimer.start();
136 } else if (m_repeatTimer.isActive()) {
137 m_repeatTimer.stop();
138 }
139
140#else
141 Q_UNUSED(e);
142#endif
143}
144
145#if QT_CONFIG(xkbcommon)
146void QLibInputKeyboard::handleRepeat()
147{
148 QWindowSystemInterface::handleExtendedKeyEvent(window: nullptr, type: QEvent::KeyPress,
149 key: m_repeatData.qtkey, modifiers: m_repeatData.mods,
150 nativeScanCode: m_repeatData.nativeScanCode, nativeVirtualKey: m_repeatData.virtualKey, nativeModifiers: m_repeatData.nativeMods,
151 text: m_repeatData.unicodeText, autorep: true, count: m_repeatData.repeatCount);
152 m_repeatData.repeatCount += 1;
153 m_repeatTimer.setInterval(REPEAT_RATE);
154 m_repeatTimer.start();
155}
156#endif
157
158QT_END_NAMESPACE
159

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