Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qwaylandtextinputv3.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
6
7#include <QtWaylandCompositor/QWaylandCompositor>
8#include <QtWaylandCompositor/private/qwaylandseat_p.h>
9
10#include "qwaylandsurface.h"
11#include "qwaylandview.h"
13
14#include <QGuiApplication>
15#include <QInputMethodEvent>
16#include <qpa/qwindowsysteminterface.h>
17
18#if QT_CONFIG(xkbcommon)
19#include <QtGui/private/qxkbcommon_p.h>
20#endif
21
23
24Q_DECLARE_LOGGING_CATEGORY(qLcWaylandCompositorTextInput)
25
29
31{
32 qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO;
33
34 Qt::InputMethodQueries queries;
35
36 if (hints != other.hints)
37 queries |= Qt::ImHints;
38 if (cursorRectangle != other.cursorRectangle)
39 queries |= Qt::ImCursorRectangle;
40 if (surroundingText != other.surroundingText)
42 if (cursorPosition != other.cursorPosition)
44 if (anchorPosition != other.anchorPosition)
46
47 return queries;
48}
49
51
52 Qt::InputMethodQueries queries;
53
54 if ((other.changedState & Qt::ImHints) && hints != other.hints) {
55 hints = other.hints;
56 queries |= Qt::ImHints;
57 }
58
59 if ((other.changedState & Qt::ImCursorRectangle) && cursorRectangle != other.cursorRectangle) {
60 cursorRectangle = other.cursorRectangle;
61 queries |= Qt::ImCursorRectangle;
62 }
63
64 if ((other.changedState & Qt::ImSurroundingText) && surroundingText != other.surroundingText) {
65 surroundingText = other.surroundingText;
67 }
68
69 if ((other.changedState & Qt::ImCursorPosition) && cursorPosition != other.cursorPosition) {
70 cursorPosition = other.cursorPosition;
72 }
73
74 if ((other.changedState & Qt::ImAnchorPosition) && anchorPosition != other.anchorPosition) {
75 anchorPosition = other.anchorPosition;
77 }
78
79 return queries;
80}
81
88
90{
91 qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO;
92
93 if (!focusResource || !focusResource->handle)
94 return;
95
96 bool needsDone = false;
97
98 const QString &newPreeditString = event->preeditString();
99
100 // Current cursor shape is only line. It means both cursorBegin
101 // and cursorEnd will be the same values.
102 int32_t preeditCursorPos = newPreeditString.length();
103
104 if (event->replacementLength() > 0 || event->replacementStart() < 0) {
105 if (event->replacementStart() <= 0 && (event->replacementLength() >= -event->replacementStart())) {
106 const int selectionStart = qMin(currentState->cursorPosition, currentState->anchorPosition);
107 const int selectionEnd = qMax(currentState->cursorPosition, currentState->anchorPosition);
108 const int before = QWaylandInputMethodEventBuilder::indexToWayland(currentState->surroundingText, -event->replacementStart(), selectionStart + event->replacementStart());
109 const int after = QWaylandInputMethodEventBuilder::indexToWayland(currentState->surroundingText, event->replacementLength() + event->replacementStart(), selectionEnd);
110 send_delete_surrounding_text(focusResource->handle, before, after);
111 needsDone = true;
112 } else {
113 qCWarning(qLcWaylandCompositorTextInput) << "Not yet supported case of replacement. Start:" << event->replacementStart() << "length:" << event->replacementLength();
114 }
115 preeditCursorPos = event->replacementStart() + event->replacementLength();
116 }
117
118 if (currentPreeditString != newPreeditString) {
119 currentPreeditString = newPreeditString;
120 send_preedit_string(focusResource->handle, currentPreeditString, preeditCursorPos, preeditCursorPos);
121 needsDone = true;
122 }
123 if (!event->commitString().isEmpty()) {
124 send_commit_string(focusResource->handle, event->commitString());
125 needsDone = true;
126 }
127
128 if (needsDone)
129 send_done(focusResource->handle, serials[focusResource]);
130}
131
132
134{
135 qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO;
136
137 if (!focusResource || !focusResource->handle)
138 return;
139
140 send_commit_string(focusResource->handle, event->text());
141
142 send_done(focusResource->handle, serials[focusResource]);
143}
144
146{
147 qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO << property;
148
149 switch (property) {
150 case Qt::ImHints:
151 return QVariant(static_cast<int>(currentState->hints));
154 case Qt::ImFont:
155 // Not supported
156 return QVariant();
158 qCDebug(qLcWaylandCompositorTextInput) << currentState->cursorPosition;
161 qCDebug(qLcWaylandCompositorTextInput) << currentState->surroundingText;
167 // Not supported
168 return QVariant();
170 qCDebug(qLcWaylandCompositorTextInput) << currentState->anchorPosition;
173 // We assume the surrounding text is our whole document for now
176 if (argument.isValid())
180 if (argument.isValid())
183
184 default:
185 return QVariant();
186 }
187}
188
190{
191 qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO << surface;
192
193 if (focusResource && focus) {
194 // sync before leave
195 // IBUS commits by itself but qtvirtualkeyboard doesn't
196 // And when handling chinese input, it is required to commit
197 // before leaving the focus.
198 if (qgetenv("QT_IM_MODULE") != QByteArrayLiteral("ibus")
199 || qApp->inputMethod()->locale().language() == QLocale::Chinese) {
200 qApp->inputMethod()->commit();
201 }
202
203 qApp->inputMethod()->hide();
204 inputPanelVisible = false;
205 send_leave(focusResource->handle, focus->resource());
207 }
208
209 if (focus != surface)
211
212 Resource *resource = surface ? resourceMap().value(surface->waylandClient()) : 0;
213 if (resource && surface) {
214 send_enter(resource->handle, surface->resource());
215
216 if (focus != surface)
218 }
219
220 focus = surface;
221 focusResource = resource;
222}
223
225{
226 qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO;
227
228 serials.insert(resource, 0);
229}
230
232{
233 qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO;
234
235 serials.remove(resource);
236 if (focusResource == resource)
237 focusResource = nullptr;
238}
239
241{
242 qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO;
243
244 wl_resource_destroy(resource->handle);
245}
246
248{
249 qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO;
250
252
254
255 enabledSurfaces.insert(resource, focus);
256 emit q->surfaceEnabled(focus);
257
258 inputPanelVisible = true;
259 qApp->inputMethod()->show();
260}
261
262void QWaylandTextInputV3Private::zwp_text_input_v3_disable(QtWaylandServer::zwp_text_input_v3::Resource *resource)
263{
264 qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO;
265
267
269 emit q->surfaceDisabled(s);
270
271 // When reselecting a word by setFocus
272 if (qgetenv("QT_IM_MODULE") != QByteArrayLiteral("ibus")
273 || qApp->inputMethod()->locale().language() == QLocale::Chinese) {
274 qApp->inputMethod()->commit();
275 }
276 qApp->inputMethod()->reset();
278}
279
280void QWaylandTextInputV3Private::zwp_text_input_v3_set_cursor_rectangle(Resource *resource, int32_t x, int32_t y, int32_t width, int32_t height)
281{
282 qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO << x << y << width << height;
283
284 if (resource != focusResource)
285 return;
286
288
290}
291
293{
294 qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO;
295
296 serials[resource] = serials[resource] < UINT_MAX ? serials[resource] + 1U : 0U;
297
298 // Just increase serials and ignore empty commits
300 qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO << "pendingState is not changed";
301 return;
302 }
303
304 // Selection starts.
305 // But since qtvirtualkeyboard with hunspell does not reset its preedit string,
306 // compositor forces to reset inputMethod.
309 qApp->inputMethod()->reset();
310
311 // Enable reselection
312 // This is a workaround to make qtvirtualkeyboad's state empty by clearing State::InputMethodClick.
314 qApp->inputMethod()->invokeAction(QInputMethod::Click, pendingState->cursorPosition);
315
316 Qt::InputMethodQueries queries = currentState->mergeChanged(*pendingState.data());
318
319 if (queries) {
320 qCDebug(qLcWaylandCompositorTextInput) << "QInputMethod::update() after commit with" << queries;
321
322 qApp->inputMethod()->update(queries);
323 }
324}
325
326void QWaylandTextInputV3Private::zwp_text_input_v3_set_content_type(Resource *resource, uint32_t hint, uint32_t purpose)
327{
328 qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO << hint << purpose;
329
330 if (resource != focusResource)
331 return;
332
334
335 if ((hint & content_hint_completion) == 0)
337 if ((hint & content_hint_auto_capitalization) == 0)
339 if ((hint & content_hint_lowercase) != 0)
341 if ((hint & content_hint_uppercase) != 0)
343 if ((hint & content_hint_hidden_text) != 0)
345 if ((hint & content_hint_sensitive_data) != 0)
347 if ((hint & content_hint_latin) != 0)
349 if ((hint & content_hint_multiline) != 0)
351
352 switch (purpose) {
353 case content_purpose_normal:
354 break;
355 case content_purpose_alpha:
357 break;
358 case content_purpose_digits:
360 break;
361 case content_purpose_number:
363 break;
364 case content_purpose_phone:
366 break;
367 case content_purpose_url:
369 break;
370 case content_purpose_email:
372 break;
373 case content_purpose_name:
374 case content_purpose_password:
375 break;
376 case content_purpose_date:
378 break;
379 case content_purpose_time:
381 break;
382 case content_purpose_datetime:
384 break;
385 case content_purpose_terminal:
386 default:
387 break;
388 }
389
390 qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO << pendingState->hints;
391
393}
394
408
410{
411 qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO;
412
413 Q_UNUSED(resource);
414 Q_UNUSED(cause);
415}
416
419{
420 connect(&d_func()->focusDestroyListener, &QWaylandDestroyListener::fired,
421 this, &QWaylandTextInputV3::focusSurfaceDestroyed);
422}
423
427
429{
431
432 d->sendInputMethodEvent(event);
433}
434
436{
438
439 d->sendKeyEvent(event);
440}
441
448
450{
451 const Q_D(QWaylandTextInputV3);
452
453 return d->focus;
454}
455
457{
459
460 d->setFocus(surface);
461}
462
463void QWaylandTextInputV3::focusSurfaceDestroyed(void *)
464{
465 qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO;
466
468
469 d->focusDestroyListener.reset();
470
471 d->focus = nullptr;
472 d->focusResource = nullptr;
473}
474
476{
477 qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO;
478
479 const Q_D(QWaylandTextInputV3);
480
481 return d->enabledSurfaces.values().contains(surface);
482}
483
484void QWaylandTextInputV3::add(::wl_client *client, uint32_t id, int version)
485{
486 qCDebug(qLcWaylandCompositorTextInput) << Q_FUNC_INFO << client << id << version;
487
489
490 d->add(client, id, version);
491}
492
494{
495 return QWaylandTextInputV3Private::interface();
496}
497
499{
500 return QWaylandTextInputV3Private::interfaceName();
501}
502
\inmodule QtCore
Definition qbytearray.h:57
bool remove(const Key &key)
Removes the item that has the key from the hash.
Definition qhash.h:958
T take(const Key &key)
Removes the item with the key from the hash and returns the value associated with it.
Definition qhash.h:985
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1303
The QInputMethodEvent class provides parameters for input method events.
Definition qevent.h:625
The QKeyEvent class describes a key event.
Definition qevent.h:424
@ Chinese
Definition qlocale.h:102
\inmodule QtCore\reentrant
Definition qrect.h:30
T * data() const noexcept
Returns the value of the pointer referenced by this object.
void reset(T *other=nullptr) noexcept(noexcept(Cleanup::cleanup(std::declval< T * >())))
Deletes the existing object it is pointing to (if any), and sets its pointer to other.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
QString left(qsizetype n) const &
Definition qstring.h:363
QString mid(qsizetype position, qsizetype n=-1) const &
Definition qstring.cpp:5300
void clear()
Clears the contents of the string and makes it null.
Definition qstring.h:1252
QString right(qsizetype n) const &
Definition qstring.h:375
qsizetype length() const noexcept
Returns the number of characters in this string.
Definition qstring.h:191
\inmodule QtCore
Definition qvariant.h:65
\qmltype WaylandCompositor \instantiates QWaylandCompositor \inqmlmodule QtWayland....
void fired(void *data)
void listenForDestruction(struct wl_resource *resource)
static int indexFromWayland(const QString &text, int length, int base=0)
static int indexToWayland(const QString &text, int length, int base=0)
\inmodule QtWaylandCompositor
\qmltype WaylandSurface \instantiates QWaylandSurface \inqmlmodule QtWayland.Compositor
struct wl_resource * resource() const
Returns the Wayland resource corresponding to this QWaylandSurface.
::wl_client * waylandClient() const
Holds the wl_client using this QWaylandSurface.
Qt::InputMethodQueries mergeChanged(const QWaylandTextInputV3ClientState &other)
Qt::InputMethodQueries updatedQueries(const QWaylandTextInputV3ClientState &other) const
void zwp_text_input_v3_destroy_resource(Resource *resource) override
QWaylandTextInputV3Private(QWaylandCompositor *compositor)
void zwp_text_input_v3_set_content_type(Resource *resource, uint32_t hint, uint32_t purpose) override
void zwp_text_input_v3_enable(Resource *resource) override
void zwp_text_input_v3_commit(Resource *resource) override
QScopedPointer< QWaylandTextInputV3ClientState > currentState
void sendInputMethodEvent(QInputMethodEvent *event)
void zwp_text_input_v3_set_text_change_cause(Resource *resource, uint32_t cause) override
void zwp_text_input_v3_disable(Resource *resource) override
QWaylandDestroyListener focusDestroyListener
void zwp_text_input_v3_bind_resource(Resource *resource) override
QVariant inputMethodQuery(Qt::InputMethodQuery property, QVariant argument) const
QHash< Resource *, uint32_t > serials
void sendKeyEvent(QKeyEvent *event)
void zwp_text_input_v3_destroy(Resource *resource) override
void zwp_text_input_v3_set_cursor_rectangle(Resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) override
QHash< Resource *, QWaylandSurface * > enabledSurfaces
void setFocus(QWaylandSurface *surface)
void zwp_text_input_v3_set_surrounding_text(Resource *resource, const QString &text, int32_t cursor, int32_t anchor) override
QScopedPointer< QWaylandTextInputV3ClientState > pendingState
static const struct wl_interface * interface()
QVariant inputMethodQuery(Qt::InputMethodQuery property, QVariant argument) const
void sendInputMethodEvent(QInputMethodEvent *event)
static QByteArray interfaceName()
void setFocus(QWaylandSurface *surface)
void add(::wl_client *client, uint32_t id, int version)
QWaylandTextInputV3(QWaylandObject *container, QWaylandCompositor *compositor)
QWaylandSurface * focus() const
void sendKeyEvent(QKeyEvent *event)
bool isSurfaceEnabled(QWaylandSurface *surface) const
QString text
QCursor cursor
Combined button and popup list for selecting options.
InputMethodQuery
@ ImMaximumTextLength
@ ImTextBeforeCursor
@ ImSurroundingText
@ ImCursorPosition
@ ImCurrentSelection
@ ImAbsolutePosition
@ ImFont
@ ImAnchorPosition
@ ImCursorRectangle
@ ImHints
@ ImTextAfterCursor
@ ImhPreferUppercase
@ ImhUrlCharactersOnly
@ ImhPreferLowercase
@ ImhTime
@ ImhFormattedNumbersOnly
@ ImhNone
@ ImhMultiLine
@ ImhLatinOnly
@ ImhUppercaseOnly
@ ImhNoPredictiveText
@ ImhDigitsOnly
@ ImhSensitiveData
@ ImhLowercaseOnly
@ ImhEmailCharactersOnly
@ ImhHiddenText
@ ImhNoAutoUppercase
@ ImhDialableCharactersOnly
@ ImhDate
#define QByteArrayLiteral(str)
Definition qbytearray.h:52
#define Q_FUNC_INFO
#define qApp
#define qCWarning(category,...)
#define qCDebug(category,...)
#define Q_DECLARE_LOGGING_CATEGORY(name)
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
constexpr T qAbs(const T &t)
Definition qnumeric.h:328
static QOpenGLCompositor * compositor
GLint GLint GLint GLint GLint x
[0]
GLint GLsizei GLsizei height
GLint GLsizei width
GLint y
struct _cl_event * event
GLdouble s
[6]
Definition qopenglext.h:235
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
static QT_BEGIN_NAMESPACE QVariant hint(QPlatformIntegration::StyleHint h)
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)
#define emit
#define Q_UNUSED(x)
const char property[13]
Definition qwizard.cpp:101
connect(quitButton, &QPushButton::clicked, &app, &QCoreApplication::quit, Qt::QueuedConnection)
QSharedPointer< T > other(t)
[5]
QDBusArgument argument