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
qwaylandinputmethodeventbuilder.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5
6#include <QBrush>
7#include <QGuiApplication>
8#include <QInputMethod>
9#include <QPalette>
10#include <QTextCharFormat>
11
12#ifdef QT_BUILD_WAYLANDCOMPOSITOR_LIB
13#include <QtWaylandCompositor/private/qwayland-server-text-input-unstable-v2.h>
14#include <QtWaylandCompositor/private/qwayland-server-text-input-unstable-v3.h>
15#else
16#include <QtWaylandClient/private/qwayland-text-input-unstable-v2.h>
17#include <QtWaylandClient/private/qwayland-text-input-unstable-v3.h>
18#endif
19
21
25
27{
28 m_anchor = 0;
29 m_cursor = 0;
30 m_deleteBefore = 0;
31 m_deleteAfter = 0;
32 m_preeditCursor = 0;
33 m_preeditStyles.clear();
34}
35
37{
38 m_cursor = index;
39 m_anchor = anchor;
40}
41
42void QWaylandInputMethodEventBuilder::setDeleteSurroundingText(uint32_t beforeLength, uint32_t afterLength)
43{
44 m_deleteBefore = beforeLength;
45 m_deleteAfter = afterLength;
46}
47
48void QWaylandInputMethodEventBuilder::addPreeditStyling(uint32_t index, uint32_t length, uint32_t style)
49{
51
52 switch (style) {
53 case ZWP_TEXT_INPUT_V2_PREEDIT_STYLE_NONE:
54 break;
55 case ZWP_TEXT_INPUT_V2_PREEDIT_STYLE_DEFAULT:
56 case ZWP_TEXT_INPUT_V2_PREEDIT_STYLE_UNDERLINE:
60 break;
61 case ZWP_TEXT_INPUT_V2_PREEDIT_STYLE_ACTIVE:
62 case ZWP_TEXT_INPUT_V2_PREEDIT_STYLE_INACTIVE:
63 format.setFontWeight(QFont::Bold);
64 format.setFontUnderline(true);
67 break;
68 case ZWP_TEXT_INPUT_V2_PREEDIT_STYLE_HIGHLIGHT:
69 case ZWP_TEXT_INPUT_V2_PREEDIT_STYLE_SELECTION:
70 {
71 format.setFontUnderline(true);
73 QPalette palette = qApp->palette();
77 }
78 break;
79 case ZWP_TEXT_INPUT_V2_PREEDIT_STYLE_INCORRECT:
80 format.setFontUnderline(true);
81 format.setUnderlineStyle(QTextCharFormat::WaveUnderline);
82 format.setUnderlineColor(QColor(Qt::red));
84 break;
85 default:
86 break;
87 }
88}
89
91{
92 m_preeditCursor = index;
93}
94
96{
97 QList<QInputMethodEvent::Attribute> attributes;
98
99 const QPair<int, int> replacement = replacementForDeleteSurrounding();
100
101 if (m_cursor != 0 || m_anchor != 0) {
104 const int anchor = QInputMethod::queryFocusObject(Qt::ImAnchorPosition, QVariant()).toInt();
105 const int absoluteCursor = QInputMethod::queryFocusObject(Qt::ImAbsolutePosition, QVariant()).toInt();
106
107 const int absoluteOffset = absoluteCursor - cursor;
108
109 const int cursorAfterCommit = qMin(anchor, cursor) + replacement.first + text.size();
110 surrounding.replace(qMin(anchor, cursor) + replacement.first,
111 qAbs(anchor - cursor) + replacement.second, text);
112
114 indexFromWayland(surrounding, m_cursor, cursorAfterCommit) + absoluteOffset,
115 indexFromWayland(surrounding, m_anchor, cursorAfterCommit) + absoluteOffset,
116 QVariant()));
117 }
118
119 QInputMethodEvent *event = new QInputMethodEvent(QString(), attributes);
120 event->setCommitString(text, replacement.first, replacement.second);
121
122 return event;
123}
124
126{
127 QList<QInputMethodEvent::Attribute> attributes;
128
129 if (m_preeditCursor < 0) {
131 } else {
132 attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, indexFromWayland(text, m_preeditCursor), 1, QVariant()));
133 }
134
135 for (const QInputMethodEvent::Attribute &attr : std::as_const(m_preeditStyles)) {
136 int start = indexFromWayland(text, attr.start);
137 int length = indexFromWayland(text, attr.start + attr.length) - start;
138 attributes.append(QInputMethodEvent::Attribute(attr.type, start, length, attr.value));
139 }
140
141 QInputMethodEvent *event = new QInputMethodEvent(text, attributes);
142
143 const QPair<int, int> replacement = replacementForDeleteSurrounding();
144 event->setCommitString(QString(), replacement.first, replacement.second);
145
146 return event;
147}
148
149QPair<int, int> QWaylandInputMethodEventBuilder::replacementForDeleteSurrounding()
150{
151 if (m_deleteBefore == 0 && m_deleteAfter == 0)
152 return QPair<int, int>(0, 0);
153
154 const QString &surrounding = QInputMethod::queryFocusObject(Qt::ImSurroundingText, QVariant()).toString();
156 const int anchor = QInputMethod::queryFocusObject(Qt::ImAnchorPosition, QVariant()).toInt();
157
158 const int selectionStart = qMin(cursor, anchor);
159 const int selectionEnd = qMax(cursor, anchor);
160
161 const int deleteBefore = selectionStart - indexFromWayland(surrounding, -m_deleteBefore, selectionStart);
162 const int deleteAfter = indexFromWayland(surrounding, m_deleteAfter, selectionEnd) - selectionEnd;
163
164 return QPair<int, int>(-deleteBefore, deleteBefore + deleteAfter);
165}
166
168{
169 uint32_t hint = ZWP_TEXT_INPUT_V2_CONTENT_HINT_NONE;
170 uint32_t purpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_NORMAL;
171
172 if (hints & Qt::ImhHiddenText)
173 hint |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_HIDDEN_TEXT;
174 if (hints & Qt::ImhSensitiveData)
175 hint |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_SENSITIVE_DATA;
176 if ((hints & Qt::ImhNoAutoUppercase) == 0)
177 hint |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_AUTO_CAPITALIZATION;
178 if (hints & Qt::ImhPreferNumbers) {
179 // Nothing yet
180 }
181 if (hints & Qt::ImhPreferUppercase)
182 hint |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_UPPERCASE;
183 if (hints & Qt::ImhPreferLowercase)
184 hint |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_LOWERCASE;
185 if ((hints & Qt::ImhNoPredictiveText) == 0) {
186 hint |= (ZWP_TEXT_INPUT_V2_CONTENT_HINT_AUTO_COMPLETION
187 | ZWP_TEXT_INPUT_V2_CONTENT_HINT_AUTO_CORRECTION);
188 }
189
190 if ((hints & Qt::ImhDate) && (hints & Qt::ImhTime) == 0)
191 purpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_DATE;
192 else if ((hints & Qt::ImhDate) && (hints & Qt::ImhTime))
193 purpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_DATETIME;
194 else if ((hints & Qt::ImhDate) == 0 && (hints & Qt::ImhTime))
195 purpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_TIME;
196
197 if (hints & Qt::ImhPreferLatin)
198 hint |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_LATIN;
199 if (hints & Qt::ImhMultiLine)
200 hint |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_MULTILINE;
201 if (hints & Qt::ImhDigitsOnly)
202 purpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_DIGITS;
203 if (hints & Qt::ImhFormattedNumbersOnly)
204 purpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_NUMBER;
205 if (hints & Qt::ImhUppercaseOnly)
206 hint |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_UPPERCASE;
207 if (hints & Qt::ImhLowercaseOnly)
208 hint |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_LOWERCASE;
210 purpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_PHONE;
211 if (hints & Qt::ImhEmailCharactersOnly)
212 purpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_EMAIL;
213 if (hints & Qt::ImhUrlCharactersOnly)
214 purpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_URL;
215 if (hints & Qt::ImhLatinOnly)
216 hint |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_LATIN;
217
219}
220
222{
223 uint32_t hint = ZWP_TEXT_INPUT_V3_CONTENT_HINT_NONE;
224 uint32_t purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NORMAL;
225
226 if (hints & Qt::ImhHiddenText)
227 hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_HIDDEN_TEXT;
228 if (hints & Qt::ImhSensitiveData)
229 hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_SENSITIVE_DATA;
230 if ((hints & Qt::ImhNoAutoUppercase) == 0)
231 hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_AUTO_CAPITALIZATION;
232 if (hints & Qt::ImhPreferNumbers) {
233 // Nothing yet
234 }
235 if (hints & Qt::ImhPreferUppercase)
236 hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_UPPERCASE;
237 if (hints & Qt::ImhPreferLowercase)
238 hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_LOWERCASE;
239 if ((hints & Qt::ImhNoPredictiveText) == 0) {
240 hint |= (ZWP_TEXT_INPUT_V3_CONTENT_HINT_COMPLETION
241 | ZWP_TEXT_INPUT_V3_CONTENT_HINT_SPELLCHECK);
242 }
243
244 if ((hints & Qt::ImhDate) && (hints & Qt::ImhTime) == 0)
245 purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_DATE;
246 else if ((hints & Qt::ImhDate) && (hints & Qt::ImhTime))
247 purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_DATETIME;
248 else if ((hints & Qt::ImhDate) == 0 && (hints & Qt::ImhTime))
249 purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_TIME;
250 if (hints & Qt::ImhPreferLatin)
251 hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_LATIN;
252 if (hints & Qt::ImhMultiLine)
253 hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_MULTILINE;
254 if (hints & Qt::ImhDigitsOnly)
255 purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_DIGITS;
256 if (hints & Qt::ImhFormattedNumbersOnly)
257 purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NUMBER;
258 if (hints & Qt::ImhUppercaseOnly)
259 hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_UPPERCASE;
260 if (hints & Qt::ImhLowercaseOnly)
261 hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_LOWERCASE;
263 purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_PHONE;
264 if (hints & Qt::ImhEmailCharactersOnly)
265 purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_EMAIL;
266 if (hints & Qt::ImhUrlCharactersOnly)
267 purpose = ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_URL;
268 if (hints & Qt::ImhLatinOnly)
269 hint |= ZWP_TEXT_INPUT_V3_CONTENT_HINT_LATIN;
270
272}
273
275{
276 if (length == 0)
277 return base;
278
279 if (length < 0) {
280 const QByteArray &utf8 = QStringView{text}.left(base).toUtf8();
281 return QString::fromUtf8(utf8.left(qMax(utf8.size() + length, 0))).size();
282 } else {
283 const QByteArray &utf8 = QStringView{text}.mid(base).toUtf8();
284 return QString::fromUtf8(utf8.left(length)).size() + base;
285 }
286}
287
289{
290 if (length == 0)
291 return base;
292
293 if (length < 0) {
294 const QByteArray &utf8 = QStringView{text}.left(base).toUtf8();
295 const int len = utf8.size();
296 const int start = len + length;
297 if (start <= 0)
298 return 0;
299
300 for (int i = 0; i < 4; i++) {
301 if (start + i >= len)
302 return base;
303
304 const unsigned char ch = utf8.at(start + i);
305 // check if current character is a utf8's initial character.
306 if (ch < 0x80 || ch > 0xbf)
307 return QString::fromUtf8(utf8.left(start + i)).size();
308 }
309 } else {
310 const QByteArray &utf8 = QStringView{text}.mid(base).toUtf8();
311 const int len = utf8.size();
312 const int start = length;
313 if (start >= len)
314 return base + QString::fromUtf8(utf8).size();
315
316 for (int i = 0; i < 4; i++) {
317 const unsigned char ch = utf8.at(start - i);
318 // check if current character is a utf8's initial character.
319 if (ch < 0x80 || ch > 0xbf)
320 return base + QString::fromUtf8(utf8.left(start - i)).size();
321 }
322 }
323 return -1;
324}
325
330
332
\inmodule QtGui
Definition qbrush.h:30
\inmodule QtCore
Definition qbytearray.h:57
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:494
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
@ Bold
Definition qfont.h:70
The QInputMethodEvent class provides parameters for input method events.
Definition qevent.h:625
static QVariant queryFocusObject(Qt::InputMethodQuery query, const QVariant &argument)
Send query to the current focus object with parameters argument and return the result.
void append(parameter_type t)
Definition qlist.h:458
void clear()
Definition qlist.h:434
The QPalette class contains color groups for each widget state.
Definition qpalette.h:19
@ HighlightedText
Definition qpalette.h:53
@ Highlight
Definition qpalette.h:53
\inmodule QtCore
Definition qstringview.h:78
\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
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:6018
QByteArray toUtf8() const &
Definition qstring.h:634
qsizetype length() const noexcept
Returns the number of characters in this string.
Definition qstring.h:191
void setFontUnderline(bool underline)
If underline is true, sets the text format's font to be underlined; otherwise it is displayed non-und...
\inmodule QtCore
Definition qvariant.h:65
static int indexFromWayland(const QString &text, int length, int base=0)
void addPreeditStyling(uint32_t index, uint32_t length, uint32_t style)
QInputMethodEvent * buildCommit(const QString &text)
QInputMethodEvent * buildPreedit(const QString &text)
void setDeleteSurroundingText(uint32_t beforeLength, uint32_t afterLength)
void setCursorPosition(int32_t index, int32_t anchor)
static int trimmedIndexFromWayland(const QString &text, int length, int base=0)
static int indexToWayland(const QString &text, int length, int base=0)
QString text
QCursor cursor
Combined button and popup list for selecting options.
@ ImSurroundingText
@ ImCursorPosition
@ ImAbsolutePosition
@ ImAnchorPosition
@ ImhPreferUppercase
@ ImhPreferLatin
@ ImhUrlCharactersOnly
@ ImhPreferLowercase
@ ImhTime
@ ImhFormattedNumbersOnly
@ ImhMultiLine
@ ImhLatinOnly
@ ImhUppercaseOnly
@ ImhNoPredictiveText
@ ImhDigitsOnly
@ ImhSensitiveData
@ ImhLowercaseOnly
@ ImhEmailCharactersOnly
@ ImhHiddenText
@ ImhNoAutoUppercase
@ ImhDialableCharactersOnly
@ ImhDate
@ ImhPreferNumbers
@ red
Definition qnamespace.h:35
#define qApp
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
GLuint index
[2]
GLenum GLuint GLenum GLsizei length
GLuint start
GLint GLsizei GLsizei GLenum format
struct _cl_event * event
GLenum GLsizei len
static const uint base
Definition qurlidna.cpp:20
static QWaylandInputMethodContentType convert(Qt::InputMethodHints hints)
static QWaylandInputMethodContentType convertV3(Qt::InputMethodHints hints)