KWayland

textinput_v2.cpp
1 /*
2  SPDX-FileCopyrightText: 2016 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 "event_queue.h"
7 #include "seat.h"
8 #include "surface.h"
9 #include "textinput_p.h"
10 #include "wayland_pointer_p.h"
11 
12 #include <wayland-text-input-v2-client-protocol.h>
13 
14 namespace KWayland
15 {
16 namespace Client
17 {
18 class TextInputUnstableV2::Private : public TextInput::Private
19 {
20 public:
21  Private(TextInputUnstableV2 *q, Seat *seat);
22 
23  void setup(zwp_text_input_v2 *textinputmanagerunstablev0);
24 
25  bool isValid() const override;
26  void enable(Surface *surface) override;
27  void disable(Surface *surface) override;
28  void showInputPanel() override;
29  void hideInputPanel() override;
30  void setCursorRectangle(const QRect &rect) override;
31  void setPreferredLanguage(const QString &lang) override;
32  void setSurroundingText(const QString &text, quint32 cursor, quint32 anchor) override;
33  void reset() override;
34  void setContentType(ContentHints hint, ContentPurpose purpose) override;
35 
36  WaylandPointer<zwp_text_input_v2, zwp_text_input_v2_destroy> textinputunstablev2;
37 
38 private:
39  static void enterCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, uint32_t serial, wl_surface *surface);
40  static void leaveCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, uint32_t serial, wl_surface *surface);
41  static void inputPanelStateCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, uint32_t state, int32_t x, int32_t y, int32_t width, int32_t height);
42  static void preeditStringCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, const char *text, const char *commit);
43  static void preeditStylingCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, uint32_t index, uint32_t length, uint32_t style);
44  static void preeditCursorCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, int32_t index);
45  static void commitStringCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, const char *text);
46  static void cursorPositionCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, int32_t index, int32_t anchor);
47  static void deleteSurroundingTextCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, uint32_t before_length, uint32_t after_length);
48  static void modifiersMapCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, wl_array *map);
49  static void keysymCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, uint32_t time, uint32_t sym, uint32_t state, uint32_t modifiers);
50  static void languageCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, const char *language);
51  static void textDirectionCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, uint32_t direction);
52  static void configureSurroundingTextCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, int32_t before_cursor, int32_t after_cursor);
53  static void inputMethodChangedCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, uint32_t serial, uint32_t flags);
54 
55  TextInputUnstableV2 *q;
56 
57  static const zwp_text_input_v2_listener s_listener;
58 };
59 
60 const zwp_text_input_v2_listener TextInputUnstableV2::Private::s_listener = {enterCallback,
61  leaveCallback,
62  inputPanelStateCallback,
63  preeditStringCallback,
64  preeditStylingCallback,
65  preeditCursorCallback,
66  commitStringCallback,
67  cursorPositionCallback,
68  deleteSurroundingTextCallback,
69  modifiersMapCallback,
70  keysymCallback,
71  languageCallback,
72  textDirectionCallback,
73  configureSurroundingTextCallback,
74  inputMethodChangedCallback};
75 
76 void TextInputUnstableV2::Private::enterCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, uint32_t serial, wl_surface *surface)
77 {
78  auto t = reinterpret_cast<TextInputUnstableV2::Private *>(data);
79  Q_ASSERT(t->textinputunstablev2 == zwp_text_input_v2);
80  t->latestSerial = serial;
81  t->enteredSurface = Surface::get(surface);
82  Q_EMIT t->q->entered();
83 }
84 
85 void TextInputUnstableV2::Private::leaveCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, uint32_t serial, wl_surface *surface)
86 {
87  Q_UNUSED(surface)
88  auto t = reinterpret_cast<TextInputUnstableV2::Private *>(data);
89  Q_ASSERT(t->textinputunstablev2 == zwp_text_input_v2);
90  t->enteredSurface = nullptr;
91  t->latestSerial = serial;
92  Q_EMIT t->q->left();
93 }
94 
95 void TextInputUnstableV2::Private::inputPanelStateCallback(void *data,
96  zwp_text_input_v2 *zwp_text_input_v2,
97  uint32_t state,
98  int32_t x,
99  int32_t y,
100  int32_t width,
101  int32_t height)
102 {
103  Q_UNUSED(x)
104  Q_UNUSED(y)
105  Q_UNUSED(width)
106  Q_UNUSED(height)
107  auto t = reinterpret_cast<TextInputUnstableV2::Private *>(data);
108  Q_ASSERT(t->textinputunstablev2 == zwp_text_input_v2);
109  // TODO: add rect
110  if (t->inputPanelVisible != state) {
111  t->inputPanelVisible = state;
112  Q_EMIT t->q->inputPanelStateChanged();
113  }
114 }
115 
116 void TextInputUnstableV2::Private::preeditStringCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, const char *text, const char *commit)
117 {
118  auto t = reinterpret_cast<TextInputUnstableV2::Private *>(data);
119  Q_ASSERT(t->textinputunstablev2 == zwp_text_input_v2);
120  t->pendingPreEdit.commitText = QByteArray(commit);
121  t->pendingPreEdit.text = QByteArray(text);
122  if (!t->pendingPreEdit.cursorSet) {
123  t->pendingPreEdit.cursor = t->pendingPreEdit.text.length();
124  }
125  t->currentPreEdit = t->pendingPreEdit;
126  t->pendingPreEdit = TextInput::Private::PreEdit();
127  Q_EMIT t->q->composingTextChanged();
128 }
129 
130 void TextInputUnstableV2::Private::preeditStylingCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, uint32_t index, uint32_t length, uint32_t style)
131 {
132  Q_UNUSED(index)
133  Q_UNUSED(length)
134  Q_UNUSED(style)
135  // TODO: implement
136  auto t = reinterpret_cast<TextInputUnstableV2::Private *>(data);
137  Q_ASSERT(t->textinputunstablev2 == zwp_text_input_v2);
138 }
139 
140 void TextInputUnstableV2::Private::preeditCursorCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, int32_t index)
141 {
142  auto t = reinterpret_cast<TextInputUnstableV2::Private *>(data);
143  Q_ASSERT(t->textinputunstablev2 == zwp_text_input_v2);
144  t->pendingPreEdit.cursor = index;
145  t->pendingPreEdit.cursorSet = true;
146 }
147 
148 void TextInputUnstableV2::Private::commitStringCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, const char *text)
149 {
150  auto t = reinterpret_cast<TextInputUnstableV2::Private *>(data);
151  Q_ASSERT(t->textinputunstablev2 == zwp_text_input_v2);
152  t->pendingCommit.text = QByteArray(text);
153  t->currentCommit = t->pendingCommit;
154  // TODO: what are the proper values it should be set to?
155  t->pendingCommit = TextInput::Private::Commit();
156  t->pendingCommit.deleteSurrounding.beforeLength = 0;
157  t->pendingCommit.deleteSurrounding.afterLength = 0;
158  Q_EMIT t->q->committed();
159 }
160 
161 void TextInputUnstableV2::Private::cursorPositionCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, int32_t index, int32_t anchor)
162 {
163  auto t = reinterpret_cast<TextInputUnstableV2::Private *>(data);
164  Q_ASSERT(t->textinputunstablev2 == zwp_text_input_v2);
165  t->pendingCommit.cursor = index;
166  t->pendingCommit.anchor = anchor;
167 }
168 
169 void TextInputUnstableV2::Private::deleteSurroundingTextCallback(void *data,
170  zwp_text_input_v2 *zwp_text_input_v2,
171  uint32_t before_length,
172  uint32_t after_length)
173 {
174  auto t = reinterpret_cast<TextInputUnstableV2::Private *>(data);
175  Q_ASSERT(t->textinputunstablev2 == zwp_text_input_v2);
176  t->pendingCommit.deleteSurrounding.beforeLength = before_length;
177  t->pendingCommit.deleteSurrounding.afterLength = after_length;
178 }
179 
180 void TextInputUnstableV2::Private::modifiersMapCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, wl_array *map)
181 {
182  // TODO: implement
183  Q_UNUSED(map)
184  auto t = reinterpret_cast<TextInputUnstableV2::Private *>(data);
185  Q_ASSERT(t->textinputunstablev2 == zwp_text_input_v2);
186 }
187 
188 void TextInputUnstableV2::Private::keysymCallback(void *data,
189  zwp_text_input_v2 *zwp_text_input_v2,
190  uint32_t time,
191  uint32_t sym,
192  uint32_t wlState,
193  uint32_t modifiers)
194 {
195  // TODO: add support for modifiers
196  Q_UNUSED(modifiers)
197  auto t = reinterpret_cast<TextInputUnstableV2::Private *>(data);
198  Q_ASSERT(t->textinputunstablev2 == zwp_text_input_v2);
199  TextInput::KeyState state;
200  switch (wlState) {
201  case WL_KEYBOARD_KEY_STATE_RELEASED:
202  state = TextInput::KeyState::Released;
203  break;
204  case WL_KEYBOARD_KEY_STATE_PRESSED:
205  state = TextInput::KeyState::Pressed;
206  break;
207  default:
208  // invalid
209  return;
210  }
211  Q_EMIT t->q->keyEvent(sym, state, Qt::KeyboardModifiers(), time);
212 }
213 
214 void TextInputUnstableV2::Private::languageCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, const char *language)
215 {
216  auto t = reinterpret_cast<TextInputUnstableV2::Private *>(data);
217  Q_ASSERT(t->textinputunstablev2 == zwp_text_input_v2);
218  if (qstrcmp(t->language, language) != 0) {
219  t->language = QByteArray(language);
220  Q_EMIT t->q->languageChanged();
221  }
222 }
223 
224 void TextInputUnstableV2::Private::textDirectionCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, uint32_t wlDirection)
225 {
226  auto t = reinterpret_cast<TextInputUnstableV2::Private *>(data);
227  Q_ASSERT(t->textinputunstablev2 == zwp_text_input_v2);
228  Qt::LayoutDirection direction;
229  switch (wlDirection) {
230  case ZWP_TEXT_INPUT_V2_TEXT_DIRECTION_LTR:
231  direction = Qt::LeftToRight;
232  break;
233  case ZWP_TEXT_INPUT_V2_TEXT_DIRECTION_RTL:
234  direction = Qt::RightToLeft;
235  break;
236  case ZWP_TEXT_INPUT_V2_TEXT_DIRECTION_AUTO:
237  direction = Qt::LayoutDirectionAuto;
238  break;
239  default:
240  // invalid
241  return;
242  }
243  if (direction != t->textDirection) {
244  t->textDirection = direction;
245  Q_EMIT t->q->textDirectionChanged();
246  }
247 }
248 
249 void TextInputUnstableV2::Private::configureSurroundingTextCallback(void *data,
250  zwp_text_input_v2 *zwp_text_input_v2,
251  int32_t before_cursor,
252  int32_t after_cursor)
253 {
254  // TODO: implement
255  Q_UNUSED(before_cursor)
256  Q_UNUSED(after_cursor)
257  auto t = reinterpret_cast<TextInputUnstableV2::Private *>(data);
258  Q_ASSERT(t->textinputunstablev2 == zwp_text_input_v2);
259 }
260 
261 void TextInputUnstableV2::Private::inputMethodChangedCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, uint32_t serial, uint32_t flags)
262 {
263  Q_UNUSED(serial)
264  Q_UNUSED(flags)
265  // TODO: implement
266  auto t = reinterpret_cast<TextInputUnstableV2::Private *>(data);
267  Q_ASSERT(t->textinputunstablev2 == zwp_text_input_v2);
268 }
269 
270 TextInputUnstableV2::Private::Private(TextInputUnstableV2 *q, Seat *seat)
271  : TextInput::Private(seat)
272  , q(q)
273 {
274 }
275 
276 void TextInputUnstableV2::Private::setup(zwp_text_input_v2 *ti)
277 {
278  Q_ASSERT(ti);
279  Q_ASSERT(!textinputunstablev2);
280  textinputunstablev2.setup(ti);
281  zwp_text_input_v2_add_listener(ti, &s_listener, this);
282 }
283 
284 bool TextInputUnstableV2::Private::isValid() const
285 {
286  return textinputunstablev2.isValid();
287 }
288 
289 void TextInputUnstableV2::Private::enable(Surface *surface)
290 {
291  zwp_text_input_v2_enable(textinputunstablev2, *surface);
292 }
293 
294 void TextInputUnstableV2::Private::disable(Surface *surface)
295 {
296  zwp_text_input_v2_disable(textinputunstablev2, *surface);
297 }
298 
299 void TextInputUnstableV2::Private::showInputPanel()
300 {
301  zwp_text_input_v2_show_input_panel(textinputunstablev2);
302 }
303 
304 void TextInputUnstableV2::Private::hideInputPanel()
305 {
306  zwp_text_input_v2_hide_input_panel(textinputunstablev2);
307 }
308 
309 void TextInputUnstableV2::Private::setCursorRectangle(const QRect &rect)
310 {
311  zwp_text_input_v2_set_cursor_rectangle(textinputunstablev2, rect.x(), rect.y(), rect.width(), rect.height());
312 }
313 
314 void TextInputUnstableV2::Private::setPreferredLanguage(const QString &lang)
315 {
316  zwp_text_input_v2_set_preferred_language(textinputunstablev2, lang.toUtf8().constData());
317 }
318 
319 void TextInputUnstableV2::Private::setSurroundingText(const QString &text, quint32 cursor, quint32 anchor)
320 {
321  const QStringView strView(text);
322 
323  zwp_text_input_v2_set_surrounding_text(textinputunstablev2,
324  text.toUtf8().constData(),
325  strView.left(cursor).toUtf8().length(),
326  strView.left(anchor).toUtf8().length());
327 }
328 
329 void TextInputUnstableV2::Private::reset()
330 {
331  zwp_text_input_v2_update_state(textinputunstablev2, latestSerial, ZWP_TEXT_INPUT_V2_UPDATE_STATE_RESET);
332 }
333 
334 void TextInputUnstableV2::Private::setContentType(ContentHints hints, ContentPurpose purpose)
335 {
336  uint32_t wlHints = 0;
337  uint32_t wlPurpose = 0;
338  if (hints.testFlag(ContentHint::AutoCompletion)) {
339  wlHints |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_AUTO_COMPLETION;
340  }
341  if (hints.testFlag(ContentHint::AutoCorrection)) {
342  wlHints |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_AUTO_CORRECTION;
343  }
344  if (hints.testFlag(ContentHint::AutoCapitalization)) {
345  wlHints |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_AUTO_CAPITALIZATION;
346  }
347  if (hints.testFlag(ContentHint::LowerCase)) {
348  wlHints |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_LOWERCASE;
349  }
350  if (hints.testFlag(ContentHint::UpperCase)) {
351  wlHints |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_UPPERCASE;
352  }
353  if (hints.testFlag(ContentHint::TitleCase)) {
354  wlHints |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_TITLECASE;
355  }
356  if (hints.testFlag(ContentHint::HiddenText)) {
357  wlHints |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_HIDDEN_TEXT;
358  }
359  if (hints.testFlag(ContentHint::SensitiveData)) {
360  wlHints |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_SENSITIVE_DATA;
361  }
362  if (hints.testFlag(ContentHint::Latin)) {
363  wlHints |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_LATIN;
364  }
365  if (hints.testFlag(ContentHint::MultiLine)) {
366  wlHints |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_MULTILINE;
367  }
368  switch (purpose) {
369  case ContentPurpose::Normal:
370  wlPurpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_NORMAL;
371  break;
372  case ContentPurpose::Alpha:
373  wlPurpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_ALPHA;
374  break;
375  case ContentPurpose::Digits:
376  wlPurpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_DIGITS;
377  break;
378  case ContentPurpose::Number:
379  wlPurpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_NUMBER;
380  break;
381  case ContentPurpose::Phone:
382  wlPurpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_PHONE;
383  break;
384  case ContentPurpose::Url:
385  wlPurpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_URL;
386  break;
387  case ContentPurpose::Email:
388  wlPurpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_EMAIL;
389  break;
390  case ContentPurpose::Name:
391  wlPurpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_NAME;
392  break;
393  case ContentPurpose::Password:
394  wlPurpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_PASSWORD;
395  break;
396  case ContentPurpose::Date:
397  wlPurpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_DATE;
398  break;
399  case ContentPurpose::Time:
400  wlPurpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_TIME;
401  break;
402  case ContentPurpose::DateTime:
403  wlPurpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_DATETIME;
404  break;
405  case ContentPurpose::Terminal:
406  wlPurpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_TERMINAL;
407  break;
408  }
409  zwp_text_input_v2_set_content_type(textinputunstablev2, wlHints, wlPurpose);
410 }
411 
412 TextInputUnstableV2::TextInputUnstableV2(Seat *seat, QObject *parent)
413  : TextInput(new Private(this, seat), parent)
414 {
415 }
416 
417 TextInputUnstableV2::~TextInputUnstableV2()
418 {
419  release();
420 }
421 
422 TextInputUnstableV2::Private *TextInputUnstableV2::d_func() const
423 {
424  return reinterpret_cast<Private *>(d.data());
425 }
426 
427 void TextInputUnstableV2::setup(zwp_text_input_v2 *textinputunstablev2)
428 {
429  Q_D();
430  d->setup(textinputunstablev2);
431 }
432 
434 {
435  Q_D();
436  d->textinputunstablev2.release();
437 }
438 
439 void TextInputUnstableV2::destroy()
440 {
441  Q_D();
442  d->textinputunstablev2.destroy();
443 }
444 
445 TextInputUnstableV2::operator zwp_text_input_v2 *()
446 {
447  Q_D();
448  return d->textinputunstablev2;
449 }
450 
451 TextInputUnstableV2::operator zwp_text_input_v2 *() const
452 {
453  Q_D();
454  return d->textinputunstablev2;
455 }
456 
457 class TextInputManagerUnstableV2::Private : public TextInputManager::Private
458 {
459 public:
460  Private() = default;
461 
462  void release() override;
463  void destroy() override;
464  bool isValid() override;
465  void setupV2(zwp_text_input_manager_v2 *ti) override;
466  TextInput *createTextInput(Seat *seat, QObject *parent = nullptr) override;
467  using TextInputManager::Private::operator wl_text_input_manager *;
468  operator zwp_text_input_manager_v2 *() override
469  {
470  return textinputmanagerunstablev2;
471  }
472  operator zwp_text_input_manager_v2 *() const override
473  {
474  return textinputmanagerunstablev2;
475  }
476 
477  WaylandPointer<zwp_text_input_manager_v2, zwp_text_input_manager_v2_destroy> textinputmanagerunstablev2;
478 };
479 
481 {
482  textinputmanagerunstablev2.release();
483 }
484 
485 void TextInputManagerUnstableV2::Private::destroy()
486 {
487  textinputmanagerunstablev2.destroy();
488 }
489 
490 bool TextInputManagerUnstableV2::Private::isValid()
491 {
492  return textinputmanagerunstablev2.isValid();
493 }
494 
495 TextInputManagerUnstableV2::TextInputManagerUnstableV2(QObject *parent)
496  : TextInputManager(new Private, parent)
497 {
498 }
499 
500 TextInputManagerUnstableV2::~TextInputManagerUnstableV2() = default;
501 
502 void TextInputManagerUnstableV2::Private::setupV2(zwp_text_input_manager_v2 *ti)
503 {
504  Q_ASSERT(ti);
505  Q_ASSERT(!textinputmanagerunstablev2);
506  textinputmanagerunstablev2.setup(ti);
507 }
508 
509 TextInput *TextInputManagerUnstableV2::Private::createTextInput(Seat *seat, QObject *parent)
510 {
511  Q_ASSERT(isValid());
512  TextInputUnstableV2 *t = new TextInputUnstableV2(seat, parent);
513  auto w = zwp_text_input_manager_v2_get_text_input(textinputmanagerunstablev2, *seat);
514  if (queue) {
515  queue->addProxy(w);
516  }
517  t->setup(w);
518  return t;
519 }
520 
521 }
522 }
virtual void release(quint64 objid)
static Surface * get(wl_surface *native)
Definition: surface.cpp:212
int width() const const
int x() const const
int y() const const
KeyState
The possible states for a keyEvent.
Definition: textinput.h:113
QByteArray toUtf8() const const
int height() const const
const char * constData() const const
bool isValid(QStringView ifopt)
LayoutDirection
KGuiItem reset()
typedef KeyboardModifiers
Q_D(Todo)
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Jan 30 2023 03:56:25 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.