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

KDE's Doxygen guidelines are available online.