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 Qt Virtual Keyboard module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:GPL$
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 General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
19 ** General Public License version 3 or (at your option) any later version
20 ** approved by the KDE Free Qt Foundation. The licenses are as published by
21 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
22 ** included in the packaging of this file. Please review the following
23 ** information to ensure the GNU General Public License requirements will
24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25 **
26 ** $QT_END_LICENSE$
27 **
28 ****************************************************************************/
29 
30 #include <QtVirtualKeyboard/qvirtualkeyboardinputcontext.h>
31 #include <QtVirtualKeyboard/private/qvirtualkeyboardinputcontext_p.h>
32 #include <QtVirtualKeyboard/private/shifthandler_p.h>
33 #include <QtVirtualKeyboard/private/platforminputcontext_p.h>
34 #include <QtVirtualKeyboard/private/virtualkeyboarddebug_p.h>
35 
36 #include <QTextFormat>
37 #include <QGuiApplication>
38 
39 QT_BEGIN_NAMESPACE
40 using namespace QtVirtualKeyboard;
41 
42 /*!
43     \qmltype InputContext
44     \instantiates QVirtualKeyboardInputContext
45     \inqmlmodule QtQuick.VirtualKeyboard
46     \ingroup qtvirtualkeyboard-qml
47     \brief Provides access to an input context.
48 
49     The InputContext can be accessed as singleton instance.
50 */
51 
52 /*!
53     \class QVirtualKeyboardInputContext
54     \inmodule QtVirtualKeyboard
55     \brief Provides access to an input context.
56 */
57 
58 /*!
59     \internal
60     Constructs an input context with \a parent as the platform input
61     context.
62 */
QVirtualKeyboardInputContext(QObject * parent)63 QVirtualKeyboardInputContext::QVirtualKeyboardInputContext(QObject *parent) :
64     QObject(parent),
65     d_ptr(new QVirtualKeyboardInputContextPrivate(this))
66 {
67     Q_D(QVirtualKeyboardInputContext);
68     d->init();
69     QObject::connect(d->_shiftHandler, &ShiftHandler::shiftActiveChanged, this, &QVirtualKeyboardInputContext::shiftActiveChanged);
70     QObject::connect(d->_shiftHandler, &ShiftHandler::capsLockActiveChanged, this, &QVirtualKeyboardInputContext::capsLockActiveChanged);
71     QObject::connect(d->_shiftHandler, &ShiftHandler::uppercaseChanged, this, &QVirtualKeyboardInputContext::uppercaseChanged);
72     QObject::connect(d, &QVirtualKeyboardInputContextPrivate::localeChanged, this, &QVirtualKeyboardInputContext::localeChanged);
73     QObject::connect(d, &QVirtualKeyboardInputContextPrivate::inputItemChanged, this, &QVirtualKeyboardInputContext::inputItemChanged);
74 }
75 
76 /*!
77     \internal
78     Destroys the input context and frees all allocated resources.
79 */
~QVirtualKeyboardInputContext()80 QVirtualKeyboardInputContext::~QVirtualKeyboardInputContext()
81 {
82 }
83 
isShiftActive() const84 bool QVirtualKeyboardInputContext::isShiftActive() const
85 {
86     Q_D(const QVirtualKeyboardInputContext);
87     return d->_shiftHandler->isShiftActive();
88 }
89 
isCapsLockActive() const90 bool QVirtualKeyboardInputContext::isCapsLockActive() const
91 {
92     Q_D(const QVirtualKeyboardInputContext);
93     return d->_shiftHandler->isCapsLockActive();
94 }
95 
isUppercase() const96 bool QVirtualKeyboardInputContext::isUppercase() const
97 {
98     Q_D(const QVirtualKeyboardInputContext);
99     return d->_shiftHandler->isUppercase();
100 }
101 
anchorPosition() const102 int QVirtualKeyboardInputContext::anchorPosition() const
103 {
104     Q_D(const QVirtualKeyboardInputContext);
105     return d->anchorPosition;
106 }
107 
cursorPosition() const108 int QVirtualKeyboardInputContext::cursorPosition() const
109 {
110     Q_D(const QVirtualKeyboardInputContext);
111     return d->cursorPosition;
112 }
113 
inputMethodHints() const114 Qt::InputMethodHints QVirtualKeyboardInputContext::inputMethodHints() const
115 {
116     Q_D(const QVirtualKeyboardInputContext);
117     return d->inputMethodHints;
118 }
119 
preeditText() const120 QString QVirtualKeyboardInputContext::preeditText() const
121 {
122     Q_D(const QVirtualKeyboardInputContext);
123     return d->preeditText;
124 }
125 
setPreeditText(const QString & text,QList<QInputMethodEvent::Attribute> attributes,int replaceFrom,int replaceLength)126 void QVirtualKeyboardInputContext::setPreeditText(const QString &text, QList<QInputMethodEvent::Attribute> attributes, int replaceFrom, int replaceLength)
127 {
128     Q_D(QVirtualKeyboardInputContext);
129     // Add default attributes
130     if (!text.isEmpty()) {
131         if (!d->testAttribute(attributes, QInputMethodEvent::TextFormat)) {
132             QTextCharFormat textFormat;
133             textFormat.setUnderlineStyle(QTextCharFormat::SingleUnderline);
134             attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 0, text.length(), textFormat));
135         }
136     } else if (d->_forceCursorPosition != -1) {
137         d->addSelectionAttribute(attributes);
138     }
139 
140     d->sendPreedit(text, attributes, replaceFrom, replaceLength);
141 }
142 
preeditTextAttributes() const143 QList<QInputMethodEvent::Attribute> QVirtualKeyboardInputContext::preeditTextAttributes() const
144 {
145     Q_D(const QVirtualKeyboardInputContext);
146     return d->preeditTextAttributes;
147 }
148 
surroundingText() const149 QString QVirtualKeyboardInputContext::surroundingText() const
150 {
151     Q_D(const QVirtualKeyboardInputContext);
152     return d->surroundingText;
153 }
154 
selectedText() const155 QString QVirtualKeyboardInputContext::selectedText() const
156 {
157     Q_D(const QVirtualKeyboardInputContext);
158     return d->selectedText;
159 }
160 
anchorRectangle() const161 QRectF QVirtualKeyboardInputContext::anchorRectangle() const
162 {
163     Q_D(const QVirtualKeyboardInputContext);
164     return d->anchorRectangle;
165 }
166 
cursorRectangle() const167 QRectF QVirtualKeyboardInputContext::cursorRectangle() const
168 {
169     Q_D(const QVirtualKeyboardInputContext);
170     return d->cursorRectangle;
171 }
172 
isAnimating() const173 bool QVirtualKeyboardInputContext::isAnimating() const
174 {
175     Q_D(const QVirtualKeyboardInputContext);
176     return d->animating;
177 }
178 
setAnimating(bool animating)179 void QVirtualKeyboardInputContext::setAnimating(bool animating)
180 {
181     Q_D(QVirtualKeyboardInputContext);
182     if (d->animating != animating) {
183         VIRTUALKEYBOARD_DEBUG() << "QVirtualKeyboardInputContext::setAnimating():" << animating;
184         d->animating = animating;
185         emit animatingChanged();
186         d->platformInputContext->emitAnimatingChanged();
187     }
188 }
189 
locale() const190 QString QVirtualKeyboardInputContext::locale() const
191 {
192     Q_D(const QVirtualKeyboardInputContext);
193     return d->locale();
194 }
195 
inputItem() const196 QObject *QVirtualKeyboardInputContext::inputItem() const
197 {
198     Q_D(const QVirtualKeyboardInputContext);
199     return d->inputItem();
200 }
201 
inputEngine() const202 QVirtualKeyboardInputEngine *QVirtualKeyboardInputContext::inputEngine() const
203 {
204     Q_D(const QVirtualKeyboardInputContext);
205     return d->inputEngine;
206 }
207 
208 /*!
209     \qmlmethod void InputContext::sendKeyClick(int key, string text, int modifiers = 0)
210 
211     Sends a key click event with the given \a key, \a text and \e modifiers to
212     the input item that currently has focus.
213 */
214 /*!
215     Sends a key click event with the given \a key, \a text and \a modifiers to
216     the input item that currently has focus.
217 */
sendKeyClick(int key,const QString & text,int modifiers)218 void QVirtualKeyboardInputContext::sendKeyClick(int key, const QString &text, int modifiers)
219 {
220     Q_D(QVirtualKeyboardInputContext);
221     if ((d->_focus && d->platformInputContext) || QT_VIRTUALKEYBOARD_FORCE_EVENTS_WITHOUT_FOCUS) {
222         QKeyEvent pressEvent(QEvent::KeyPress, key, Qt::KeyboardModifiers(modifiers), text);
223         QKeyEvent releaseEvent(QEvent::KeyRelease, key, Qt::KeyboardModifiers(modifiers), text);
224         VIRTUALKEYBOARD_DEBUG().nospace() << "InputContext::sendKeyClick()"
225 #ifdef SENSITIVE_DEBUG
226             << ": " << key
227 #endif
228         ;
229 
230 
231         d->setState(QVirtualKeyboardInputContextPrivate::State::KeyEvent);
232         d->platformInputContext->sendKeyEvent(&pressEvent);
233         d->platformInputContext->sendKeyEvent(&releaseEvent);
234         if (d->activeKeys.isEmpty())
235             d->clearState(QVirtualKeyboardInputContextPrivate::State::KeyEvent);
236     } else {
237         VIRTUALKEYBOARD_WARN() << "InputContext::sendKeyClick(): no focus to send key click"
238 #ifdef SENSITIVE_DEBUG
239             << key << text
240 #endif
241             << "- QGuiApplication::focusWindow() is:" << QGuiApplication::focusWindow();
242     }
243 }
244 
245 /*!
246     \qmlmethod void InputContext::commit()
247 
248     Commits the current pre-edit text.
249 */
250 /*!
251     \fn void QVirtualKeyboardInputContext::commit()
252 
253     Commits the current pre-edit text.
254 */
commit()255 void QVirtualKeyboardInputContext::commit()
256 {
257     Q_D(QVirtualKeyboardInputContext);
258     QString text = d->preeditText;
259     commit(text);
260 }
261 
262 /*!
263     \qmlmethod void InputContext::commit(string text, int replaceFrom = 0, int replaceLength = 0)
264 
265     Commits the final \a text to the input item and optionally
266     modifies the text relative to the start of the pre-edit text.
267     If \e replaceFrom is non-zero, the \a text replaces the
268     contents relative to \e replaceFrom with a length of
269     \e replaceLength.
270 */
271 /*!
272     Commits the final \a text to the input item and optionally
273     modifies the text relative to the start of the pre-edit text.
274     If \a replaceFrom is non-zero, the \a text replaces the
275     contents relative to \a replaceFrom with a length of
276     \a replaceLength.
277 */
commit(const QString & text,int replaceFrom,int replaceLength)278 void QVirtualKeyboardInputContext::commit(const QString &text, int replaceFrom, int replaceLength)
279 {
280     Q_D(QVirtualKeyboardInputContext);
281 
282     VIRTUALKEYBOARD_DEBUG() << "QVirtualKeyboardInputContext::commit()"
283 #ifdef SENSITIVE_DEBUG
284            << text << replaceFrom << replaceLength
285 #endif
286         ;
287     bool preeditChanged = !d->preeditText.isEmpty();
288 
289     if (d->platformInputContext) {
290         QList<QInputMethodEvent::Attribute> attributes;
291         d->addSelectionAttribute(attributes);
292         d->preeditText.clear();
293         d->preeditTextAttributes.clear();
294         QInputMethodEvent inputEvent(QString(), attributes);
295         inputEvent.setCommitString(text, replaceFrom, replaceLength);
296         d->sendInputMethodEvent(&inputEvent);
297     } else {
298         d->preeditText.clear();
299         d->preeditTextAttributes.clear();
300     }
301 
302     if (preeditChanged)
303         emit preeditTextChanged();
304 }
305 
306 /*!
307     \qmlmethod void InputContext::clear()
308 
309     Clears the pre-edit text.
310 */
311 /*!
312     \fn void QVirtualKeyboardInputContext::clear()
313 
314     Clears the pre-edit text.
315 */
clear()316 void QVirtualKeyboardInputContext::clear()
317 {
318     Q_D(QVirtualKeyboardInputContext);
319     bool preeditChanged = !d->preeditText.isEmpty();
320     d->preeditText.clear();
321     d->preeditTextAttributes.clear();
322 
323     if (d->platformInputContext) {
324         QList<QInputMethodEvent::Attribute> attributes;
325         d->addSelectionAttribute(attributes);
326         QInputMethodEvent event(QString(), attributes);
327         d->sendInputMethodEvent(&event);
328     }
329 
330     if (preeditChanged)
331         emit preeditTextChanged();
332 }
333 
334 /*!
335     \internal
336 */
setSelectionOnFocusObject(const QPointF & anchorPos,const QPointF & cursorPos)337 void QVirtualKeyboardInputContext::setSelectionOnFocusObject(const QPointF &anchorPos, const QPointF &cursorPos)
338 {
339     QPlatformInputContext::setSelectionOnFocusObject(anchorPos, cursorPos);
340 }
341 
342 /*!
343     \property QVirtualKeyboardInputContext::anchorRectIntersectsClipRect
344     \brief Holds \c true if the bounding rectangle of the selection anchor
345     intersects the exposed input item rectangle.
346 
347     \sa Qt::ImAnchorRectangle, Qt::ImInputItemClipRectangle
348 */
349 /*!
350     \qmlproperty bool InputContext::anchorRectIntersectsClipRect
351     \readonly
352     \brief Holds \c true if the bounding rectangle of the selection anchor
353     intersects the exposed input item rectangle.
354 
355     \sa Qt::ImAnchorRectangle, Qt::ImInputItemClipRectangle
356 */
anchorRectIntersectsClipRect() const357 bool QVirtualKeyboardInputContext::anchorRectIntersectsClipRect() const
358 {
359     Q_D(const QVirtualKeyboardInputContext);
360     return d->anchorRectIntersectsClipRect;
361 }
362 
363 /*!
364     \property QVirtualKeyboardInputContext::cursorRectIntersectsClipRect
365     \brief Holds \c true if the bounding rectangle of the input cursor
366     intersects the exposed input item rectangle.
367 
368     \sa Qt::ImCursorRectangle, Qt::ImInputItemClipRectangle
369 */
370 /*!
371     \qmlproperty bool InputContext::cursorRectIntersectsClipRect
372     \readonly
373     \brief Holds \c true if the bounding rectangle of the input cursor
374     intersects the exposed input item rectangle.
375 
376     \sa Qt::ImCursorRectangle, Qt::ImInputItemClipRectangle
377 */
cursorRectIntersectsClipRect() const378 bool QVirtualKeyboardInputContext::cursorRectIntersectsClipRect() const
379 {
380     Q_D(const QVirtualKeyboardInputContext);
381     return d->cursorRectIntersectsClipRect;
382 }
383 
384 /*!
385     \property QVirtualKeyboardInputContext::selectionControlVisible
386     \brief Holds \c true if the selection control is currently visible.
387 */
388 /*!
389     \qmlproperty bool InputContext::selectionControlVisible
390     \readonly
391     \brief Holds \c true if the selection control is currently visible.
392 */
isSelectionControlVisible() const393 bool QVirtualKeyboardInputContext::isSelectionControlVisible() const
394 {
395     Q_D(const QVirtualKeyboardInputContext);
396     return d->selectionControlVisible;
397 }
398 
399 /*!
400     \internal
401 */
priv() const402 QVirtualKeyboardInputContextPrivate *QVirtualKeyboardInputContext::priv() const
403 {
404     Q_D(const QVirtualKeyboardInputContext);
405     return const_cast<QVirtualKeyboardInputContextPrivate *>(d);
406 }
407 
408 /*!
409     \qmlproperty bool InputContext::shift
410     \deprecated
411 
412     Use \l shiftActive instead.
413 
414     This property is changed when the shift status changes.
415 */
416 
417 /*!
418     \property QVirtualKeyboardInputContext::shift
419     \brief the shift status.
420     \deprecated
421 
422     Use \l shiftActive instead.
423 
424     This property is changed when the shift status changes.
425 */
426 
427 /*!
428     \qmlproperty bool InputContext::shiftActive
429     \since QtQuick.VirtualKeyboard 2.4
430 
431     This property is changed when the shift status changes.
432 */
433 
434 /*!
435     \property QVirtualKeyboardInputContext::shiftActive
436     \brief the shift status.
437 
438     This property is changed when the shift status changes.
439 */
440 
441 /*!
442     \qmlproperty bool InputContext::capsLock
443     \deprecated
444 
445     Use \l capsLockActive instead.
446 
447     This property is changed when the caps lock status changes.
448 */
449 
450 /*!
451     \property QVirtualKeyboardInputContext::capsLock
452     \brief the caps lock status.
453     \deprecated
454 
455     Use \l capsLockActive instead.
456 
457     This property is changed when the caps lock status changes.
458 */
459 
460 /*!
461     \qmlproperty bool InputContext::capsLockActive
462     \since QtQuick.VirtualKeyboard 2.4
463 
464     This property is changed when the caps lock status changes.
465 */
466 
467 /*!
468     \property QVirtualKeyboardInputContext::capsLockActive
469     \brief the caps lock status.
470 
471     This property is changed when the caps lock status changes.
472 */
473 
474 /*!
475     \qmlproperty bool InputContext::uppercase
476     \since QtQuick.VirtualKeyboard 2.2
477 
478     This property is \c true when either \l shiftActive or \l capsLockActive is \c true.
479 */
480 
481 /*!
482     \property QVirtualKeyboardInputContext::uppercase
483     \brief the uppercase status.
484 
485     This property is \c true when either \l shiftActive or \l capsLockActive is \c true.
486 */
487 
488 /*!
489     \qmlproperty int InputContext::anchorPosition
490     \since QtQuick.VirtualKeyboard 2.2
491 
492     This property is changed when the anchor position changes.
493 */
494 
495 /*!
496     \property QVirtualKeyboardInputContext::anchorPosition
497     \brief the anchor position.
498 
499     This property is changed when the anchor position changes.
500 */
501 
502 /*!
503     \qmlproperty int InputContext::cursorPosition
504 
505     This property is changed when the cursor position changes.
506 */
507 
508 /*!
509     \property QVirtualKeyboardInputContext::cursorPosition
510     \brief the cursor position.
511 
512     This property is changed when the cursor position changes.
513 */
514 
515 /*!
516     \qmlproperty int InputContext::inputMethodHints
517 
518     This property is changed when the input method hints changes.
519 */
520 
521 /*!
522     \property QVirtualKeyboardInputContext::inputMethodHints
523     \brief the input method hints.
524 
525     This property is changed when the input method hints changes.
526 */
527 
528 /*!
529     \qmlproperty string InputContext::preeditText
530 
531     This property sets the pre-edit text.
532 */
533 
534 /*!
535     \property QVirtualKeyboardInputContext::preeditText
536     \brief the pre-edit text.
537 
538     This property sets the pre-edit text.
539 */
540 
541 /*!
542     \qmlproperty string InputContext::surroundingText
543 
544     This property is changed when the surrounding text around the cursor changes.
545 */
546 
547 /*!
548     \property QVirtualKeyboardInputContext::surroundingText
549     \brief the surrounding text around cursor.
550 
551     This property is changed when the surrounding text around the cursor changes.
552 */
553 
554 /*!
555     \qmlproperty string InputContext::selectedText
556 
557     This property is changed when the selected text changes.
558 */
559 
560 /*!
561     \property QVirtualKeyboardInputContext::selectedText
562     \brief the selected text.
563 
564     This property is changed when the selected text changes.
565 */
566 
567 /*!
568     \qmlproperty rect InputContext::anchorRectangle
569     \since QtQuick.VirtualKeyboard 2.1
570 
571     This property is changed when the anchor rectangle changes.
572 */
573 
574 /*!
575     \property QVirtualKeyboardInputContext::anchorRectangle
576     \brief the anchor rectangle.
577 
578     This property is changed when the anchor rectangle changes.
579 */
580 
581 /*!
582     \qmlproperty rect InputContext::cursorRectangle
583 
584     This property is changed when the cursor rectangle changes.
585 */
586 
587 /*!
588     \property QVirtualKeyboardInputContext::cursorRectangle
589     \brief the cursor rectangle.
590 
591     This property is changed when the cursor rectangle changes.
592 */
593 
594 /*!
595     \qmlproperty bool InputContext::animating
596 
597     Use this property to set the animating status, for example
598     during UI transitioning states.
599 */
600 
601 /*!
602     \property QVirtualKeyboardInputContext::animating
603     \brief the animating status.
604 
605     Use this property to set the animating status, for example
606     during UI transitioning states.
607 */
608 
609 /*!
610     \qmlproperty string InputContext::locale
611 
612     This property is changed when the input locale changes.
613 */
614 
615 /*!
616     \property QVirtualKeyboardInputContext::locale
617     \brief the locale.
618 
619     This property is changed when the input locale changes.
620 */
621 
622 /*!
623     \qmlproperty QtObject InputContext::inputItem
624     \deprecated
625 
626     This property is changed when the focused input item changes.
627 */
628 
629 /*!
630     \property QVirtualKeyboardInputContext::inputItem
631     \brief the focused input item.
632     \deprecated
633 
634     This property is changed when the focused input item changes.
635 */
636 
637 /*!
638     \qmlproperty InputEngine InputContext::inputEngine
639 
640     This property stores the input engine.
641 */
642 
643 /*!
644     \property QVirtualKeyboardInputContext::inputEngine
645     \brief the input engine.
646 
647     This property stores the input engine.
648 */
649 
650 /*!
651     \property QVirtualKeyboardInputContext::priv
652     \internal
653 */
654 QT_END_NAMESPACE
655