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 plugins of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
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 Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39
40 #include "qwinrtinputcontext.h"
41 #include "qwinrtscreen.h"
42 #include <QtGui/QGuiApplication>
43 #include <QtGui/QWindow>
44 #include <private/qeventdispatcher_winrt_p.h>
45
46 #include <functional>
47 #include <wrl.h>
48 #include <roapi.h>
49 #include <windows.ui.viewmanagement.h>
50 #include <windows.ui.core.h>
51 using namespace Microsoft::WRL;
52 using namespace Microsoft::WRL::Wrappers;
53 using namespace ABI::Windows::Foundation;
54 using namespace ABI::Windows::UI::ViewManagement;
55 using namespace ABI::Windows::UI::Core;
56
57 typedef ITypedEventHandler<InputPane*, InputPaneVisibilityEventArgs*> InputPaneVisibilityHandler;
58
59 QT_BEGIN_NAMESPACE
60
61 Q_LOGGING_CATEGORY(lcQpaInputMethods, "qt.qpa.input.methods")
62
getInputPaneRect(ComPtr<IInputPane> pane,qreal scaleFactor)63 inline QRectF getInputPaneRect(ComPtr<IInputPane> pane, qreal scaleFactor)
64 {
65 Rect rect;
66 pane->get_OccludedRect(&rect);
67 return QRectF(qRound(qreal(rect.X) * scaleFactor), qRound(qreal(rect.Y) * scaleFactor),
68 qRound(qreal(rect.Width) * scaleFactor), qRound(qreal(rect.Height) * scaleFactor));
69 }
70
71 /*!
72 \class QWinRTInputContext
73 \brief Manages Input Method visibility
74 \internal
75 \ingroup qt-qpa-winrt
76
77 Listens to the native virtual keyboard for hide/show events and provides
78 hints to the OS for showing/hiding. On WinRT, showInputPanel()/hideInputPanel()
79 have no effect because WinRT dictates that keyboard presence is user-driven:
80 (http://msdn.microsoft.com/en-us/library/windows/apps/hh465404.aspx)
81 Windows Phone, however, supports direct hiding/showing of the keyboard.
82 */
83
QWinRTInputContext(QWinRTScreen * screen)84 QWinRTInputContext::QWinRTInputContext(QWinRTScreen *screen)
85 : m_screen(screen)
86 {
87 qCDebug(lcQpaInputMethods) << __FUNCTION__ << screen;
88
89 QEventDispatcherWinRT::runOnXamlThread([this]() {
90 ComPtr<IInputPaneStatics> statics;
91 if (FAILED(GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_ViewManagement_InputPane).Get(),
92 &statics))) {
93 qWarning("failed to retrieve input pane statics.");
94 return S_OK;
95 }
96
97 ComPtr<IInputPane> inputPane;
98 statics->GetForCurrentView(&inputPane);
99 if (inputPane) {
100 EventRegistrationToken showToken, hideToken;
101 inputPane->add_Showing(Callback<InputPaneVisibilityHandler>(
102 this, &QWinRTInputContext::onShowing).Get(), &showToken);
103 inputPane->add_Hiding(Callback<InputPaneVisibilityHandler>(
104 this, &QWinRTInputContext::onHiding).Get(), &hideToken);
105
106 m_keyboardRect = getInputPaneRect(inputPane, m_screen->scaleFactor());
107 m_isInputPanelVisible = !m_keyboardRect.isEmpty();
108 } else {
109 qWarning("failed to retrieve InputPane.");
110 }
111 return S_OK;
112 });
113
114 connect(QGuiApplication::inputMethod(), &QInputMethod::cursorRectangleChanged,
115 this, &QWinRTInputContext::updateScreenCursorRect);
116 }
117
keyboardRect() const118 QRectF QWinRTInputContext::keyboardRect() const
119 {
120 return m_keyboardRect;
121 }
122
isInputPanelVisible() const123 bool QWinRTInputContext::isInputPanelVisible() const
124 {
125 return m_isInputPanelVisible;
126 }
127
updateScreenCursorRect()128 void QWinRTInputContext::updateScreenCursorRect()
129 {
130 m_screen->setCursorRect(QGuiApplication::inputMethod()->cursorRectangle());
131 }
132
onShowing(IInputPane * pane,IInputPaneVisibilityEventArgs *)133 HRESULT QWinRTInputContext::onShowing(IInputPane *pane, IInputPaneVisibilityEventArgs *)
134 {
135 qCDebug(lcQpaInputMethods) << __FUNCTION__ << pane;
136 m_isInputPanelVisible = true;
137 emitInputPanelVisibleChanged();
138 return handleVisibilityChange(pane);
139 }
140
onHiding(IInputPane * pane,IInputPaneVisibilityEventArgs *)141 HRESULT QWinRTInputContext::onHiding(IInputPane *pane, IInputPaneVisibilityEventArgs *)
142 {
143 qCDebug(lcQpaInputMethods) << __FUNCTION__ << pane;
144 m_isInputPanelVisible = false;
145 emitInputPanelVisibleChanged();
146 return handleVisibilityChange(pane);
147 }
148
handleVisibilityChange(IInputPane * pane)149 HRESULT QWinRTInputContext::handleVisibilityChange(IInputPane *pane)
150 {
151 qCDebug(lcQpaInputMethods) << __FUNCTION__ << pane;
152 const QRectF keyboardRect = getInputPaneRect(pane, m_screen->scaleFactor());
153 if (m_keyboardRect != keyboardRect) {
154 m_keyboardRect = keyboardRect;
155 m_screen->setKeyboardRect(m_keyboardRect);
156 emitKeyboardRectChanged();
157 }
158 return S_OK;
159 }
160
getInputPane(ComPtr<IInputPane2> * inputPane2)161 static HRESULT getInputPane(ComPtr<IInputPane2> *inputPane2)
162 {
163 ComPtr<IInputPaneStatics> factory;
164 HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_ViewManagement_InputPane).Get(),
165 &factory);
166 if (FAILED(hr)) {
167 qErrnoWarning(hr, "Failed to get input pane factory.");
168 return hr;
169 }
170
171 ComPtr<IInputPane> inputPane;
172 hr = factory->GetForCurrentView(&inputPane);
173 if (FAILED(hr)) {
174 qErrnoWarning(hr, "Failed to get input pane.");
175 return hr;
176 }
177
178 hr = inputPane.As(inputPane2);
179 if (FAILED(hr)) {
180 qErrnoWarning(hr, "Failed to get extended input pane.");
181 return hr;
182 }
183 return hr;
184 }
185
showInputPanel()186 void QWinRTInputContext::showInputPanel()
187 {
188 qCDebug(lcQpaInputMethods) << __FUNCTION__;
189
190 QEventDispatcherWinRT::runOnXamlThread([&]() {
191 ComPtr<IInputPane2> inputPane;
192 HRESULT hr = getInputPane(&inputPane);
193 if (FAILED(hr))
194 return S_OK;
195 boolean success;
196 hr = inputPane->TryShow(&success);
197 if (FAILED(hr) || !success)
198 qErrnoWarning(hr, "Failed to show input panel.");
199 return S_OK;
200 });
201 }
202
hideInputPanel()203 void QWinRTInputContext::hideInputPanel()
204 {
205 qCDebug(lcQpaInputMethods) << __FUNCTION__;
206 if (!m_isInputPanelVisible)
207 return;
208
209 QEventDispatcherWinRT::runOnXamlThread([&]() {
210 ComPtr<IInputPane2> inputPane;
211 HRESULT hr = getInputPane(&inputPane);
212 if (FAILED(hr))
213 return S_OK;
214 boolean success;
215 hr = inputPane->TryHide(&success);
216 if (FAILED(hr) || !success)
217 qErrnoWarning(hr, "Failed to hide input panel.");
218 return S_OK;
219 });
220 }
221
222 QT_END_NAMESPACE
223