KWaylandServer

inputmethod_v1_interface.cpp
1 /*
2  SPDX-FileCopyrightText: 2020 Aleix Pol Gonzalez <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5 */
6 
7 #include "inputmethod_v1_interface.h"
8 #include "display.h"
9 #include "keyboard_interface.h"
10 #include "keyboard_interface_p.h"
11 #include "logging.h"
12 #include "output_interface.h"
13 #include "seat_interface.h"
14 #include "surface_interface.h"
15 #include "surfacerole_p.h"
16 
17 #include <QHash>
18 #include <QTemporaryFile>
19 
20 #include <unistd.h>
21 
22 #include "qwayland-server-input-method-unstable-v1.h"
23 #include "qwayland-server-text-input-unstable-v1.h"
24 #include "qwayland-server-wayland.h"
25 
26 namespace KWaylandServer
27 {
28 static int s_version = 1;
29 
30 class InputKeyboardV1InterfacePrivate : public QtWaylandServer::wl_keyboard
31 {
32 public:
33  InputKeyboardV1InterfacePrivate()
34  {
35  }
36 };
37 
38 InputMethodGrabV1::InputMethodGrabV1(QObject *parent)
39  : QObject(parent)
40  , d(new InputKeyboardV1InterfacePrivate)
41 {
42 }
43 
44 InputMethodGrabV1::~InputMethodGrabV1()
45 {
46 }
47 
48 void InputMethodGrabV1::sendKeymap(const QByteArray &keymap)
49 {
51  if (!tmp->open()) {
52  qCWarning(KWAYLAND_SERVER) << "Failed to create keymap file:" << tmp->errorString();
53  return;
54  }
55 
56  unlink(tmp->fileName().toUtf8().constData());
57  if (!tmp->resize(keymap.size())) {
58  qCWarning(KWAYLAND_SERVER) << "Failed to resize keymap file:" << tmp->errorString();
59  return;
60  }
61 
62  uchar *address = tmp->map(0, keymap.size());
63  if (!address) {
64  qCWarning(KWAYLAND_SERVER) << "Failed to map keymap file:" << tmp->errorString();
65  return;
66  }
67 
68  qstrncpy(reinterpret_cast<char *>(address), keymap.constData(), keymap.size() + 1);
69  tmp->unmap(address);
70 
71  const auto resources = d->resourceMap();
72  for (auto r : resources) {
73  d->send_keymap(r->handle, QtWaylandServer::wl_keyboard::keymap_format::keymap_format_xkb_v1, tmp->handle(), tmp->size());
74  }
75 }
76 
77 void InputMethodGrabV1::sendKey(quint32 serial, quint32 timestamp, quint32 key, KeyboardKeyState state)
78 {
79  const auto resources = d->resourceMap();
80  for (auto r : resources) {
81  d->send_key(r->handle, serial, timestamp, key, quint32(state));
82  }
83 }
84 
85 void InputMethodGrabV1::sendModifiers(quint32 serial, quint32 depressed, quint32 latched, quint32 locked, quint32 group)
86 {
87  const auto resources = d->resourceMap();
88  for (auto r : resources) {
89  d->send_modifiers(r->handle, depressed, latched, locked, group, serial);
90  }
91 }
92 
93 class InputMethodContextV1InterfacePrivate : public QtWaylandServer::zwp_input_method_context_v1
94 {
95 public:
96  InputMethodContextV1InterfacePrivate(InputMethodContextV1Interface *q)
97  : zwp_input_method_context_v1()
98  , q(q)
99  {
100  }
101 
102  ~InputMethodContextV1InterfacePrivate()
103  {
104  }
105 
106  void zwp_input_method_context_v1_commit_string(Resource *, uint32_t serial, const QString &text) override
107  {
108  Q_EMIT q->commitString(serial, text);
109  }
110  void zwp_input_method_context_v1_preedit_string(Resource *, uint32_t serial, const QString &text, const QString &commit) override
111  {
112  Q_EMIT q->preeditString(serial, text, commit);
113  }
114 
115  void zwp_input_method_context_v1_preedit_styling(Resource *, uint32_t index, uint32_t length, uint32_t style) override
116  {
117  Q_EMIT q->preeditStyling(index, length, style);
118  }
119  void zwp_input_method_context_v1_preedit_cursor(Resource *, int32_t index) override
120  {
121  Q_EMIT q->preeditCursor(index);
122  }
123  void zwp_input_method_context_v1_delete_surrounding_text(Resource *, int32_t index, uint32_t length) override
124  {
125  Q_EMIT q->deleteSurroundingText(index, length);
126  }
127  void zwp_input_method_context_v1_cursor_position(Resource *, int32_t index, int32_t anchor) override
128  {
129  Q_EMIT q->cursorPosition(index, anchor);
130  }
131  void zwp_input_method_context_v1_modifiers_map(Resource *, wl_array *map) override
132  {
133  const auto mods = QByteArray::fromRawData(static_cast<const char *>(map->data), map->size);
134 
135  Q_EMIT q->modifiersMap(mods);
136  }
137  void zwp_input_method_context_v1_keysym(Resource *, uint32_t serial, uint32_t time, uint32_t sym, uint32_t state, uint32_t modifiers) override
138  {
139  Q_EMIT q->keysym(serial, time, sym, state == WL_KEYBOARD_KEY_STATE_PRESSED, modifiers);
140  }
141  void zwp_input_method_context_v1_grab_keyboard(Resource *resource, uint32_t id) override
142  {
143  m_keyboardGrab.reset(new InputMethodGrabV1(q));
144  m_keyboardGrab->d->add(resource->client(), id, 1);
145  Q_EMIT q->keyboardGrabRequested(m_keyboardGrab.data());
146  }
147  void zwp_input_method_context_v1_key(Resource *, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) override
148  {
149  Q_EMIT q->key(serial, time, key, state == WL_KEYBOARD_KEY_STATE_PRESSED);
150  }
151  void zwp_input_method_context_v1_modifiers(Resource *,
152  uint32_t serial,
153  uint32_t mods_depressed,
154  uint32_t mods_latched,
155  uint32_t mods_locked,
156  uint32_t group) override
157  {
158  Q_EMIT q->modifiers(serial, mods_depressed, mods_latched, mods_locked, group);
159  }
160  void zwp_input_method_context_v1_language(Resource *, uint32_t serial, const QString &language) override
161  {
162  Q_EMIT q->language(serial, language);
163  }
164  void zwp_input_method_context_v1_text_direction(Resource *, uint32_t serial, uint32_t direction) override
165  {
166  Qt::LayoutDirection qtDirection;
167  switch (direction) {
168  case ZWP_TEXT_INPUT_V1_TEXT_DIRECTION_LTR:
169  qtDirection = Qt::LeftToRight;
170  break;
171  case ZWP_TEXT_INPUT_V1_TEXT_DIRECTION_RTL:
172  qtDirection = Qt::RightToLeft;
173  break;
174  case ZWP_TEXT_INPUT_V1_TEXT_DIRECTION_AUTO:
175  qtDirection = Qt::LayoutDirectionAuto;
176  break;
177  default:
178  Q_UNREACHABLE();
179  break;
180  }
181  Q_EMIT q->textDirection(serial, qtDirection);
182  }
183 
184  void zwp_input_method_context_v1_destroy(Resource *resource) override
185  {
186  wl_resource_destroy(resource->handle);
187  }
188 
189  InputMethodContextV1Interface *const q;
190  QScopedPointer<InputMethodGrabV1> m_keyboardGrab;
191 };
192 
193 InputMethodContextV1Interface::InputMethodContextV1Interface(InputMethodV1Interface *parent)
194  : QObject(parent)
195  , d(new InputMethodContextV1InterfacePrivate(this))
196 {
197 }
198 
199 InputMethodContextV1Interface::~InputMethodContextV1Interface() = default;
200 
201 void InputMethodContextV1Interface::sendCommitState(uint32_t serial)
202 {
203  for (auto r : d->resourceMap()) {
204  d->send_commit_state(r->handle, serial);
205  }
206 }
207 
208 void InputMethodContextV1Interface::sendContentType(TextInputContentHints hint, TextInputContentPurpose purpose)
209 {
210  quint32 contentHint = QtWaylandServer::zwp_text_input_v1::content_hint_none;
211  quint32 contentPurpose;
212 
213  if (hint.testFlag(TextInputContentHint::AutoCapitalization)) {
214  contentHint |= QtWaylandServer::zwp_text_input_v1::content_hint_auto_capitalization;
215  }
216  if (hint.testFlag(TextInputContentHint::AutoCorrection)) {
217  contentHint |= QtWaylandServer::zwp_text_input_v1::content_hint_auto_correction;
218  }
219  if (hint.testFlag(TextInputContentHint::AutoCompletion)) {
220  contentHint |= QtWaylandServer::zwp_text_input_v1::content_hint_auto_completion;
221  }
222  if (hint.testFlag(TextInputContentHint::LowerCase)) {
223  contentHint |= QtWaylandServer::zwp_text_input_v1::content_hint_lowercase;
224  }
225  if (hint.testFlag(TextInputContentHint::UpperCase)) {
226  contentHint |= QtWaylandServer::zwp_text_input_v1::content_hint_uppercase;
227  }
228  if (hint.testFlag(TextInputContentHint::TitleCase)) {
229  contentHint |= QtWaylandServer::zwp_text_input_v1::content_hint_titlecase;
230  }
231  if (hint.testFlag(TextInputContentHint::HiddenText)) {
232  contentHint |= QtWaylandServer::zwp_text_input_v1::content_hint_hidden_text;
233  }
234  if (hint.testFlag(TextInputContentHint::SensitiveData)) {
235  contentHint |= QtWaylandServer::zwp_text_input_v1::content_hint_lowercase;
236  }
237  if (hint.testFlag(TextInputContentHint::Latin)) {
238  contentHint |= QtWaylandServer::zwp_text_input_v1::content_hint_latin;
239  }
240  if (hint.testFlag(TextInputContentHint::MultiLine)) {
241  contentHint |= QtWaylandServer::zwp_text_input_v1::content_hint_multiline;
242  }
243  if (hint.testFlag(TextInputContentHint::None)) {
244  contentHint |= QtWaylandServer::zwp_text_input_v1::content_hint_none;
245  }
246 
247  switch (purpose) {
248  case TextInputContentPurpose::Alpha:
249  contentPurpose = QtWaylandServer::zwp_text_input_v1::content_purpose_alpha;
250  break;
251  case TextInputContentPurpose::Digits:
252  contentPurpose = QtWaylandServer::zwp_text_input_v1::content_purpose_digits;
253  break;
254  case TextInputContentPurpose::Number:
255  contentPurpose = QtWaylandServer::zwp_text_input_v1::content_purpose_number;
256  break;
257  case TextInputContentPurpose::Phone:
258  contentPurpose = QtWaylandServer::zwp_text_input_v1::content_purpose_phone;
259  break;
260  case TextInputContentPurpose::Url:
261  contentPurpose = QtWaylandServer::zwp_text_input_v1::content_purpose_url;
262  break;
263  case TextInputContentPurpose::Email:
264  contentPurpose = QtWaylandServer::zwp_text_input_v1::content_purpose_email;
265  break;
266  case TextInputContentPurpose::Name:
267  contentPurpose = QtWaylandServer::zwp_text_input_v1::content_purpose_name;
268  break;
269  case TextInputContentPurpose::Password:
270  contentPurpose = QtWaylandServer::zwp_text_input_v1::content_purpose_password;
271  break;
272  case TextInputContentPurpose::Date:
273  contentPurpose = QtWaylandServer::zwp_text_input_v1::content_purpose_date;
274  break;
275  case TextInputContentPurpose::Time:
276  contentPurpose = QtWaylandServer::zwp_text_input_v1::content_purpose_time;
277  break;
278  case TextInputContentPurpose::DateTime:
279  contentPurpose = QtWaylandServer::zwp_text_input_v1::content_purpose_datetime;
280  break;
281  case TextInputContentPurpose::Terminal:
282  contentPurpose = QtWaylandServer::zwp_text_input_v1::content_purpose_terminal;
283  break;
284  case TextInputContentPurpose::Normal:
285  default:
286  contentPurpose = QtWaylandServer::zwp_text_input_v1::content_purpose_normal;
287  }
288 
289  for (auto r : d->resourceMap()) {
290  d->send_content_type(r->handle, contentHint, contentPurpose);
291  }
292 }
293 
294 void InputMethodContextV1Interface::sendInvokeAction(uint32_t button, uint32_t index)
295 {
296  for (auto r : d->resourceMap()) {
297  d->send_invoke_action(r->handle, button, index);
298  }
299 }
300 
301 void InputMethodContextV1Interface::sendPreferredLanguage(const QString &language)
302 {
303  for (auto r : d->resourceMap()) {
304  d->send_preferred_language(r->handle, language);
305  }
306 }
307 
308 void InputMethodContextV1Interface::sendReset()
309 {
310  for (auto r : d->resourceMap()) {
311  d->send_reset(r->handle);
312  }
313 }
314 
315 void InputMethodContextV1Interface::sendSurroundingText(const QString &text, uint32_t cursor, uint32_t anchor)
316 {
317  for (auto r : d->resourceMap()) {
318  d->send_surrounding_text(r->handle, text, cursor, anchor);
319  }
320 }
321 
322 InputMethodGrabV1 *InputMethodContextV1Interface::keyboardGrab() const
323 {
324  return d->m_keyboardGrab.get();
325 }
326 
327 class InputPanelSurfaceV1InterfacePrivate : public QtWaylandServer::zwp_input_panel_surface_v1, public SurfaceRole
328 {
329  friend class InputPanelSurfaceV1Interface;
330 
331 public:
332  InputPanelSurfaceV1InterfacePrivate(SurfaceInterface *surface, quint32 id, InputPanelSurfaceV1Interface *q)
333  : zwp_input_panel_surface_v1()
334  , SurfaceRole(surface, QByteArrayLiteral("input_panel_surface_v1"))
335  , q(q)
336  {
337  Q_UNUSED(id)
338  }
339 
340  void zwp_input_panel_surface_v1_set_overlay_panel(Resource *) override
341  {
342  Q_EMIT q->overlayPanel();
343  }
344 
345  void zwp_input_panel_surface_v1_set_toplevel(Resource *, struct ::wl_resource *output, uint32_t position) override
346  {
347  Q_EMIT q->topLevel(OutputInterface::get(output), InputPanelSurfaceV1Interface::Position(position));
348  }
349 
350  void commit() override
351  {
352  }
353 
354  void zwp_input_panel_surface_v1_destroy_resource(Resource *) override
355  {
356  delete q;
357  }
358 
359  InputPanelSurfaceV1Interface *const q;
360 };
361 
362 InputPanelSurfaceV1Interface::InputPanelSurfaceV1Interface(SurfaceInterface *surface, quint32 id, QObject *parent)
363  : QObject(parent)
364  , d(new InputPanelSurfaceV1InterfacePrivate(surface, id, this))
365 {
366 }
367 
368 InputPanelSurfaceV1Interface::~InputPanelSurfaceV1Interface()
369 {
370 }
371 
372 class InputPanelV1InterfacePrivate : public QtWaylandServer::zwp_input_panel_v1
373 {
374 public:
375  InputPanelV1InterfacePrivate(InputPanelV1Interface *q, Display *d)
376  : zwp_input_panel_v1(*d, s_version)
377  , q(q)
378  {
379  }
380 
381  void zwp_input_panel_v1_get_input_panel_surface(Resource *resource, uint32_t id, struct ::wl_resource *surfaceResource) override
382  {
383  auto surface = SurfaceInterface::get(surfaceResource);
384 
385  SurfaceRole *surfaceRole = SurfaceRole::get(surface);
386  if (surfaceRole) {
387  wl_resource_post_error(resource->handle, 0, "the surface already has a role assigned %s", surfaceRole->name().constData());
388  return;
389  }
390 
391  auto interface = new InputPanelSurfaceV1Interface(surface, id, nullptr);
392  interface->d->init(resource->client(), id, resource->version());
393 
394  Q_EMIT q->inputPanelSurfaceAdded(interface);
395  }
396 
397  InputPanelV1Interface *const q;
398 };
399 
400 InputPanelV1Interface::InputPanelV1Interface(Display *display, QObject *parent)
401  : QObject(parent)
402  , d(new InputPanelV1InterfacePrivate(this, display))
403 {
404 }
405 
406 InputPanelV1Interface::~InputPanelV1Interface() = default;
407 
408 SurfaceInterface *InputPanelSurfaceV1Interface::surface() const
409 {
410  return d->surface();
411 }
412 
413 class InputMethodV1InterfacePrivate : public QtWaylandServer::zwp_input_method_v1
414 {
415 public:
416  InputMethodV1InterfacePrivate(Display *d, InputMethodV1Interface *q)
417  : zwp_input_method_v1(*d, s_version)
418  , q(q)
419  , m_display(d)
420  {
421  }
422 
423  void zwp_input_method_v1_bind_resource(Resource *resource) override
424  {
425  if (!m_context) {
426  return;
427  }
428 
429  auto addedResource = m_context->d->add(resource->client(), resource->version());
430  send_activate(resource->handle, addedResource->handle);
431  }
432 
434  InputMethodV1Interface *const q;
435  Display *const m_display;
436 };
437 
438 InputMethodV1Interface::InputMethodV1Interface(Display *d, QObject *parent)
439  : QObject(parent)
440  , d(new InputMethodV1InterfacePrivate(d, this))
441 {
442 }
443 
444 InputMethodV1Interface::~InputMethodV1Interface() = default;
445 
446 void InputMethodV1Interface::sendActivate()
447 {
448  if (d->m_context) {
449  return;
450  }
451 
452  d->m_context.reset(new InputMethodContextV1Interface(this));
453 
454  for (auto resource : d->resourceMap()) {
455  auto connection = d->m_context->d->add(resource->client(), resource->version());
456  d->send_activate(resource->handle, connection->handle);
457  }
458 }
459 
460 void InputMethodV1Interface::sendDeactivate()
461 {
462  if (!d->m_context) {
463  return;
464  }
465 
466  for (auto resource : d->resourceMap()) {
467  auto connection = d->m_context->d->resourceMap().value(resource->client());
468  if (connection) {
469  d->send_deactivate(resource->handle, connection->handle);
470  }
471  }
472  d->m_context.reset();
473 }
474 
475 InputMethodContextV1Interface *InputMethodV1Interface::context() const
476 {
477  return d->m_context.get();
478 }
479 
480 }
T * get() const const
QByteArray fromRawData(const char *data, int size)
LayoutDirection
void reset(T *other)
PostalAddress address(const QVariant &location)
static SurfaceInterface * get(wl_resource *native)
const char * constData() const const
int size() const const
QObject * parent() const const
Q_EMITQ_EMIT
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sat Oct 23 2021 23:08:27 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.