Coverage Report

Created: 2025-07-16 07:53

/src/qtbase/src/gui/kernel/qinputmethod.cpp
Line
Count
Source (jump to first uncovered line)
1
// Copyright (C) 2016 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
4
#include <qinputmethod.h>
5
#include <private/qinputmethod_p.h>
6
#include <qguiapplication.h>
7
#include <qpa/qplatforminputcontext_p.h>
8
9
#include <QDebug>
10
11
QT_BEGIN_NAMESPACE
12
13
/*!
14
    \internal
15
*/
16
QInputMethod::QInputMethod()
17
0
    : QObject(*new QInputMethodPrivate)
18
0
{
19
0
}
20
21
/*!
22
    \internal
23
*/
24
QInputMethod::~QInputMethod()
25
0
{
26
0
}
27
28
/*!
29
    \class QInputMethod
30
    \brief The QInputMethod class provides access to the active text input method.
31
    \inmodule QtGui
32
33
    QInputMethod is used by the text editors for integrating to the platform text input
34
    methods and more commonly by application views for querying various text input method-related
35
    information like virtual keyboard visibility and keyboard dimensions.
36
37
    Qt Quick also provides access to QInputMethod in QML through \l{QmlGlobalQtObject}{Qt global object}
38
    as \c Qt.inputMethod property.
39
*/
40
41
/*!
42
    Returns the transformation from input item coordinates to the window coordinates.
43
*/
44
QTransform QInputMethod::inputItemTransform() const
45
0
{
46
0
    Q_D(const QInputMethod);
47
0
    return d->inputItemTransform;
48
0
}
49
50
/*!
51
    Sets the transformation from input item coordinates to window coordinates to be \a transform.
52
    Item transform needs to be updated by the focused window like QQuickCanvas whenever
53
    item is moved inside the scene.
54
*/
55
void QInputMethod::setInputItemTransform(const QTransform &transform)
56
0
{
57
0
    Q_D(QInputMethod);
58
0
    if (d->inputItemTransform == transform)
59
0
        return;
60
61
0
    d->inputItemTransform = transform;
62
0
    emit cursorRectangleChanged();
63
0
    emit anchorRectangleChanged();
64
0
}
65
66
67
/*!
68
    \since 5.1
69
70
    Returns the input item's geometry in input item coordinates.
71
72
    \sa setInputItemRectangle()
73
*/
74
QRectF QInputMethod::inputItemRectangle() const
75
0
{
76
0
    Q_D(const QInputMethod);
77
0
    return d->inputRectangle;
78
0
}
79
80
/*!
81
    \since 5.1
82
83
    Sets the input item's geometry to be \a rect, in input item coordinates.
84
    This needs to be updated by the focused window like QQuickCanvas whenever
85
    item is moved inside the scene, or focus is changed.
86
*/
87
void QInputMethod::setInputItemRectangle(const QRectF &rect)
88
0
{
89
0
    Q_D(QInputMethod);
90
0
    d->inputRectangle = rect;
91
0
}
92
93
static QRectF inputMethodQueryRectangle_helper(Qt::InputMethodQuery imquery, const QTransform &xform)
94
0
{
95
0
    QRectF r;
96
0
    if (QObject *focusObject = qGuiApp->focusObject()) {
97
0
        QInputMethodQueryEvent query(imquery);
98
0
        QGuiApplication::sendEvent(focusObject, &query);
99
0
        r = query.value(imquery).toRectF();
100
0
        if (r.isValid())
101
0
            r = xform.mapRect(r);
102
0
    }
103
0
    return r;
104
0
}
105
106
/*!
107
    \property QInputMethod::cursorRectangle
108
    \brief Input item's cursor rectangle in window coordinates.
109
110
    Cursor rectangle is often used by various text editing controls
111
    like text prediction popups for following the text being typed.
112
*/
113
QRectF QInputMethod::cursorRectangle() const
114
0
{
115
0
    Q_D(const QInputMethod);
116
0
    return inputMethodQueryRectangle_helper(Qt::ImCursorRectangle, d->inputItemTransform);
117
0
}
118
119
/*!
120
    \property QInputMethod::anchorRectangle
121
    \brief Input item's anchor rectangle in window coordinates.
122
123
    Anchor rectangle is often used by various text editing controls
124
    like text prediction popups for following the text selection.
125
*/
126
QRectF QInputMethod::anchorRectangle() const
127
0
{
128
0
    Q_D(const QInputMethod);
129
0
    return inputMethodQueryRectangle_helper(Qt::ImAnchorRectangle, d->inputItemTransform);
130
0
}
131
132
/*!
133
    \property QInputMethod::keyboardRectangle
134
    \brief Virtual keyboard's geometry in window coordinates.
135
136
    This might be an empty rectangle if it is not possible to know the geometry
137
    of the keyboard. This is the case for a floating keyboard on android.
138
*/
139
QRectF QInputMethod::keyboardRectangle() const
140
0
{
141
0
    Q_D(const QInputMethod);
142
0
    QPlatformInputContext *ic = d->platformInputContext();
143
0
    if (ic)
144
0
        return ic->keyboardRect();
145
0
    return QRectF();
146
0
}
147
148
/*!
149
    \property QInputMethod::inputItemClipRectangle
150
    \brief Input item's clipped rectangle in window coordinates.
151
152
    The clipped input rectangle is often used by various input methods to determine
153
    how much screen real estate is available for the input method (e.g. Virtual Keyboard).
154
*/
155
QRectF QInputMethod::inputItemClipRectangle() const
156
0
{
157
0
    Q_D(const QInputMethod);
158
0
    return inputMethodQueryRectangle_helper(Qt::ImInputItemClipRectangle, d->inputItemTransform);
159
0
}
160
/*!
161
    Requests virtual keyboard to open. If the platform
162
    doesn't provide virtual keyboard the visibility
163
    remains false.
164
165
    Normally applications should not need to call this
166
    function, keyboard should automatically open when
167
    the text editor gains focus.
168
*/
169
void QInputMethod::show()
170
0
{
171
0
    Q_D(QInputMethod);
172
0
    QPlatformInputContext *ic = d->platformInputContext();
173
0
    if (ic)
174
0
        ic->showInputPanel();
175
0
}
176
177
/*!
178
    Requests virtual keyboard to close.
179
180
    Normally applications should not need to call this function,
181
    keyboard should automatically close when the text editor loses
182
    focus, for example when the parent view is closed.
183
*/
184
void QInputMethod::hide()
185
0
{
186
0
    Q_D(QInputMethod);
187
0
    QPlatformInputContext *ic = d->platformInputContext();
188
0
    if (ic)
189
0
        ic->hideInputPanel();
190
0
}
191
192
/*!
193
    \property QInputMethod::visible
194
    \brief Virtual keyboard's visibility on the screen
195
196
    Input method visibility remains false for devices
197
    with no virtual keyboards.
198
199
    \sa show(), hide()
200
*/
201
bool QInputMethod::isVisible() const
202
0
{
203
0
    Q_D(const QInputMethod);
204
0
    QPlatformInputContext *ic = d->platformInputContext();
205
0
    if (ic)
206
0
        return ic->isInputPanelVisible();
207
0
    return false;
208
0
}
209
210
/*!
211
    Controls the keyboard visibility. Equivalent
212
    to calling show() (if \a visible is \c true)
213
    or hide() (if \a visible is \c false).
214
215
    \sa show(), hide()
216
*/
217
void QInputMethod::setVisible(bool visible)
218
0
{
219
0
    visible ? show() : hide();
220
0
}
221
222
/*!
223
    \property QInputMethod::animating
224
    \brief True when the virtual keyboard is being opened or closed.
225
226
    Animating is false when keyboard is fully open or closed.
227
    When \c animating is \c true and \c visibility is \c true keyboard
228
    is being opened. When \c animating is \c true and \c visibility is
229
    false keyboard is being closed.
230
*/
231
232
bool QInputMethod::isAnimating() const
233
0
{
234
0
    Q_D(const QInputMethod);
235
0
    QPlatformInputContext *ic = d->platformInputContext();
236
0
    if (ic)
237
0
        return ic->isAnimating();
238
0
    return false;
239
0
}
240
241
/*!
242
    \property QInputMethod::locale
243
    \brief Current input locale.
244
*/
245
QLocale QInputMethod::locale() const
246
0
{
247
0
    Q_D(const QInputMethod);
248
0
    QPlatformInputContext *ic = d->platformInputContext();
249
0
    if (ic)
250
0
        return ic->locale();
251
0
    return QLocale::c();
252
0
}
253
254
/*!
255
    \property QInputMethod::inputDirection
256
    \brief Current input direction.
257
*/
258
Qt::LayoutDirection QInputMethod::inputDirection() const
259
0
{
260
0
    Q_D(const QInputMethod);
261
0
    QPlatformInputContext *ic = d->platformInputContext();
262
0
    if (ic)
263
0
        return ic->inputDirection();
264
0
    return Qt::LeftToRight;
265
0
}
266
267
/*!
268
    Called by the input item to inform the platform input methods when there has been
269
    state changes in editor's input method query attributes. When calling the function
270
    \a queries parameter has to be used to tell what has changes, which input method
271
    can use to make queries for attributes it's interested with QInputMethodQueryEvent.
272
273
    In particular calling update whenever the cursor position changes is important as
274
    that often causes other query attributes like surrounding text and text selection
275
    to change as well. The attributes that often change together with cursor position
276
    have been grouped in Qt::ImQueryInput value for convenience.
277
*/
278
void QInputMethod::update(Qt::InputMethodQueries queries)
279
0
{
280
0
    Q_D(QInputMethod);
281
282
0
    if (queries & Qt::ImEnabled) {
283
0
        QObject *focus = qApp->focusObject();
284
0
        bool enabled = d->objectAcceptsInputMethod(focus);
285
0
        QPlatformInputContextPrivate::setInputMethodAccepted(enabled);
286
0
    }
287
288
0
    QPlatformInputContext *ic = d->platformInputContext();
289
0
    if (ic)
290
0
        ic->update(queries);
291
292
0
    if (queries & Qt::ImCursorRectangle)
293
0
        emit cursorRectangleChanged();
294
295
0
    if (queries & (Qt::ImAnchorRectangle))
296
0
        emit anchorRectangleChanged();
297
298
0
    if (queries & (Qt::ImInputItemClipRectangle))
299
0
        emit inputItemClipRectangleChanged();
300
0
}
301
302
/*!
303
    Resets the input method state. For example, a text editor normally calls
304
    this method before inserting a text to make widget ready to accept a text.
305
306
    Input method resets automatically when the focused editor changes.
307
*/
308
void QInputMethod::reset()
309
0
{
310
0
    Q_D(QInputMethod);
311
0
    QPlatformInputContext *ic = d->platformInputContext();
312
0
    if (ic)
313
0
        ic->reset();
314
0
}
315
316
/*!
317
    Commits the word user is currently composing to the editor. The function is
318
    mostly needed by the input methods with text prediction features and by the
319
    methods where the script used for typing characters is different from the
320
    script that actually gets appended to the editor. Any kind of action that
321
    interrupts the text composing needs to flush the composing state by calling the
322
    commit() function, for example when the cursor is moved elsewhere.
323
*/
324
void QInputMethod::commit()
325
0
{
326
0
    Q_D(QInputMethod);
327
0
    QPlatformInputContext *ic = d->platformInputContext();
328
0
    if (ic)
329
0
        ic->commit();
330
0
}
331
332
/*!
333
    \enum QInputMethod::Action
334
335
    Indicates the kind of action performed by the user.
336
337
    \value Click        A normal click/tap
338
    \value ContextMenu  A context menu click/tap (e.g. right-button or tap-and-hold)
339
340
    \sa invokeAction()
341
*/
342
343
/*!
344
    Called by the input item when the word currently being composed is tapped by
345
    the user, as indicated by the action \a a and the given \a cursorPosition.
346
    Input methods often use this information to offer more word suggestions to the user.
347
*/
348
void QInputMethod::invokeAction(Action a, int cursorPosition)
349
0
{
350
0
    Q_D(QInputMethod);
351
0
    QPlatformInputContext *ic = d->platformInputContext();
352
0
    if (ic)
353
0
        ic->invokeAction(a, cursorPosition);
354
0
}
355
356
static inline bool platformSupportsHiddenText()
357
0
{
358
0
    const QPlatformInputContext *inputContext = QGuiApplicationPrivate::platformIntegration()->inputContext();
359
0
    return inputContext && inputContext->hasCapability(QPlatformInputContext::HiddenTextCapability);
360
0
}
361
362
bool QInputMethodPrivate::objectAcceptsInputMethod(QObject *object)
363
0
{
364
0
    bool enabled = false;
365
0
    if (object) {
366
        // If the platform does not support hidden text, query the hints
367
        // in addition and disable in case of ImhHiddenText.
368
0
        static const bool supportsHiddenText = platformSupportsHiddenText();
369
0
        QInputMethodQueryEvent query(supportsHiddenText
370
0
                                     ? Qt::InputMethodQueries(Qt::ImEnabled)
371
0
                                     : Qt::InputMethodQueries(Qt::ImEnabled | Qt::ImHints));
372
0
        QGuiApplication::sendEvent(object, &query);
373
0
        enabled = query.value(Qt::ImEnabled).toBool();
374
0
        if (enabled && !supportsHiddenText
375
0
            && Qt::InputMethodHints(query.value(Qt::ImHints).toInt()).testFlag(Qt::ImhHiddenText)) {
376
0
            enabled = false;
377
0
        }
378
0
    }
379
0
    return enabled;
380
0
}
381
382
/*!
383
  Send \a query to the current focus object with parameters \a argument and return the result.
384
 */
385
QVariant QInputMethod::queryFocusObject(Qt::InputMethodQuery query, const QVariant &argument)
386
0
{
387
0
    QVariant retval;
388
0
    QObject *focusObject = qGuiApp->focusObject();
389
0
    if (!focusObject)
390
0
        return retval;
391
392
0
    static const char *signature = "inputMethodQuery(Qt::InputMethodQuery,QVariant)";
393
0
    const bool newMethodSupported = focusObject->metaObject()->indexOfMethod(signature) != -1;
394
0
    if (newMethodSupported) {
395
0
        const bool ok = QMetaObject::invokeMethod(focusObject, "inputMethodQuery",
396
0
                                                        Qt::DirectConnection,
397
0
                                                        Q_RETURN_ARG(QVariant, retval),
398
0
                                                        Q_ARG(Qt::InputMethodQuery, query),
399
0
                                                        Q_ARG(QVariant, argument));
400
0
        Q_ASSERT(ok);
401
0
        if (retval.isValid())
402
0
            return retval;
403
404
        // If the new API didn't have an answer to the query, we fall
405
        // back to use the old event-based API.
406
0
    }
407
408
0
    QInputMethodQueryEvent queryEvent(query);
409
0
    QCoreApplication::sendEvent(focusObject, &queryEvent);
410
0
    return queryEvent.value(query);
411
0
}
412
413
QT_END_NAMESPACE
414
415
#include "moc_qinputmethod.cpp"