KWin
Loading...
Searching...
No Matches
keyboard_input.cpp
Go to the documentation of this file.
1/*
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5 SPDX-FileCopyrightText: 2013, 2016 Martin Gräßlin <mgraesslin@kde.org>
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8*/
9#include "keyboard_input.h"
10
11#include <config-kwin.h>
12
13#include "input_event.h"
14#include "input_event_spy.h"
15#include "inputmethod.h"
16#include "keyboard_layout.h"
17#include "keyboard_repeat.h"
19#include "wayland/datadevice.h"
20#include "wayland/keyboard.h"
21#include "wayland/seat.h"
22#include "wayland_server.h"
23#include "window.h"
24#include "workspace.h"
25#include "xkb.h"
26// screenlocker
27#if KWIN_BUILD_SCREENLOCKER
28#include <KScreenLocker/KsldApp>
29#endif
30// Frameworks
31#include <KGlobalAccel>
32// Qt
33#include <QKeyEvent>
34
35#include <cmath>
36
37namespace KWin
38{
39
41 : QObject(parent)
42 , m_input(parent)
43 , m_xkb(new Xkb(kwinApp()->followLocale1()))
44{
45 connect(m_xkb.get(), &Xkb::ledsChanged, this, &KeyboardInputRedirection::ledsChanged);
46 if (waylandServer()) {
47 m_xkb->setSeat(waylandServer()->seat());
48 }
49}
50
52
54{
55 return m_xkb.get();
56}
57
58Qt::KeyboardModifiers KeyboardInputRedirection::modifiers() const
59{
60 return m_xkb->modifiers();
61}
62
64{
65 return m_xkb->modifiersRelevantForGlobalShortcuts();
66}
67
69{
70public:
75
76 void keyEvent(KeyEvent *event) override
77 {
78 if (event->isAutoRepeat()) {
79 return;
80 }
81 Q_EMIT m_input->keyStateChanged(event->nativeScanCode(), event->type() == QEvent::KeyPress ? InputRedirection::KeyboardKeyPressed : InputRedirection::KeyboardKeyReleased);
82 }
83
84private:
85 InputRedirection *m_input;
86};
87
89{
90public:
92 : m_input(input)
93 , m_modifiers()
94 {
95 }
96
97 void keyEvent(KeyEvent *event) override
98 {
99 if (event->isAutoRepeat()) {
100 return;
101 }
102 const Qt::KeyboardModifiers mods = event->modifiers();
103 if (mods == m_modifiers) {
104 return;
105 }
106 Q_EMIT m_input->keyboardModifiersChanged(mods, m_modifiers);
107 m_modifiers = mods;
108 }
109
110private:
111 InputRedirection *m_input;
112 Qt::KeyboardModifiers m_modifiers;
113};
114
116{
117 Q_ASSERT(!m_inited);
118 m_inited = true;
119 const auto config = kwinApp()->kxkbConfig();
120 m_xkb->setNumLockConfig(kwinApp()->inputConfig());
121 m_xkb->setConfig(config);
122
124
125 m_input->installInputEventSpy(new KeyStateChangedSpy(m_input));
126 m_modifiersChangedSpy = new ModifiersChangedSpy(m_input);
127 m_input->installInputEventSpy(m_modifiersChangedSpy);
128 m_keyboardLayout = new KeyboardLayout(m_xkb.get(), config);
129 m_keyboardLayout->init();
130 m_input->installInputEventSpy(m_keyboardLayout);
131
132 if (waylandServer()->hasGlobalShortcutSupport()) {
134 }
135
136 KeyboardRepeat *keyRepeatSpy = new KeyboardRepeat(m_xkb.get());
137 connect(keyRepeatSpy, &KeyboardRepeat::keyRepeat, this,
138 std::bind(&KeyboardInputRedirection::processKey, this, std::placeholders::_1, InputRedirection::KeyboardKeyAutoRepeat, std::placeholders::_2, nullptr));
139 m_input->installInputEventSpy(keyRepeatSpy);
140
141 connect(workspace(), &QObject::destroyed, this, [this] {
142 m_inited = false;
143 });
144 connect(waylandServer(), &QObject::destroyed, this, [this] {
145 m_inited = false;
146 });
147 connect(workspace(), &Workspace::windowActivated, this, [this] {
148 disconnect(m_activeWindowSurfaceChangedConnection);
149 if (auto window = workspace()->activeWindow()) {
150 m_activeWindowSurfaceChangedConnection = connect(window, &Window::surfaceChanged, this, &KeyboardInputRedirection::update);
151 } else {
152 m_activeWindowSurfaceChangedConnection = QMetaObject::Connection();
153 }
154 update();
155 });
156#if KWIN_BUILD_SCREENLOCKER
158 connect(ScreenLocker::KSldApp::self(), &ScreenLocker::KSldApp::lockStateChanged, this, &KeyboardInputRedirection::update);
159 }
160#endif
161
162 reconfigure();
163}
164
166{
167 if (!m_inited) {
168 return;
169 }
170 if (waylandServer()->seat()->keyboard()) {
171 const auto config = kwinApp()->inputConfig()->group(QStringLiteral("Keyboard"));
172 const int delay = config.readEntry("RepeatDelay", 660);
173 const int rate = std::ceil(config.readEntry("RepeatRate", 25.0));
174 const QString repeatMode = config.readEntry("KeyRepeat", "repeat");
175 // when the clients will repeat the character or turn repeat key events into an accent character selection, we want
176 // to tell the clients that we are indeed repeating keys.
177 const bool enabled = repeatMode == QLatin1String("accent") || repeatMode == QLatin1String("repeat");
178
179 waylandServer()->seat()->keyboard()->setRepeatInfo(enabled ? rate : 0, delay);
180 }
181}
182
184{
185 if (!m_inited) {
186 return;
187 }
188 auto seat = waylandServer()->seat();
189 // TODO: this needs better integration
190 Window *found = nullptr;
191 if (waylandServer()->isScreenLocked()) {
192 const QList<Window *> &stacking = Workspace::self()->stackingOrder();
193 if (!stacking.isEmpty()) {
194 auto it = stacking.end();
195 do {
196 --it;
197 Window *t = (*it);
198 if (t->isDeleted()) {
199 // a deleted window doesn't get mouse events
200 continue;
201 }
202 if (!t->isLockScreen()) {
203 continue;
204 }
205 if (!t->readyForPainting()) {
206 continue;
207 }
208 found = t;
209 break;
210 } while (it != stacking.begin());
211 }
212 } else if (!input()->isSelectingWindow()) {
213 found = workspace()->activeWindow();
214 }
215 if (found && found->surface()) {
216 if (found->surface() != seat->focusedKeyboardSurface()) {
217 seat->setFocusedKeyboardSurface(found->surface());
218 }
219 } else {
220 seat->setFocusedKeyboardSurface(nullptr);
221 }
222}
223
224void KeyboardInputRedirection::processKey(uint32_t key, InputRedirection::KeyboardKeyState state, std::chrono::microseconds time, InputDevice *device)
225{
226 QEvent::Type type;
227 bool autoRepeat = false;
228 switch (state) {
230 autoRepeat = true;
231 // fall through
233 type = QEvent::KeyPress;
234 break;
236 type = QEvent::KeyRelease;
237 break;
238 default:
239 Q_UNREACHABLE();
240 }
241
242 const quint32 previousLayout = m_xkb->currentLayout();
243 if (!autoRepeat) {
244 m_xkb->updateKey(key, state);
245 }
246
247 const xkb_keysym_t keySym = m_xkb->currentKeysym();
248 const Qt::KeyboardModifiers globalShortcutsModifiers = m_xkb->modifiersRelevantForGlobalShortcuts(key);
249 KeyEvent event(type,
250 m_xkb->toQtKey(keySym, key, globalShortcutsModifiers ? Qt::ControlModifier : Qt::KeyboardModifiers()),
251 m_xkb->modifiers(),
252 key,
253 keySym,
254 m_xkb->toString(keySym),
255 autoRepeat,
256 time,
257 device);
258 event.setModifiersRelevantForGlobalShortcuts(globalShortcutsModifiers);
259
260 m_input->processSpies(std::bind(&InputEventSpy::keyEvent, std::placeholders::_1, &event));
261 if (!m_inited) {
262 return;
263 }
264 input()->setLastInputHandler(this);
265 m_input->processFilters(std::bind(&InputEventFilter::keyEvent, std::placeholders::_1, &event));
266
267 m_xkb->forwardModifiers();
268 if (auto *inputmethod = kwinApp()->inputMethod()) {
269 inputmethod->forwardModifiers(InputMethod::NoForce);
270 }
271
272 if (event.modifiersRelevantForGlobalShortcuts() == Qt::KeyboardModifier::NoModifier && type != QEvent::KeyRelease) {
273 m_keyboardLayout->checkLayoutChange(previousLayout);
274 }
275}
276
277}
278
279#include "moc_keyboard_input.cpp"
virtual bool keyEvent(KeyEvent *event)
Definition input.cpp:125
virtual void keyEvent(KeyEvent *event)
This class is responsible for redirecting incoming input to the surface which currently has input or ...
Definition input.h:70
void installInputEventSpy(InputEventSpy *spy)
void keyboardModifiersChanged(Qt::KeyboardModifiers newMods, Qt::KeyboardModifiers oldMods)
Emitted when the modifiers changes.
void processSpies(UnaryFunction function)
Definition input.h:211
void processFilters(UnaryPredicate function)
Definition input.h:192
void setLastInputHandler(QObject *device)
Definition input.cpp:2739
void keyStateChanged(quint32 keyCode, InputRedirection::KeyboardKeyState state)
Emitted when the state of a key changed.
void setModifiersRelevantForGlobalShortcuts(const Qt::KeyboardModifiers &mods)
void keyEvent(KeyEvent *event) override
KeyStateChangedSpy(InputRedirection *input)
KeyboardInputRedirection(InputRedirection *parent)
Qt::KeyboardModifiers modifiersRelevantForGlobalShortcuts() const
void processKey(uint32_t key, InputRedirection::KeyboardKeyState state, std::chrono::microseconds time, InputDevice *device=nullptr)
Qt::KeyboardModifiers modifiers() const
void setRepeatInfo(qint32 charactersPerSecond, qint32 delay)
Definition keyboard.cpp:240
void checkLayoutChange(uint previousLayout)
void keyRepeat(quint32 key, std::chrono::microseconds time)
void keyEvent(KeyEvent *event) override
ModifiersChangedSpy(InputRedirection *input)
void setHasKeyboard(bool has)
Definition seat.cpp:342
KeyboardInterface * keyboard() const
Definition seat.cpp:963
bool hasScreenLockerIntegration() const
SeatInterface * seat() const
SurfaceInterface * surface() const
Definition window.cpp:342
bool readyForPainting() const
Definition window.h:1917
void surfaceChanged()
virtual bool isLockScreen() const
Definition window.h:2007
bool isDeleted() const
Definition window.cpp:540
Window * activeWindow() const
Definition workspace.h:767
const QList< Window * > & stackingOrder() const
Definition workspace.h:788
void windowActivated(KWin::Window *)
static Workspace * self()
Definition workspace.h:91
void ledsChanged(const LEDs &leds)
uint32_t xkb_keysym_t
Session::Type type
Definition session.cpp:17
WaylandServer * waylandServer()
Workspace * workspace()
Definition workspace.h:830
InputRedirection * input()
Definition input.h:549