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
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 qt_text_input_method_v1_destroy(object());
29}
30
32{
33 if (m_isVisible != visible) {
34 m_isVisible = visible;
35 QGuiApplicationPrivate::platformIntegration()->inputContext()->emitInputPanelVisibleChanged();
36 }
37}
38
40{
41 m_locale = QLocale(localeName);
42}
43
48
50{
51 const QRectF keyboardRectangle(wl_fixed_to_double(x),
52 wl_fixed_to_double(y),
53 wl_fixed_to_double(width),
54 wl_fixed_to_double(height));
55 if (m_keyboardRect != keyboardRectangle) {
56 m_keyboardRect = keyboardRectangle;
57 QGuiApplicationPrivate::platformIntegration()->inputContext()->emitKeyboardRectChanged();
58 }
59}
60
61void QWaylandTextInputMethod::text_input_method_v1_start_input_method_event(uint32_t serial, int32_t surrounding_text_offset)
62{
63 if (m_pendingInputMethodEvents.contains(serial)) {
64 qCWarning(qLcQpaInputMethods) << "Input method event with serial" << serial << "already started";
65 return;
66 }
67
68 m_pendingInputMethodEvents[serial] = QList<QInputMethodEvent::Attribute>{};
69 m_offsetFromCompositor[serial] = surrounding_text_offset;
70}
71
72// We need to keep surrounding text below maxStringSize characters, with cursorPos centered in that substring
73
74static int calculateOffset(const QString &text, int cursorPos)
75{
76 int size = text.size();
77 int halfSize = maxStringSize/2;
78 if (size <= maxStringSize || cursorPos < halfSize)
79 return 0;
80 if (cursorPos > size - halfSize)
81 return size - maxStringSize;
82 return cursorPos - halfSize;
83}
84
86{
87 return s.mid(offset, maxStringSize);
88}
89
91{
92 return pos - offset;
93}
94
96{
97 return pos + offset;
98}
99
101{
102 if (!m_pendingInputMethodEvents.contains(serial)) {
103 qCWarning(qLcQpaInputMethods) << "Input method event with serial" << serial << "does not exist";
104 return;
105 }
106
107 int startMapped = mapPositionFromCompositor(start, m_offsetFromCompositor[serial]);
108 QList<QInputMethodEvent::Attribute> &attributes = m_pendingInputMethodEvents[serial];
109 switch (type) {
112 break;
115 break;
117 {
118 QTextCharFormat textFormat;
119 textFormat.setProperty(QTextFormat::FontUnderline, true);
122 break;
123 }
127 break;
128 };
129}
130
132{
133 int cursorPosition = event->value(Qt::ImCursorPosition).toInt();
134 int anchorPosition = event->value(Qt::ImAnchorPosition).toInt();
135 QString surroundingText = event->value(Qt::ImSurroundingText).toString();
136 int offset = calculateOffset(surroundingText, cursorPosition);
137
138 if (queries & Qt::ImCursorPosition)
139 update_cursor_position(mapPositionToCompositor(cursorPosition, offset));
140 if (queries & Qt::ImSurroundingText)
141 update_surrounding_text(mapSurroundingTextToCompositor(surroundingText, offset), offset);
142 if (queries & Qt::ImAnchorPosition)
143 update_anchor_position(mapPositionToCompositor(anchorPosition, offset));
144 if (queries & Qt::ImAbsolutePosition)
145 update_absolute_position(event->value(Qt::ImAbsolutePosition).toInt()); // do not map: this is the position in the whole document
146}
147
148
149void QWaylandTextInputMethod::text_input_method_v1_end_input_method_event(uint32_t serial, const QString &commitString, const QString &preeditString, int32_t replacementStart, int32_t replacementLength)
150{
151 if (!m_pendingInputMethodEvents.contains(serial)) {
152 qCWarning(qLcQpaInputMethods) << "Input method event with serial" << serial << "does not exist";
153 return;
154 }
155
156 QList<QInputMethodEvent::Attribute> attributes = m_pendingInputMethodEvents.take(serial);
157 m_offsetFromCompositor.remove(serial);
158 if (QGuiApplication::focusObject() != nullptr) {
159 QInputMethodEvent event(preeditString, attributes);
160 event.setCommitString(commitString, replacementStart, replacementLength);
162 }
163
164 // Send current state to make sure it matches
165 if (QGuiApplication::focusObject() != nullptr) {
169 }
170
171 acknowledge_input_method();
172}
173
175 int32_t key,
176 int32_t modifiers,
177 int32_t autoRepeat,
178 int32_t count,
179 int32_t nativeScanCode,
180 int32_t nativeVirtualKey,
181 int32_t nativeModifiers,
182 const QString &text)
183{
184 if (QGuiApplication::focusObject() != nullptr) {
186 key,
187 Qt::KeyboardModifiers(modifiers),
188 nativeScanCode,
189 nativeVirtualKey,
190 nativeModifiers,
191 text,
192 autoRepeat,
193 count);
195 }
196}
197
199{
200 m_surface = surface;
201}
202
204{
205 if (surface != m_surface) {
206 qCWarning(qLcQpaInputMethods) << "Got leave event for surface without corresponding enter";
207 } else {
208 m_surface = nullptr;
209 }
210}
211
216
220
222{
223 return m_display->textInputMethodManager() != nullptr;
224}
225
227{
228 QWaylandTextInputMethod *inputMethod = textInputMethod();
229 if (inputMethod != nullptr)
230 inputMethod->reset();
231}
232
234{
235 QWaylandTextInputMethod *inputMethod = textInputMethod();
236 if (inputMethod != nullptr)
237 inputMethod->commit();
238
239 m_display->forceRoundTrip();
240}
241
242void QWaylandInputMethodContext::update(Qt::InputMethodQueries queries)
243{
244 wl_surface *currentSurface = m_currentWindow != nullptr && m_currentWindow->handle() != nullptr
245 ? static_cast<QWaylandWindow *>(m_currentWindow->handle())->wlSurface()
246 : nullptr;
247 if (currentSurface != nullptr && !inputMethodAccepted()) {
248 textInputMethod()->disable(currentSurface);
249 m_currentWindow.clear();
250 } else if (currentSurface == nullptr && inputMethodAccepted()) {
252 currentSurface = window != nullptr && window->handle() != nullptr
253 ? static_cast<QWaylandWindow *>(window->handle())->wlSurface()
254 : nullptr;
255 if (currentSurface != nullptr) {
256 textInputMethod()->disable(currentSurface);
257 m_currentWindow = window;
258 }
259 }
260
261 queries &= (Qt::ImEnabled
271
272 const Qt::InputMethodQueries queriesNeedingOffset = Qt::ImCursorPosition | Qt::ImSurroundingText | Qt::ImAnchorPosition;
273 if (queries & queriesNeedingOffset)
274 queries |= queriesNeedingOffset;
275
276 QWaylandTextInputMethod *inputMethod = textInputMethod();
277 if (inputMethod != nullptr && QGuiApplication::focusObject() != nullptr) {
280
281 inputMethod->start_update(int(queries));
282
283 if (queries & Qt::ImHints)
284 inputMethod->update_hints(event.value(Qt::ImHints).toInt());
285
286 if (queries & Qt::ImCursorRectangle) {
287 QRect rect = event.value(Qt::ImCursorRectangle).toRect();
288 inputMethod->update_cursor_rectangle(rect.x(), rect.y(), rect.width(), rect.height());
289 }
290
291 inputMethod->sendInputState(&event, queries);
292
293 if (queries & Qt::ImPreferredLanguage)
294 inputMethod->update_preferred_language(event.value(Qt::ImPreferredLanguage).toString());
295
296 inputMethod->end_update();
297
298 // ### Should we do a display sync here and ignore all events until it is received?
299 }
300}
301
303{
304 QWaylandTextInputMethod *inputMethod = textInputMethod();
305 if (inputMethod != nullptr)
306 inputMethod->invoke_action(int(action), cursorPosition);
307}
308
310{
311 QWaylandTextInputMethod *inputMethod = textInputMethod();
312 if (inputMethod != nullptr)
313 inputMethod->show_input_panel();
314}
315
317{
318 QWaylandTextInputMethod *inputMethod = textInputMethod();
319 if (inputMethod != nullptr)
320 inputMethod->hide_input_panel();
321}
322
324{
325 QWaylandTextInputMethod *inputMethod = textInputMethod();
326 if (inputMethod != nullptr)
327 return inputMethod->isVisible();
328 else
329 return false;
330}
331
333{
334 QWaylandTextInputMethod *inputMethod = textInputMethod();
335 if (inputMethod != nullptr)
336 return inputMethod->keyboardRect();
337 else
338 return QRectF();
339}
340
342{
343 QWaylandTextInputMethod *inputMethod = textInputMethod();
344 if (inputMethod != nullptr)
345 return inputMethod->locale();
346 else
347 return QLocale();
348}
349
351{
352 QWaylandTextInputMethod *inputMethod = textInputMethod();
353 if (inputMethod != nullptr)
354 return inputMethod->inputDirection();
355 else
356 return Qt::LeftToRight;
357}
358
360{
361 QWaylandTextInputMethod *inputMethod = textInputMethod();
362 if (inputMethod == nullptr)
363 return;
364
365 if (inputMethod->isVisible() && !inputMethodAccepted())
366 inputMethod->hide_input_panel();
367
369
370 if (m_currentWindow != nullptr && m_currentWindow->handle() != nullptr) {
371 if (m_currentWindow.data() != window || !inputMethodAccepted()) {
372 auto *surface = static_cast<QWaylandWindow *>(m_currentWindow->handle())->wlSurface();
373 if (surface)
374 inputMethod->disable(surface);
375 m_currentWindow.clear();
376 }
377 }
378
379 if (window != nullptr && window->handle() != nullptr && inputMethodAccepted()) {
380 if (m_currentWindow.data() != window) {
381 auto *surface = static_cast<QWaylandWindow *>(window->handle())->wlSurface();
382 if (surface != nullptr) {
383 inputMethod->enable(surface);
384 m_currentWindow = window;
385 }
386 }
387
389 }
390}
391
392QWaylandTextInputMethod *QWaylandInputMethodContext::textInputMethod() const
393{
394 return m_display->defaultInputDevice() ? m_display->defaultInputDevice()->textInputMethod() : nullptr;
395}
396
397} // QtWaylandClient
398
400
401#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: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
bool contains(const Key &key) const noexcept
Returns true if the hash contains an item with the key; otherwise returns false.
Definition qhash.h:1007
The QInputMethodEvent class provides parameters for input method events.
Definition qevent.h:625
AttributeType
\value TextFormat A QTextCharFormat for the part of the preedit string specified by start and length.
Definition qevent.h:628
The QInputMethodQueryEvent class provides an event sent by the input context to input objects.
Definition qevent.h:679
Action
Indicates the kind of action performed by the user.
The QKeyEvent class describes a key event.
Definition qevent.h:424
\inmodule QtCore
Definition qobject.h:103
bool inputMethodAccepted() const
Returns true if current focus object supports input method events.
void clear() noexcept
Definition qpointer.h:87
T * data() const noexcept
Definition qpointer.h:73
\inmodule QtCore\reentrant
Definition qrect.h:484
\inmodule QtCore\reentrant
Definition qrect.h:30
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
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]