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