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

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