1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include <QtVirtualKeyboard/private/platforminputcontext_p.h>
5#include <QtVirtualKeyboard/qvirtualkeyboardinputcontext.h>
6#include <QtVirtualKeyboard/private/qvirtualkeyboardinputcontext_p.h>
7#include <QtVirtualKeyboard/private/shadowinputcontext_p.h>
8#include <QtVirtualKeyboard/private/abstractinputpanel_p.h>
9#ifdef QT_VIRTUALKEYBOARD_DESKTOP
10#include <QtVirtualKeyboard/private/desktopinputpanel_p.h>
11#endif
12#include <QtVirtualKeyboard/private/appinputpanel_p.h>
13#include <QtVirtualKeyboard/private/virtualkeyboarddebug_p.h>
14
15#include <QWindow>
16#include <QGuiApplication>
17
18QT_BEGIN_NAMESPACE
19namespace QtVirtualKeyboard {
20
21Q_LOGGING_CATEGORY(qlcVirtualKeyboard, "qt.virtualkeyboard")
22
23static const char disableDesktopEnvVarName[] = "QT_VIRTUALKEYBOARD_DESKTOP_DISABLE";
24
25/*!
26 \class QtVirtualKeyboard::PlatformInputContext
27 \internal
28*/
29
30PlatformInputContext::PlatformInputContext() :
31 m_inputContext(nullptr),
32 m_inputPanel(nullptr),
33 m_focusObject(nullptr),
34 m_locale(),
35 m_inputDirection(m_locale.textDirection()),
36 m_filterEvent(nullptr),
37 m_visible(false),
38 m_desktopModeDisabled(false)
39{
40 if (!qEnvironmentVariableIsEmpty(varName: disableDesktopEnvVarName)) {
41 bool ok;
42 int desktopModeDisabled = qgetenv(varName: disableDesktopEnvVarName).toInt(ok: &ok);
43 m_desktopModeDisabled = ok && desktopModeDisabled != 0;
44 }
45}
46
47PlatformInputContext::~PlatformInputContext()
48{
49}
50
51bool PlatformInputContext::isValid() const
52{
53 return true;
54}
55
56void PlatformInputContext::reset()
57{
58 VIRTUALKEYBOARD_DEBUG() << "PlatformInputContext::reset()";
59 if (m_inputContext)
60 m_inputContext->priv()->reset();
61}
62
63void PlatformInputContext::commit()
64{
65 VIRTUALKEYBOARD_DEBUG() << "PlatformInputContext::commit()";
66 if (m_inputContext)
67 m_inputContext->priv()->commit();
68}
69
70void PlatformInputContext::update(Qt::InputMethodQueries queries)
71{
72 VIRTUALKEYBOARD_DEBUG() << "PlatformInputContext::update():" << queries;
73 const bool enabled = inputMethodAccepted();
74#ifdef QT_VIRTUALKEYBOARD_DESKTOP
75 if (enabled && !m_inputPanel && !m_desktopModeDisabled) {
76 m_inputPanel = new DesktopInputPanel(this);
77 m_inputPanel->createView();
78 if (m_inputContext) {
79 m_selectionControl = new DesktopInputSelectionControl(this, m_inputContext);
80 m_selectionControl->createHandles();
81 if (QObject *inputPanel = m_inputContext->priv()->inputPanel)
82 inputPanel->setProperty(name: "desktopPanel", value: true);
83 }
84 }
85#endif
86 if (m_inputContext) {
87 if (enabled)
88 m_inputContext->priv()->update(queries);
89 m_inputContext->priv()->setFocus(enabled);
90 updateInputPanelVisible();
91 }
92}
93
94void PlatformInputContext::invokeAction(QInputMethod::Action action, int cursorPosition)
95{
96 VIRTUALKEYBOARD_DEBUG() << "PlatformInputContext::invokeAction():" << action << cursorPosition;
97 if (m_inputContext)
98 m_inputContext->priv()->invokeAction(action, cursorPosition);
99}
100
101QRectF PlatformInputContext::keyboardRect() const
102{
103 return m_inputContext ? m_inputContext->priv()->keyboardRectangle() : QRectF();
104}
105
106bool PlatformInputContext::isAnimating() const
107{
108 return m_inputContext ? m_inputContext->isAnimating() : false;
109}
110
111void PlatformInputContext::showInputPanel()
112{
113 if (!m_visible) {
114 VIRTUALKEYBOARD_DEBUG() << "PlatformInputContext::showInputPanel()";
115 m_visible = true;
116 }
117 updateInputPanelVisible();
118}
119
120void PlatformInputContext::hideInputPanel()
121{
122 if (m_visible) {
123 VIRTUALKEYBOARD_DEBUG() << "PlatformInputContext::hideInputPanel()";
124 m_visible = false;
125 }
126 updateInputPanelVisible();
127}
128
129bool PlatformInputContext::isInputPanelVisible() const
130{
131 return m_inputPanel ? m_inputPanel->isVisible() : false;
132}
133
134QLocale PlatformInputContext::locale() const
135{
136 return m_locale;
137}
138
139void PlatformInputContext::setLocale(QLocale locale)
140{
141 if (m_locale != locale) {
142 VIRTUALKEYBOARD_DEBUG() << "PlatformInputContext::setLocale():" << locale;
143 m_locale = locale;
144 emitLocaleChanged();
145 }
146}
147
148Qt::LayoutDirection PlatformInputContext::inputDirection() const
149{
150 return m_inputDirection;
151}
152
153void PlatformInputContext::setInputDirection(Qt::LayoutDirection direction)
154{
155 if (m_inputDirection != direction) {
156 VIRTUALKEYBOARD_DEBUG() << "PlatformInputContext::setInputDirection():" << direction;
157 m_inputDirection = direction;
158 emitInputDirectionChanged(newDirection: m_inputDirection);
159 }
160}
161
162QObject *PlatformInputContext::focusObject()
163{
164 return m_focusObject;
165}
166
167void PlatformInputContext::setFocusObject(QObject *object)
168{
169 VIRTUALKEYBOARD_DEBUG() << "PlatformInputContext::setFocusObject():" << object;
170 Q_ASSERT(m_inputContext == nullptr ||
171 m_inputContext->priv()->shadow()->inputItem() == nullptr ||
172 m_inputContext->priv()->shadow()->inputItem() != object);
173 QScopedPointer<QVirtualKeyboardScopedState> setFocusState;
174 if (m_inputContext)
175 setFocusState.reset(other: new QVirtualKeyboardScopedState(m_inputContext->priv(), QVirtualKeyboardInputContextPrivate::State::SetFocus));
176 if (m_focusObject != object) {
177 if (m_focusObject)
178 m_focusObject->removeEventFilter(obj: this);
179 m_focusObject = object;
180 if (m_focusObject)
181 m_focusObject->installEventFilter(filterObj: this);
182 emit focusObjectChanged();
183 }
184 update(queries: Qt::ImQueryAll);
185}
186
187QVirtualKeyboardInputContext *PlatformInputContext::inputContext() const
188{
189 return m_inputContext;
190}
191
192bool PlatformInputContext::eventFilter(QObject *object, QEvent *event)
193{
194 if (event != m_filterEvent && object == m_focusObject && m_inputContext)
195 return m_inputContext->priv()->filterEvent(event);
196 return false;
197}
198
199void PlatformInputContext::sendEvent(QEvent *event)
200{
201 if (m_focusObject) {
202 m_filterEvent = event;
203 QGuiApplication::sendEvent(receiver: m_focusObject, event);
204 m_filterEvent = nullptr;
205 }
206}
207
208void PlatformInputContext::sendKeyEvent(QKeyEvent *event)
209{
210 const QGuiApplication *app = qApp;
211 QWindow *focusWindow = nullptr;
212 if (app) {
213 if (QT_VIRTUALKEYBOARD_FORCE_EVENTS_WITHOUT_FOCUS) {
214 if (!app->allWindows().isEmpty()) {
215 focusWindow = app->allWindows().first();
216 }
217 }
218 else {
219 focusWindow = app->focusWindow();
220 }
221 }
222 if (focusWindow) {
223 m_filterEvent = event;
224 QGuiApplication::sendEvent(receiver: focusWindow, event);
225 m_filterEvent = nullptr;
226 }
227}
228
229QVariant PlatformInputContext::inputMethodQuery(Qt::InputMethodQuery query)
230{
231 QInputMethodQueryEvent event(query);
232 sendEvent(event: &event);
233 return event.value(query);
234}
235
236void PlatformInputContext::setInputContext(QVirtualKeyboardInputContext *context)
237{
238 if (m_inputContext) {
239 disconnect(receiver: this, SLOT(keyboardRectangleChanged()));
240 }
241 m_inputContext = context;
242 if (m_inputContext) {
243 if (!m_inputPanel)
244 m_inputPanel = new AppInputPanel(this);
245 QObject::connect(sender: m_inputContext->priv(), signal: &QVirtualKeyboardInputContextPrivate::keyboardRectangleChanged, context: this, slot: &PlatformInputContext::keyboardRectangleChanged);
246 } else if (m_inputPanel) {
247 m_inputPanel = nullptr;
248 }
249}
250
251bool PlatformInputContext::evaluateInputPanelVisible() const
252{
253 // Show input panel when input panel is requested by showInputPanel()
254 // and focus object is set to an input control with input method accepted (Qt::ImEnabled)
255 // or input events without focus are enabled.
256 return m_visible &&
257 ((m_focusObject && inputMethodAccepted()) ||
258 QT_VIRTUALKEYBOARD_FORCE_EVENTS_WITHOUT_FOCUS);
259}
260
261void PlatformInputContext::keyboardRectangleChanged()
262{
263 m_inputPanel->setInputRect(m_inputContext->priv()->keyboardRectangle().toRect());
264}
265
266void PlatformInputContext::updateInputPanelVisible()
267{
268 if (!m_inputPanel)
269 return;
270
271 const bool visible = evaluateInputPanelVisible();
272 if (visible != m_inputPanel->isVisible()) {
273 if (visible)
274 m_inputPanel->show();
275 else
276 m_inputPanel->hide();
277 if (m_selectionControl) {
278 m_selectionControl->setEnabled(visible);
279 m_inputContext->priv()->updateSelectionControlVisible(inputPanelVisible: visible);
280 }
281 emitInputPanelVisibleChanged();
282 }
283}
284
285} // namespace QtVirtualKeyboard
286QT_END_NAMESPACE
287

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