Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qwaylandinputmethodcontext.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5#include "qwaylanddisplay_p.h"
7
8#include <QtGui/qguiapplication.h>
9#include <QtGui/qtextformat.h>
10#include <QtGui/private/qguiapplication_p.h>
11
13
14Q_DECLARE_LOGGING_CATEGORY(qLcQpaInputMethods)
15
16namespace QtWaylandClient {
17
18static constexpr int maxStringSize = 1000; // actual max is 4096/3
19
20QWaylandTextInputMethod::QWaylandTextInputMethod(QWaylandDisplay *display, struct ::qt_text_input_method_v1 *textInputMethod)
21 : QtWayland::qt_text_input_method_v1(textInputMethod)
22{
24}
25
27{
28}
29
31{
32 if (m_isVisible != visible) {
33 m_isVisible = visible;
35 }
36}
37
39{
40 m_locale = QLocale(localeName);
41}
42
44{
45 m_layoutDirection = Qt::LayoutDirection(inputDirection);
46}
47
49{
50 const QRectF keyboardRectangle(wl_fixed_to_double(x),
51 wl_fixed_to_double(y),
52 wl_fixed_to_double(width),
53 wl_fixed_to_double(height));
54 if (m_keyboardRect != keyboardRectangle) {
55 m_keyboardRect = keyboardRectangle;
57 }
58}
59
60void QWaylandTextInputMethod::text_input_method_v1_start_input_method_event(uint32_t serial, int32_t surrounding_text_offset)
61{
62 if (m_pendingInputMethodEvents.contains(serial)) {
63 qCWarning(qLcQpaInputMethods) << "Input method event with serial" << serial << "already started";
64 return;
65 }
66
67 m_pendingInputMethodEvents[serial] = QList<QInputMethodEvent::Attribute>{};
68 m_offsetFromCompositor[serial] = surrounding_text_offset;
69}
70
71// We need to keep surrounding text below maxStringSize characters, with cursorPos centered in that substring
72
73static int calculateOffset(const QString &text, int cursorPos)
74{
75 int size = text.size();
76 int halfSize = maxStringSize/2;
77 if (size <= maxStringSize || cursorPos < halfSize)
78 return 0;
79 if (cursorPos > size - halfSize)
80 return size - maxStringSize;
81 return cursorPos - halfSize;
82}
83
85{
86 return s.mid(offset, maxStringSize);
87}
88
90{
91 return pos - offset;
92}
93
95{
96 return pos + offset;
97}
98
100{
101 if (!m_pendingInputMethodEvents.contains(serial)) {
102 qCWarning(qLcQpaInputMethods) << "Input method event with serial" << serial << "does not exist";
103 return;
104 }
105
106 int startMapped = mapPositionFromCompositor(start, m_offsetFromCompositor[serial]);
107 QList<QInputMethodEvent::Attribute> &attributes = m_pendingInputMethodEvents[serial];
108 switch (type) {
111 break;
114 break;
116 {
117 QTextCharFormat textFormat;
118 textFormat.setProperty(QTextFormat::FontUnderline, true);
121 break;
122 }
126 break;
127 };
128}
129
131{
132 int cursorPosition = event->value(Qt::ImCursorPosition).toInt();
133 int anchorPosition = event->value(Qt::ImAnchorPosition).toInt();
134 QString surroundingText = event->value(Qt::ImSurroundingText).toString();
135 int offset = calculateOffset(surroundingText, cursorPosition);
136
137 if (queries & Qt::ImCursorPosition)
138 update_cursor_position(mapPositionToCompositor(cursorPosition, offset));
139 if (queries & Qt::ImSurroundingText)
140 update_surrounding_text(mapSurroundingTextToCompositor(surroundingText, offset), offset);
141 if (queries & Qt::ImAnchorPosition)
142 update_anchor_position(mapPositionToCompositor(anchorPosition, offset));
143 if (queries & Qt::ImAbsolutePosition)
144 update_absolute_position(event->value(Qt::ImAbsolutePosition).toInt()); // do not map: this is the position in the whole document
145}
146
147
148void QWaylandTextInputMethod::text_input_method_v1_end_input_method_event(uint32_t serial, const QString &commitString, const QString &preeditString, int32_t replacementStart, int32_t replacementLength)
149{
150 if (!m_pendingInputMethodEvents.contains(serial)) {
151 qCWarning(qLcQpaInputMethods) << "Input method event with serial" << serial << "does not exist";
152 return;
153 }
154
155 QList<QInputMethodEvent::Attribute> attributes = m_pendingInputMethodEvents.take(serial);
156 m_offsetFromCompositor.remove(serial);
157 if (QGuiApplication::focusObject() != nullptr) {
158 QInputMethodEvent event(preeditString, attributes);
159 event.setCommitString(commitString, replacementStart, replacementLength);
161 }
162
163 // Send current state to make sure it matches
164 if (QGuiApplication::focusObject() != nullptr) {
168 }
169
170 acknowledge_input_method();
171}
172
174 int32_t key,
175 int32_t modifiers,
176 int32_t autoRepeat,
177 int32_t count,
178 int32_t nativeScanCode,
179 int32_t nativeVirtualKey,
180 int32_t nativeModifiers,
181 const QString &text)
182{
183 if (QGuiApplication::focusObject() != nullptr) {
185 key,
186 Qt::KeyboardModifiers(modifiers),
187 nativeScanCode,
188 nativeVirtualKey,
189 nativeModifiers,
190 text,
191 autoRepeat,
192 count);
194 }
195}
196
198{
199 m_surface = surface;
200}
201
203{
204 if (surface != m_surface) {
205 qCWarning(qLcQpaInputMethods) << "Got leave event for surface without corresponding enter";
206 } else {
207 m_surface = nullptr;
208 }
209}
210
212 : m_display(display)
213{
214}
215
217{
218}
219
221{
222 return m_display->textInputMethodManager() != nullptr;
223}
224
226{
227 QWaylandTextInputMethod *inputMethod = textInputMethod();
228 if (inputMethod != nullptr)
229 inputMethod->reset();
230}
231
233{
234 QWaylandTextInputMethod *inputMethod = textInputMethod();
235 if (inputMethod != nullptr)
236 inputMethod->commit();
237
238 m_display->forceRoundTrip();
239}
240
241void QWaylandInputMethodContext::update(Qt::InputMethodQueries queries)
242{
243 wl_surface *currentSurface = m_currentWindow != nullptr && m_currentWindow->handle() != nullptr
244 ? static_cast<QWaylandWindow *>(m_currentWindow->handle())->wlSurface()
245 : nullptr;
246 if (currentSurface != nullptr && !inputMethodAccepted()) {
247 textInputMethod()->disable(currentSurface);
248 m_currentWindow.clear();
249 } else if (currentSurface == nullptr && inputMethodAccepted()) {
251 currentSurface = window != nullptr && window->handle() != nullptr
252 ? static_cast<QWaylandWindow *>(window->handle())->wlSurface()
253 : nullptr;
254 if (currentSurface != nullptr) {
255 textInputMethod()->disable(currentSurface);
256 m_currentWindow = window;
257 }
258 }
259
260 queries &= (Qt::ImEnabled
270
271 const Qt::InputMethodQueries queriesNeedingOffset = Qt::ImCursorPosition | Qt::ImSurroundingText | Qt::ImAnchorPosition;
272 if (queries & queriesNeedingOffset)
273 queries |= queriesNeedingOffset;
274
275 QWaylandTextInputMethod *inputMethod = textInputMethod();
276 if (inputMethod != nullptr && QGuiApplication::focusObject() != nullptr) {
279
280 inputMethod->start_update(int(queries));
281
282 if (queries & Qt::ImHints)
283 inputMethod->update_hints(event.value(Qt::ImHints).toInt());
284
285 if (queries & Qt::ImCursorRectangle) {
286 QRect rect = event.value(Qt::ImCursorRectangle).toRect();
287 inputMethod->update_cursor_rectangle(rect.x(), rect.y(), rect.width(), rect.height());
288 }
289
290 inputMethod->sendInputState(&event, queries);
291
292 if (queries & Qt::ImPreferredLanguage)
293 inputMethod->update_preferred_language(event.value(Qt::ImPreferredLanguage).toString());
294
295 inputMethod->end_update();
296
297 // ### Should we do a display sync here and ignore all events until it is received?
298 }
299}
300
302{
303 QWaylandTextInputMethod *inputMethod = textInputMethod();
304 if (inputMethod != nullptr)
305 inputMethod->invoke_action(int(action), cursorPosition);
306}
307
309{
310 QWaylandTextInputMethod *inputMethod = textInputMethod();
311 if (inputMethod != nullptr)
312 inputMethod->show_input_panel();
313}
314
316{
317 QWaylandTextInputMethod *inputMethod = textInputMethod();
318 if (inputMethod != nullptr)
319 inputMethod->hide_input_panel();
320}
321
323{
324 QWaylandTextInputMethod *inputMethod = textInputMethod();
325 if (inputMethod != nullptr)
326 return inputMethod->isVisible();
327 else
328 return false;
329}
330
332{
333 QWaylandTextInputMethod *inputMethod = textInputMethod();
334 if (inputMethod != nullptr)
335 return inputMethod->keyboardRect();
336 else
337 return QRectF();
338}
339
341{
342 QWaylandTextInputMethod *inputMethod = textInputMethod();
343 if (inputMethod != nullptr)
344 return inputMethod->locale();
345 else
346 return QLocale();
347}
348
350{
351 QWaylandTextInputMethod *inputMethod = textInputMethod();
352 if (inputMethod != nullptr)
353 return inputMethod->inputDirection();
354 else
355 return Qt::LeftToRight;
356}
357
359{
360 QWaylandTextInputMethod *inputMethod = textInputMethod();
361 if (inputMethod == nullptr)
362 return;
363
365
366 if (m_currentWindow != nullptr && m_currentWindow->handle() != nullptr) {
367 if (m_currentWindow.data() != window || !inputMethodAccepted()) {
368 auto *surface = static_cast<QWaylandWindow *>(m_currentWindow->handle())->wlSurface();
369 if (surface)
370 inputMethod->disable(surface);
371 m_currentWindow.clear();
372 }
373 }
374
375 if (window != nullptr && window->handle() != nullptr && inputMethodAccepted()) {
376 if (m_currentWindow.data() != window) {
377 auto *surface = static_cast<QWaylandWindow *>(window->handle())->wlSurface();
378 if (surface != nullptr) {
379 inputMethod->enable(surface);
380 m_currentWindow = window;
381 }
382 }
383
385 }
386}
387
388QWaylandTextInputMethod *QWaylandInputMethodContext::textInputMethod() const
389{
390 return m_display->defaultInputDevice() ? m_display->defaultInputDevice()->textInputMethod() : nullptr;
391}
392
393} // QtWaylandClient
394
396
397#include "moc_qwaylandinputmethodcontext_p.cpp"
static QColor fromString(QAnyStringView name) noexcept
Definition qcolor.cpp:980
static bool sendEvent(QObject *receiver, QEvent *event)
Sends event event directly to receiver receiver, using the notify() function.
Type
This enum type defines the valid event types in Qt.
Definition qcoreevent.h:51
static QPlatformIntegration * platformIntegration()
static QObject * focusObject()
Returns the QObject in currently active window that will be final receiver of events tied to focus,...
static QWindow * focusWindow()
Returns the QWindow that receives events tied to focus, such as key events.
bool remove(const Key &key)
Removes the item that has the key from the hash.
Definition qhash.h:956
T take(const Key &key)
Removes the item with the key from the hash and returns the value associated with it.
Definition qhash.h:975
bool contains(const Key &key) const noexcept
Returns true if the hash contains an item with the key; otherwise returns false.
Definition qhash.h:991
The QInputMethodEvent class provides parameters for input method events.
Definition qevent.h:624
AttributeType
\value TextFormat A QTextCharFormat for the part of the preedit string specified by start and length.
Definition qevent.h:627
The QInputMethodQueryEvent class provides an event sent by the input context to input objects.
Definition qevent.h:678
Action
Indicates the kind of action performed by the user.
The QKeyEvent class describes a key event.
Definition qevent.h:423
Definition qlist.h:74
void append(parameter_type t)
Definition qlist.h:441
\inmodule QtCore
Definition qobject.h:90
bool inputMethodAccepted() const
Returns true if current focus object supports input method events.
void emitInputPanelVisibleChanged()
Active QPlatformInputContext is responsible for providing visible property to QInputMethod.
void emitKeyboardRectChanged()
Active QPlatformInputContext is responsible for providing keyboardRectangle property to QInputMethod.
virtual QPlatformInputContext * inputContext() const
Returns the platforms input context.
void clear()
Definition qpointer.h:70
T * data() const
Definition qpointer.h:56
\inmodule QtCore\reentrant
Definition qrect.h:483
\inmodule QtCore\reentrant
Definition qrect.h:30
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
qsizetype size() const
Returns the number of characters in this string.
Definition qstring.h:182
QString mid(qsizetype position, qsizetype n=-1) const
Returns a string that contains n characters of this string, starting at the specified position index.
Definition qstring.cpp:5204
void setProperty(int propertyId, const QVariant &value)
Sets the property specified by the propertyId to the given value.
\inmodule QtGui
Definition qwindow.h:63
QWaylandInputDevice * defaultInputDevice() const
QtWayland::qt_text_input_method_manager_v1 * textInputMethodManager() const
QWaylandTextInputMethod * textInputMethod() const
void update(Qt::InputMethodQueries) override
Notification on editor updates.
Qt::LayoutDirection inputDirection() const override
bool isInputPanelVisible() const override
Returns input panel visibility status.
void reset() override
Method to be called when input method needs to be reset.
void setFocusObject(QObject *object) override
This virtual method gets called to notify updated focus to object.
void hideInputPanel() override
Request to hide input panel.
QRectF keyboardRect() const override
This function can be reimplemented to return virtual keyboard rectangle in currently active window co...
void showInputPanel() override
Request to show input panel.
bool isValid() const override
Returns input context validity.
void invokeAction(QInputMethod::Action, int cursorPosition) override
Called when the word currently being composed in the input item is tapped by the user.
void text_input_method_v1_start_input_method_event(uint32_t serial, int32_t surrounding_text_offset) override
void text_input_method_v1_key(int32_t type, int32_t key, int32_t modifiers, int32_t autoRepeat, int32_t count, int32_t nativeScanCode, int32_t nativeVirtualKey, int32_t nativeModifiers, const QString &text) override
void text_input_method_v1_input_method_event_attribute(uint32_t serial, int32_t type, int32_t start, int32_t length, const QString &value) override
void text_input_method_v1_leave(struct ::wl_surface *surface) override
void text_input_method_v1_end_input_method_event(uint32_t serial, const QString &commitString, const QString &preeditString, int32_t replacementStart, int32_t replacementLength) override
void sendInputState(QInputMethodQueryEvent *state, Qt::InputMethodQueries queries=Qt::ImQueryInput)
void text_input_method_v1_keyboard_rectangle_changed(wl_fixed_t x, wl_fixed_t y, wl_fixed_t width, wl_fixed_t height) override
void text_input_method_v1_input_direction_changed(int32_t inputDirection) override
void text_input_method_v1_locale_changed(const QString &localeName) override
void text_input_method_v1_enter(struct ::wl_surface *surface) override
QWaylandTextInputMethod(QWaylandDisplay *display, struct ::qt_text_input_method_v1 *textInputMethod)
void text_input_method_v1_visible_changed(int32_t visible) override
EGLImageKHR int int EGLuint64KHR * modifiers
QString text
rect
[4]
struct wl_display * display
Definition linuxdmabuf.h:41
Combined button and popup list for selecting options.
static int mapPositionFromCompositor(int pos, int offset)
static int calculateOffset(const QString &text, int cursorPos)
static constexpr int maxStringSize
static QString mapSurroundingTextToCompositor(const QString &s, int offset)
static int mapPositionToCompositor(int pos, int offset)
@ ImTextBeforeCursor
@ ImSurroundingText
@ ImCursorPosition
@ ImCurrentSelection
@ ImAbsolutePosition
@ ImPreferredLanguage
@ ImAnchorPosition
@ ImCursorRectangle
@ ImHints
@ ImEnabled
@ ImTextAfterCursor
@ ImQueryAll
LayoutDirection
@ LeftToRight
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define qCWarning(category,...)
#define Q_DECLARE_LOGGING_CATEGORY(name)
GLint GLint GLint GLint GLint x
[0]
GLuint64 key
GLint GLsizei GLsizei height
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum GLuint GLenum GLsizei length
GLenum GLenum GLsizei count
GLint GLsizei width
GLenum type
GLuint start
GLenum GLuint GLintptr offset
GLint y
struct _cl_event * event
GLdouble s
[6]
Definition qopenglext.h:235
#define Q_UNUSED(x)
aWidget window() -> setWindowTitle("New Window Title")
[2]