KWaylandServer

keyboard_interface.cpp
1 /*
2  SPDX-FileCopyrightText: 2014 Martin Gräßlin <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5 */
6 #include "display.h"
7 #include "keyboard_interface_p.h"
8 #include "logging.h"
9 #include "seat_interface.h"
10 #include "seat_interface_p.h"
11 #include "surface_interface.h"
12 // Qt
13 #include <QTemporaryFile>
14 #include <QVector>
15 
16 #include <unistd.h>
17 
18 namespace KWaylandServer
19 {
20 KeyboardInterfacePrivate::KeyboardInterfacePrivate(SeatInterface *s)
21  : seat(s)
22 {
23 }
24 
25 void KeyboardInterfacePrivate::keyboard_release(Resource *resource)
26 {
27  wl_resource_destroy(resource->handle);
28 }
29 
30 void KeyboardInterfacePrivate::keyboard_bind_resource(Resource *resource)
31 {
32  const ClientConnection *focusedClient = focusedSurface ? focusedSurface->client() : nullptr;
33 
34  if (resource->version() >= WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION) {
35  send_repeat_info(resource->handle, keyRepeat.charactersPerSecond, keyRepeat.delay);
36  }
37  if (!keymap.isNull()) {
38  sendKeymap(resource);
39  }
40 
41  if (focusedClient && focusedClient->client() == resource->client()) {
42  const QVector<quint32> keys = pressedKeys();
43  const QByteArray keysData = QByteArray::fromRawData(reinterpret_cast<const char *>(keys.data()), sizeof(quint32) * keys.count());
44  const quint32 serial = seat->display()->nextSerial();
45 
46  send_enter(resource->handle, serial, focusedSurface->resource(), keysData);
47  send_modifiers(resource->handle, serial, modifiers.depressed, modifiers.latched, modifiers.locked, modifiers.group);
48  }
49 }
50 
51 QList<KeyboardInterfacePrivate::Resource *> KeyboardInterfacePrivate::keyboardsForClient(ClientConnection *client) const
52 {
53  return resourceMap().values(client->client());
54 }
55 
56 void KeyboardInterfacePrivate::sendLeave(SurfaceInterface *surface, quint32 serial)
57 {
58  const QList<Resource *> keyboards = keyboardsForClient(surface->client());
59  for (Resource *keyboardResource : keyboards) {
60  send_leave(keyboardResource->handle, serial, surface->resource());
61  }
62 }
63 
64 void KeyboardInterfacePrivate::sendEnter(SurfaceInterface *surface, quint32 serial)
65 {
66  const auto states = pressedKeys();
67  QByteArray data = QByteArray::fromRawData(reinterpret_cast<const char *>(states.constData()), sizeof(quint32) * states.size());
68 
69  const QList<Resource *> keyboards = keyboardsForClient(surface->client());
70  for (Resource *keyboardResource : keyboards) {
71  send_enter(keyboardResource->handle, serial, surface->resource(), data);
72  }
73 }
74 
75 void KeyboardInterfacePrivate::sendKeymap(Resource *resource)
76 {
78  if (!tmp->open()) {
79  qCWarning(KWAYLAND_SERVER) << "Failed to create keymap file:" << tmp->errorString();
80  return;
81  }
82 
83  unlink(tmp->fileName().toUtf8().constData());
84  if (!tmp->resize(keymap.size())) {
85  qCWarning(KWAYLAND_SERVER) << "Failed to resize keymap file:" << tmp->errorString();
86  return;
87  }
88 
89  uchar *address = tmp->map(0, keymap.size());
90  if (!address) {
91  qCWarning(KWAYLAND_SERVER) << "Failed to map keymap file:" << tmp->errorString();
92  return;
93  }
94 
95  qstrncpy(reinterpret_cast<char *>(address), keymap.constData(), keymap.size() + 1);
96  tmp->unmap(address);
97 
98  send_keymap(resource->handle, keymap_format::keymap_format_xkb_v1, tmp->handle(), tmp->size());
99 }
100 
101 void KeyboardInterface::setKeymap(const QByteArray &content)
102 {
103  if (content.isNull()) {
104  return;
105  }
106 
107  d->keymap = content;
108 
109  const auto keyboardResources = d->resourceMap();
110  for (KeyboardInterfacePrivate::Resource *resource : keyboardResources) {
111  d->sendKeymap(resource);
112  }
113 }
114 
115 void KeyboardInterfacePrivate::sendModifiers(quint32 depressed, quint32 latched, quint32 locked, quint32 group, quint32 serial)
116 {
117  const QList<Resource *> keyboards = keyboardsForClient(focusedSurface->client());
118  for (Resource *keyboardResource : keyboards) {
119  send_modifiers(keyboardResource->handle, serial, depressed, latched, locked, group);
120  }
121 }
122 
123 bool KeyboardInterfacePrivate::updateKey(quint32 key, KeyboardKeyState state)
124 {
125  auto it = states.find(key);
126  if (it == states.end()) {
127  states.insert(key, state);
128  return true;
129  }
130  if (it.value() == state) {
131  return false;
132  }
133  it.value() = state;
134  return true;
135 }
136 
137 KeyboardInterface::KeyboardInterface(SeatInterface *seat)
138  : d(new KeyboardInterfacePrivate(seat))
139 {
140 }
141 
142 KeyboardInterface::~KeyboardInterface() = default;
143 
144 void KeyboardInterfacePrivate::sendModifiers()
145 {
146  sendModifiers(modifiers.depressed, modifiers.latched, modifiers.locked, modifiers.group, modifiers.serial);
147 }
148 
149 void KeyboardInterface::setFocusedSurface(SurfaceInterface *surface, quint32 serial)
150 {
151  if (d->focusedSurface == surface) {
152  return;
153  }
154 
155  if (d->focusedSurface) {
156  d->sendLeave(d->focusedSurface, serial);
157  disconnect(d->destroyConnection);
158  }
159 
160  d->focusedSurface = surface;
161  if (!d->focusedSurface) {
162  return;
163  }
164  d->destroyConnection = connect(d->focusedSurface, &SurfaceInterface::aboutToBeDestroyed, this, [this] {
165  d->sendLeave(d->focusedSurface, d->seat->display()->nextSerial());
166  d->focusedSurface = nullptr;
167  });
168 
169  d->sendEnter(d->focusedSurface, serial);
170  d->sendModifiers();
171 }
172 
173 QVector<quint32> KeyboardInterfacePrivate::pressedKeys() const
174 {
175  QVector<quint32> keys;
176  for (auto it = states.constBegin(); it != states.constEnd(); ++it) {
177  if (it.value() == KeyboardKeyState::Pressed) {
178  keys << it.key();
179  }
180  }
181  return keys;
182 }
183 
184 void KeyboardInterface::sendKey(quint32 key, KeyboardKeyState state)
185 {
186  if (!d->updateKey(key, state)) {
187  return;
188  }
189 
190  if (!d->focusedSurface) {
191  return;
192  }
193 
194  const QList<KeyboardInterfacePrivate::Resource *> keyboards = d->keyboardsForClient(d->focusedSurface->client());
195  const quint32 serial = d->seat->display()->nextSerial();
196  for (KeyboardInterfacePrivate::Resource *keyboardResource : keyboards) {
197  d->send_key(keyboardResource->handle, serial, d->seat->timestamp(), key, quint32(state));
198  }
199 }
200 
201 void KeyboardInterface::sendModifiers(quint32 depressed, quint32 latched, quint32 locked, quint32 group)
202 {
203  bool changed = false;
204 #define UPDATE(value) \
205  if (d->modifiers.value != value) { \
206  d->modifiers.value = value; \
207  changed = true; \
208  }
209  UPDATE(depressed)
210  UPDATE(latched)
211  UPDATE(locked)
212  UPDATE(group)
213  if (!changed) {
214  return;
215  }
216 
217  if (!d->focusedSurface) {
218  return;
219  }
220 
221  d->modifiers.serial = d->seat->display()->nextSerial();
222  d->sendModifiers(depressed, latched, locked, group, d->modifiers.serial);
223 }
224 
225 void KeyboardInterface::setRepeatInfo(qint32 charactersPerSecond, qint32 delay)
226 {
227  d->keyRepeat.charactersPerSecond = qMax(charactersPerSecond, 0);
228  d->keyRepeat.delay = qMax(delay, 0);
229  const QList<KeyboardInterfacePrivate::Resource *> keyboards = d->resourceMap().values();
230  for (KeyboardInterfacePrivate::Resource *keyboardResource : keyboards) {
231  if (keyboardResource->version() >= WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION) {
232  d->send_repeat_info(keyboardResource->handle, d->keyRepeat.charactersPerSecond, d->keyRepeat.delay);
233  }
234  }
235 }
236 
238 {
239  return d->focusedSurface;
240 }
241 
243 {
244  return d->keyRepeat.delay;
245 }
246 
248 {
249  return d->keyRepeat.charactersPerSecond;
250 }
251 
252 }
void setRepeatInfo(qint32 charactersPerSecond, qint32 delay)
Sets the key repeat information to be forwarded to all bound keyboards.
bool isNull() const const
QByteArray fromRawData(const char *data, int size)
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
T * data()
PostalAddress address(const QVariant &location)
SurfaceInterface * focusedSurface() const
int count(const T &value) const const
Resource representing a wl_surface.
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void aboutToBeDestroyed()
This signal is emitted when the underlying wl_surface resource is about to be freed.
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sat Oct 16 2021 23:10:14 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.