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