1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include <QtVirtualKeyboard/qvirtualkeyboardinputcontext.h>
5#include <QtVirtualKeyboard/private/qvirtualkeyboardinputcontext_p.h>
6#include <QtVirtualKeyboard/private/shifthandler_p.h>
7#include <QtVirtualKeyboard/private/platforminputcontext_p.h>
8#include <QtVirtualKeyboard/private/virtualkeyboarddebug_p.h>
9#include <QtVirtualKeyboard/qvirtualkeyboardobserver.h>
10
11#include <QTextFormat>
12#include <QGuiApplication>
13#include <QtGui/private/qhighdpiscaling_p.h>
14
15QT_BEGIN_NAMESPACE
16using namespace QtVirtualKeyboard;
17
18/*!
19 \qmltype InputContext
20 \instantiates QVirtualKeyboardInputContext
21 \inqmlmodule QtQuick.VirtualKeyboard
22 \ingroup qtvirtualkeyboard-internal-qml
23 \brief Provides access to an input context.
24
25 The InputContext can be accessed as singleton instance.
26*/
27
28/*!
29 \class QVirtualKeyboardInputContext
30 \inmodule QtVirtualKeyboard
31 \ingroup qtvirtualkeyboard-cpp-for-devs
32 \brief Provides access to an input context.
33*/
34
35/*!
36 \internal
37 Constructs an input context with \a parent as the platform input
38 context.
39*/
40QVirtualKeyboardInputContext::QVirtualKeyboardInputContext(QObject *parent) :
41 QObject(parent),
42 d_ptr(new QVirtualKeyboardInputContextPrivate(this))
43{
44 Q_D(QVirtualKeyboardInputContext);
45 d->init();
46 QObject::connect(sender: d->_shiftHandler, signal: &ShiftHandler::shiftActiveChanged, context: this, slot: &QVirtualKeyboardInputContext::shiftActiveChanged);
47 QObject::connect(sender: d->_shiftHandler, signal: &ShiftHandler::capsLockActiveChanged, context: this, slot: &QVirtualKeyboardInputContext::capsLockActiveChanged);
48 QObject::connect(sender: d->_shiftHandler, signal: &ShiftHandler::uppercaseChanged, context: this, slot: &QVirtualKeyboardInputContext::uppercaseChanged);
49 QObject::connect(sender: d, signal: &QVirtualKeyboardInputContextPrivate::localeChanged, context: this, slot: &QVirtualKeyboardInputContext::localeChanged);
50 QObject::connect(sender: d, signal: &QVirtualKeyboardInputContextPrivate::inputItemChanged, context: this, slot: &QVirtualKeyboardInputContext::inputItemChanged);
51}
52
53/*!
54 \internal
55 Destroys the input context and frees all allocated resources.
56*/
57QVirtualKeyboardInputContext::~QVirtualKeyboardInputContext()
58{
59}
60
61bool QVirtualKeyboardInputContext::isShiftActive() const
62{
63 Q_D(const QVirtualKeyboardInputContext);
64 return d->_shiftHandler->isShiftActive();
65}
66
67bool QVirtualKeyboardInputContext::isCapsLockActive() const
68{
69 Q_D(const QVirtualKeyboardInputContext);
70 return d->_shiftHandler->isCapsLockActive();
71}
72
73bool QVirtualKeyboardInputContext::isUppercase() const
74{
75 Q_D(const QVirtualKeyboardInputContext);
76 return d->_shiftHandler->isUppercase();
77}
78
79int QVirtualKeyboardInputContext::anchorPosition() const
80{
81 Q_D(const QVirtualKeyboardInputContext);
82 return d->anchorPosition;
83}
84
85int QVirtualKeyboardInputContext::cursorPosition() const
86{
87 Q_D(const QVirtualKeyboardInputContext);
88 return d->cursorPosition;
89}
90
91Qt::InputMethodHints QVirtualKeyboardInputContext::inputMethodHints() const
92{
93 Q_D(const QVirtualKeyboardInputContext);
94 return d->inputMethodHints;
95}
96
97QString QVirtualKeyboardInputContext::preeditText() const
98{
99 Q_D(const QVirtualKeyboardInputContext);
100 return d->preeditText;
101}
102
103void QVirtualKeyboardInputContext::setPreeditText(const QString &text, QList<QInputMethodEvent::Attribute> attributes, int replaceFrom, int replaceLength)
104{
105 Q_D(QVirtualKeyboardInputContext);
106 // Add default attributes
107 if (!text.isEmpty()) {
108 if (!d->testAttribute(attributes, attributeType: QInputMethodEvent::TextFormat)) {
109 QTextCharFormat textFormat;
110 textFormat.setUnderlineStyle(QTextCharFormat::SingleUnderline);
111 attributes.append(t: QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 0, text.size(), textFormat));
112 }
113 } else if (d->_forceCursorPosition != -1) {
114 d->addSelectionAttribute(attributes);
115 }
116
117 d->sendPreedit(text, attributes, replaceFrom, replaceLength);
118}
119
120QList<QInputMethodEvent::Attribute> QVirtualKeyboardInputContext::preeditTextAttributes() const
121{
122 Q_D(const QVirtualKeyboardInputContext);
123 return d->preeditTextAttributes;
124}
125
126QString QVirtualKeyboardInputContext::surroundingText() const
127{
128 Q_D(const QVirtualKeyboardInputContext);
129 return d->surroundingText;
130}
131
132QString QVirtualKeyboardInputContext::selectedText() const
133{
134 Q_D(const QVirtualKeyboardInputContext);
135 return d->selectedText;
136}
137
138QRectF QVirtualKeyboardInputContext::anchorRectangle() const
139{
140 Q_D(const QVirtualKeyboardInputContext);
141 return d->anchorRectangle;
142}
143
144QRectF QVirtualKeyboardInputContext::cursorRectangle() const
145{
146 Q_D(const QVirtualKeyboardInputContext);
147 return d->cursorRectangle;
148}
149
150bool QVirtualKeyboardInputContext::isAnimating() const
151{
152 Q_D(const QVirtualKeyboardInputContext);
153 return d->animating;
154}
155
156void QVirtualKeyboardInputContext::setAnimating(bool animating)
157{
158 Q_D(QVirtualKeyboardInputContext);
159 if (d->animating != animating) {
160 VIRTUALKEYBOARD_DEBUG() << "QVirtualKeyboardInputContext::setAnimating():" << animating;
161 d->animating = animating;
162 emit animatingChanged();
163 d->platformInputContext->emitAnimatingChanged();
164 }
165}
166
167QString QVirtualKeyboardInputContext::locale() const
168{
169 Q_D(const QVirtualKeyboardInputContext);
170 return d->locale();
171}
172
173QObject *QVirtualKeyboardInputContext::inputItem() const
174{
175 Q_D(const QVirtualKeyboardInputContext);
176 return d->inputItem();
177}
178
179QVirtualKeyboardInputEngine *QVirtualKeyboardInputContext::inputEngine() const
180{
181 Q_D(const QVirtualKeyboardInputContext);
182 return d->inputEngine;
183}
184
185/*!
186 \qmlmethod void InputContext::sendKeyClick(int key, string text, int modifiers = 0)
187
188 Sends a key click event with the given \a key, \a text and \a modifiers to
189 the input item that currently has focus.
190*/
191/*!
192 Sends a key click event with the given \a key, \a text and \a modifiers to
193 the input item that currently has focus.
194*/
195void QVirtualKeyboardInputContext::sendKeyClick(int key, const QString &text, int modifiers)
196{
197 Q_D(QVirtualKeyboardInputContext);
198 if ((d->_focus && d->platformInputContext) || QT_VIRTUALKEYBOARD_FORCE_EVENTS_WITHOUT_FOCUS) {
199 QKeyEvent pressEvent(QEvent::KeyPress, key, Qt::KeyboardModifiers(modifiers), text);
200 QKeyEvent releaseEvent(QEvent::KeyRelease, key, Qt::KeyboardModifiers(modifiers), text);
201 VIRTUALKEYBOARD_DEBUG().nospace() << "InputContext::sendKeyClick()"
202#ifdef SENSITIVE_DEBUG
203 << ": " << key
204#endif
205 ;
206
207
208 d->setState(QVirtualKeyboardInputContextPrivate::State::KeyEvent);
209 d->platformInputContext->sendKeyEvent(event: &pressEvent);
210 d->platformInputContext->sendKeyEvent(event: &releaseEvent);
211 if (d->activeKeys.isEmpty())
212 d->clearState(state: QVirtualKeyboardInputContextPrivate::State::KeyEvent);
213 } else {
214 VIRTUALKEYBOARD_WARN() << "InputContext::sendKeyClick(): no focus to send key click"
215#ifdef SENSITIVE_DEBUG
216 << key << text
217#endif
218 << "- QGuiApplication::focusWindow() is:" << QGuiApplication::focusWindow();
219 }
220}
221
222/*!
223 \qmlmethod void InputContext::commit()
224
225 Commits the current pre-edit text.
226*/
227/*!
228 \fn void QVirtualKeyboardInputContext::commit()
229
230 Commits the current pre-edit text.
231*/
232void QVirtualKeyboardInputContext::commit()
233{
234 Q_D(QVirtualKeyboardInputContext);
235 QString text = d->preeditText;
236 commit(text);
237}
238
239/*!
240 \qmlmethod void InputContext::commit(string text, int replaceFrom = 0, int replaceLength = 0)
241
242 Commits the final \a text to the input item and optionally
243 modifies the text relative to the start of the pre-edit text.
244 If \e replaceFrom is non-zero, the \a text replaces the
245 contents relative to \e replaceFrom with a length of
246 \e replaceLength.
247*/
248/*!
249 Commits the final \a text to the input item and optionally
250 modifies the text relative to the start of the pre-edit text.
251 If \a replaceFrom is non-zero, the \a text replaces the
252 contents relative to \a replaceFrom with a length of
253 \a replaceLength.
254*/
255void QVirtualKeyboardInputContext::commit(const QString &text, int replaceFrom, int replaceLength)
256{
257 Q_D(QVirtualKeyboardInputContext);
258
259 VIRTUALKEYBOARD_DEBUG() << "QVirtualKeyboardInputContext::commit()"
260#ifdef SENSITIVE_DEBUG
261 << text << replaceFrom << replaceLength
262#endif
263 ;
264 bool preeditChanged = !d->preeditText.isEmpty();
265
266 if (d->platformInputContext) {
267 QList<QInputMethodEvent::Attribute> attributes;
268 d->addSelectionAttribute(attributes);
269 d->preeditText.clear();
270 d->preeditTextAttributes.clear();
271 QInputMethodEvent inputEvent(QString(), attributes);
272 inputEvent.setCommitString(commitString: text, replaceFrom, replaceLength);
273 d->sendInputMethodEvent(event: &inputEvent);
274 } else {
275 d->preeditText.clear();
276 d->preeditTextAttributes.clear();
277 }
278
279 if (preeditChanged)
280 emit preeditTextChanged();
281}
282
283/*!
284 \qmlmethod void InputContext::clear()
285
286 Clears the pre-edit text.
287*/
288/*!
289 \fn void QVirtualKeyboardInputContext::clear()
290
291 Clears the pre-edit text.
292*/
293void QVirtualKeyboardInputContext::clear()
294{
295 Q_D(QVirtualKeyboardInputContext);
296 bool preeditChanged = !d->preeditText.isEmpty();
297 d->preeditText.clear();
298 d->preeditTextAttributes.clear();
299
300 if (d->platformInputContext) {
301 QList<QInputMethodEvent::Attribute> attributes;
302 d->addSelectionAttribute(attributes);
303 QInputMethodEvent event(QString(), attributes);
304 d->sendInputMethodEvent(event: &event);
305 }
306
307 if (preeditChanged)
308 emit preeditTextChanged();
309}
310
311/*!
312 \internal
313*/
314void QVirtualKeyboardInputContext::setSelectionOnFocusObject(const QPointF &anchorPos, const QPointF &cursorPos)
315{
316 QWindow *window = qApp->focusWindow();
317 const QPointF &nativeAnchorPos = QHighDpi::toNativePixels(value: anchorPos, context: window);
318 const QPointF &nativeCursorPos = QHighDpi::toNativePixels(value: cursorPos, context: window);
319
320 QPlatformInputContext::setSelectionOnFocusObject(anchorPos: nativeAnchorPos, cursorPos: nativeCursorPos);
321}
322
323/*!
324 \property QVirtualKeyboardInputContext::anchorRectIntersectsClipRect
325 \brief Holds \c true if the bounding rectangle of the selection anchor
326 intersects the exposed input item rectangle.
327
328 \sa Qt::ImAnchorRectangle, Qt::ImInputItemClipRectangle
329*/
330/*!
331 \qmlproperty bool InputContext::anchorRectIntersectsClipRect
332 \readonly
333 \brief Holds \c true if the bounding rectangle of the selection anchor
334 intersects the exposed input item rectangle.
335
336 \sa Qt::ImAnchorRectangle, Qt::ImInputItemClipRectangle
337*/
338bool QVirtualKeyboardInputContext::anchorRectIntersectsClipRect() const
339{
340 Q_D(const QVirtualKeyboardInputContext);
341 return d->anchorRectIntersectsClipRect;
342}
343
344/*!
345 \property QVirtualKeyboardInputContext::cursorRectIntersectsClipRect
346 \brief Holds \c true if the bounding rectangle of the input cursor
347 intersects the exposed input item rectangle.
348
349 \sa Qt::ImCursorRectangle, Qt::ImInputItemClipRectangle
350*/
351/*!
352 \qmlproperty bool InputContext::cursorRectIntersectsClipRect
353 \readonly
354 \brief Holds \c true if the bounding rectangle of the input cursor
355 intersects the exposed input item rectangle.
356
357 \sa Qt::ImCursorRectangle, Qt::ImInputItemClipRectangle
358*/
359bool QVirtualKeyboardInputContext::cursorRectIntersectsClipRect() const
360{
361 Q_D(const QVirtualKeyboardInputContext);
362 return d->cursorRectIntersectsClipRect;
363}
364
365/*!
366 \property QVirtualKeyboardInputContext::selectionControlVisible
367 \brief Holds \c true if the selection control is currently visible.
368*/
369/*!
370 \qmlproperty bool InputContext::selectionControlVisible
371 \readonly
372 \brief Holds \c true if the selection control is currently visible.
373*/
374bool QVirtualKeyboardInputContext::isSelectionControlVisible() const
375{
376 Q_D(const QVirtualKeyboardInputContext);
377 return d->selectionControlVisible;
378}
379
380/*!
381 \internal
382*/
383QVirtualKeyboardInputContextPrivate *QVirtualKeyboardInputContext::priv() const
384{
385 Q_D(const QVirtualKeyboardInputContext);
386 return const_cast<QVirtualKeyboardInputContextPrivate *>(d);
387}
388
389/*!
390 \property QVirtualKeyboardInputContext::keyboardObserver
391 \since QtQuick.VirtualKeyboard 6.1
392 \brief Holds the keyboard observer object, which can be used to receive
393 notifications of keyboard change events.
394*/
395/*!
396 \qmlproperty KeyboardObserver InputContext::keyboardObserver
397 \readonly
398 \since QtQuick.VirtualKeyboard 6.1
399 \brief Holds the keyboard observer object, which can be used to receive
400 notifications of keyboard change events.
401*/
402QVirtualKeyboardObserver *QVirtualKeyboardInputContext::keyboardObserver() const
403{
404 Q_D(const QVirtualKeyboardInputContext);
405 return d->keyboardObserver;
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*/
654QT_END_NAMESPACE
655

source code of qtvirtualkeyboard/src/virtualkeyboard/qvirtualkeyboardinputcontext.cpp