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 "qwinrtscreen.h"
41
42 #include "qwinrtbackingstore.h"
43 #include "qwinrtinputcontext.h"
44 #include "qwinrtcursor.h"
45 #if QT_CONFIG(draganddrop)
46 #include "qwinrtdrag.h"
47 #endif
48 #include "qwinrtwindow.h"
49 #include "qwinrtcanvas.h"
50 #include <private/qeventdispatcher_winrt_p.h>
51 #include <private/qhighdpiscaling_p.h>
52
53 #include <QtCore/qdebug.h>
54 #include <QtCore/QLoggingCategory>
55 #include <QtGui/QSurfaceFormat>
56 #include <QtGui/QGuiApplication>
57 #include <qpa/qwindowsysteminterface.h>
58 #include <QtCore/qt_windows.h>
59 #include <QtCore/qfunctions_winrt.h>
60
61 #include <functional>
62 #include <wrl.h>
63 #include <windows.system.h>
64 #include <Windows.ApplicationModel.h>
65 #include <Windows.ApplicationModel.core.h>
66 #include <windows.devices.input.h>
67 #include <windows.ui.h>
68 #include <windows.ui.core.h>
69 #include <windows.ui.input.h>
70 #include <windows.ui.xaml.h>
71 #include <windows.ui.viewmanagement.h>
72 #include <windows.graphics.display.h>
73 #include <windows.foundation.h>
74
75 using namespace Microsoft::WRL;
76 using namespace Microsoft::WRL::Wrappers;
77 using namespace ABI::Windows::ApplicationModel;
78 using namespace ABI::Windows::ApplicationModel::Core;
79 using namespace ABI::Windows::Foundation;
80 using namespace ABI::Windows::System;
81 using namespace ABI::Windows::UI;
82 using namespace ABI::Windows::UI::Core;
83 using namespace ABI::Windows::UI::Input;
84 using namespace ABI::Windows::UI::ViewManagement;
85 using namespace ABI::Windows::Devices::Input;
86 using namespace ABI::Windows::Graphics::Display;
87
88 typedef ITypedEventHandler<CoreWindow*, WindowActivatedEventArgs*> ActivatedHandler;
89 typedef ITypedEventHandler<CoreWindow*, CoreWindowEventArgs*> ClosedHandler;
90 typedef ITypedEventHandler<CoreWindow*, CharacterReceivedEventArgs*> CharacterReceivedHandler;
91 typedef ITypedEventHandler<CoreWindow*, InputEnabledEventArgs*> InputEnabledHandler;
92 typedef ITypedEventHandler<CoreWindow*, KeyEventArgs*> KeyHandler;
93 typedef ITypedEventHandler<CoreWindow*, PointerEventArgs*> PointerHandler;
94 typedef ITypedEventHandler<CoreWindow*, VisibilityChangedEventArgs*> VisibilityChangedHandler;
95 typedef ITypedEventHandler<DisplayInformation*, IInspectable*> DisplayInformationHandler;
96 typedef ITypedEventHandler<ICorePointerRedirector*, PointerEventArgs*> RedirectHandler;
97 typedef ITypedEventHandler<ApplicationView*, IInspectable*> VisibleBoundsChangedHandler;
98
99 QT_BEGIN_NAMESPACE
100
101 Q_LOGGING_CATEGORY(lcQpaEvents, "qt.qpa.events")
102
103 #if !defined(QT_NO_DEBUG_STREAM)
operator <<(QDebug dbg,QWinRTScreen::MousePositionTransition transition)104 QDebug operator<<(QDebug dbg, QWinRTScreen::MousePositionTransition transition)
105 {
106 QDebugStateSaver saver(dbg);
107 dbg.nospace() << "QWinRTScreen::MousePositionTransition::";
108 switch (transition) {
109 case QWinRTScreen::MousePositionTransition::MovedOut:
110 dbg << "MovedOut";
111 break;
112 case QWinRTScreen::MousePositionTransition::MovedIn:
113 dbg << "MovedIn";
114 break;
115 case QWinRTScreen::MousePositionTransition::StayedOut:
116 dbg << "StayedOut";
117 break;
118 case QWinRTScreen::MousePositionTransition::StayedIn:
119 dbg << "StayedIn";
120 break;
121 }
122 return dbg;
123 }
124 #endif
125
126 struct KeyInfo {
KeyInfoKeyInfo127 KeyInfo()
128 {
129 }
130
KeyInfoKeyInfo131 KeyInfo(quint32 virtualKey)
132 : virtualKey(virtualKey)
133 {
134 }
135
136 QString text;
137 quint32 virtualKey{0};
138 bool isAutoRepeat{false};
139 };
140
qtOrientationsFromNative(DisplayOrientations native)141 static inline Qt::ScreenOrientations qtOrientationsFromNative(DisplayOrientations native)
142 {
143 Qt::ScreenOrientations orientations = Qt::PrimaryOrientation;
144 if (native & DisplayOrientations_Portrait)
145 orientations |= Qt::PortraitOrientation;
146 if (native & DisplayOrientations_PortraitFlipped)
147 orientations |= Qt::InvertedPortraitOrientation;
148 if (native & DisplayOrientations_Landscape)
149 orientations |= Qt::LandscapeOrientation;
150 if (native & DisplayOrientations_LandscapeFlipped)
151 orientations |= Qt::InvertedLandscapeOrientation;
152 return orientations;
153 }
154
nativeOrientationsFromQt(Qt::ScreenOrientations orientation)155 static inline DisplayOrientations nativeOrientationsFromQt(Qt::ScreenOrientations orientation)
156 {
157 DisplayOrientations native = DisplayOrientations_None;
158 if (orientation & Qt::PortraitOrientation)
159 native |= DisplayOrientations_Portrait;
160 if (orientation & Qt::InvertedPortraitOrientation)
161 native |= DisplayOrientations_PortraitFlipped;
162 if (orientation & Qt::LandscapeOrientation)
163 native |= DisplayOrientations_Landscape;
164 if (orientation & Qt::InvertedLandscapeOrientation)
165 native |= DisplayOrientations_LandscapeFlipped;
166 return native;
167 }
168
qIsNonPrintable(quint32 keyCode)169 static inline bool qIsNonPrintable(quint32 keyCode)
170 {
171 switch (keyCode) {
172 case '\b':
173 case '\n':
174 case '\t':
175 case '\r':
176 case '\v':
177 case '\f':
178 return true;
179 default:
180 return false;
181 }
182 }
183
184 // Return Qt meta key from VirtualKey
qKeyFromVirtual(VirtualKey key)185 static inline Qt::Key qKeyFromVirtual(VirtualKey key)
186 {
187 switch (key) {
188
189 default:
190 return Qt::Key_unknown;
191
192 // Non-printable characters
193 case VirtualKey_Enter:
194 return Qt::Key_Enter;
195 case VirtualKey_Tab:
196 return Qt::Key_Tab;
197 case VirtualKey_Back:
198 return Qt::Key_Backspace;
199
200 // Modifiers
201 case VirtualKey_Shift:
202 case VirtualKey_LeftShift:
203 case VirtualKey_RightShift:
204 return Qt::Key_Shift;
205 case VirtualKey_Control:
206 case VirtualKey_LeftControl:
207 case VirtualKey_RightControl:
208 return Qt::Key_Control;
209 case VirtualKey_Menu:
210 case VirtualKey_LeftMenu:
211 case VirtualKey_RightMenu:
212 return Qt::Key_Alt;
213 case VirtualKey_LeftWindows:
214 case VirtualKey_RightWindows:
215 return Qt::Key_Meta;
216
217 // Toggle keys
218 case VirtualKey_CapitalLock:
219 return Qt::Key_CapsLock;
220 case VirtualKey_NumberKeyLock:
221 return Qt::Key_NumLock;
222 case VirtualKey_Scroll:
223 return Qt::Key_ScrollLock;
224
225 // East-Asian language keys
226 case VirtualKey_Kana:
227 //case VirtualKey_Hangul: // Same enum as Kana
228 return Qt::Key_Kana_Shift;
229 case VirtualKey_Junja:
230 return Qt::Key_Hangul_Jeonja;
231 case VirtualKey_Kanji:
232 //case VirtualKey_Hanja: // Same enum as Kanji
233 return Qt::Key_Kanji;
234 case VirtualKey_ModeChange:
235 return Qt::Key_Mode_switch;
236 case VirtualKey_Convert:
237 return Qt::Key_Henkan;
238 case VirtualKey_NonConvert:
239 return Qt::Key_Muhenkan;
240
241 // Misc. keys
242 case VirtualKey_Cancel:
243 return Qt::Key_Cancel;
244 case VirtualKey_Clear:
245 return Qt::Key_Clear;
246 case VirtualKey_Application:
247 return Qt::Key_ApplicationLeft;
248 case VirtualKey_Sleep:
249 return Qt::Key_Sleep;
250 case VirtualKey_Pause:
251 return Qt::Key_Pause;
252 case VirtualKey_PageUp:
253 return Qt::Key_PageUp;
254 case VirtualKey_PageDown:
255 return Qt::Key_PageDown;
256 case VirtualKey_End:
257 return Qt::Key_End;
258 case VirtualKey_Home:
259 return Qt::Key_Home;
260 case VirtualKey_Left:
261 return Qt::Key_Left;
262 case VirtualKey_Up:
263 return Qt::Key_Up;
264 case VirtualKey_Right:
265 return Qt::Key_Right;
266 case VirtualKey_Down:
267 return Qt::Key_Down;
268 case VirtualKey_Select:
269 return Qt::Key_Select;
270 case VirtualKey_Print:
271 return Qt::Key_Print;
272 case VirtualKey_Execute:
273 return Qt::Key_Execute;
274 case VirtualKey_Insert:
275 return Qt::Key_Insert;
276 case VirtualKey_Delete:
277 return Qt::Key_Delete;
278 case VirtualKey_Help:
279 return Qt::Key_Help;
280 case VirtualKey_Snapshot:
281 return Qt::Key_Camera;
282 case VirtualKey_Escape:
283 return Qt::Key_Escape;
284
285 // Function Keys
286 case VirtualKey_F1:
287 return Qt::Key_F1;
288 case VirtualKey_F2:
289 return Qt::Key_F2;
290 case VirtualKey_F3:
291 return Qt::Key_F3;
292 case VirtualKey_F4:
293 return Qt::Key_F4;
294 case VirtualKey_F5:
295 return Qt::Key_F5;
296 case VirtualKey_F6:
297 return Qt::Key_F6;
298 case VirtualKey_F7:
299 return Qt::Key_F7;
300 case VirtualKey_F8:
301 return Qt::Key_F8;
302 case VirtualKey_F9:
303 return Qt::Key_F9;
304 case VirtualKey_F10:
305 return Qt::Key_F10;
306 case VirtualKey_F11:
307 return Qt::Key_F11;
308 case VirtualKey_F12:
309 return Qt::Key_F12;
310 case VirtualKey_F13:
311 return Qt::Key_F13;
312 case VirtualKey_F14:
313 return Qt::Key_F14;
314 case VirtualKey_F15:
315 return Qt::Key_F15;
316 case VirtualKey_F16:
317 return Qt::Key_F16;
318 case VirtualKey_F17:
319 return Qt::Key_F17;
320 case VirtualKey_F18:
321 return Qt::Key_F18;
322 case VirtualKey_F19:
323 return Qt::Key_F19;
324 case VirtualKey_F20:
325 return Qt::Key_F20;
326 case VirtualKey_F21:
327 return Qt::Key_F21;
328 case VirtualKey_F22:
329 return Qt::Key_F22;
330 case VirtualKey_F23:
331 return Qt::Key_F23;
332 case VirtualKey_F24:
333 return Qt::Key_F24;
334
335 // Character keys
336 case VirtualKey_Space:
337 return Qt::Key_Space;
338 case VirtualKey_Number0:
339 case VirtualKey_NumberPad0:
340 return Qt::Key_0;
341 case VirtualKey_Number1:
342 case VirtualKey_NumberPad1:
343 return Qt::Key_1;
344 case VirtualKey_Number2:
345 case VirtualKey_NumberPad2:
346 return Qt::Key_2;
347 case VirtualKey_Number3:
348 case VirtualKey_NumberPad3:
349 return Qt::Key_3;
350 case VirtualKey_Number4:
351 case VirtualKey_NumberPad4:
352 return Qt::Key_4;
353 case VirtualKey_Number5:
354 case VirtualKey_NumberPad5:
355 return Qt::Key_5;
356 case VirtualKey_Number6:
357 case VirtualKey_NumberPad6:
358 return Qt::Key_6;
359 case VirtualKey_Number7:
360 case VirtualKey_NumberPad7:
361 return Qt::Key_7;
362 case VirtualKey_Number8:
363 case VirtualKey_NumberPad8:
364 return Qt::Key_8;
365 case VirtualKey_Number9:
366 case VirtualKey_NumberPad9:
367 return Qt::Key_9;
368 case VirtualKey_A:
369 return Qt::Key_A;
370 case VirtualKey_B:
371 return Qt::Key_B;
372 case VirtualKey_C:
373 return Qt::Key_C;
374 case VirtualKey_D:
375 return Qt::Key_D;
376 case VirtualKey_E:
377 return Qt::Key_E;
378 case VirtualKey_F:
379 return Qt::Key_F;
380 case VirtualKey_G:
381 return Qt::Key_G;
382 case VirtualKey_H:
383 return Qt::Key_H;
384 case VirtualKey_I:
385 return Qt::Key_I;
386 case VirtualKey_J:
387 return Qt::Key_J;
388 case VirtualKey_K:
389 return Qt::Key_K;
390 case VirtualKey_L:
391 return Qt::Key_L;
392 case VirtualKey_M:
393 return Qt::Key_M;
394 case VirtualKey_N:
395 return Qt::Key_N;
396 case VirtualKey_O:
397 return Qt::Key_O;
398 case VirtualKey_P:
399 return Qt::Key_P;
400 case VirtualKey_Q:
401 return Qt::Key_Q;
402 case VirtualKey_R:
403 return Qt::Key_R;
404 case VirtualKey_S:
405 return Qt::Key_S;
406 case VirtualKey_T:
407 return Qt::Key_T;
408 case VirtualKey_U:
409 return Qt::Key_U;
410 case VirtualKey_V:
411 return Qt::Key_V;
412 case VirtualKey_W:
413 return Qt::Key_W;
414 case VirtualKey_X:
415 return Qt::Key_X;
416 case VirtualKey_Y:
417 return Qt::Key_Y;
418 case VirtualKey_Z:
419 return Qt::Key_Z;
420 case VirtualKey_Multiply:
421 return Qt::Key_9;
422 case VirtualKey_Add:
423 return Qt::Key_9;
424 case VirtualKey_Separator:
425 return Qt::Key_9;
426 case VirtualKey_Subtract:
427 return Qt::Key_9;
428 case VirtualKey_Decimal:
429 return Qt::Key_9;
430 case VirtualKey_Divide:
431 return Qt::Key_9;
432
433 /* Keys with no matching Qt enum (?)
434 case VirtualKey_None:
435 case VirtualKey_LeftButton:
436 case VirtualKey_RightButton:
437 case VirtualKey_MiddleButton:
438 case VirtualKey_XButton1:
439 case VirtualKey_XButton2:
440 case VirtualKey_Final:
441 case VirtualKey_Accept:*/
442 }
443 }
444
445 // Some keys like modifiers, caps lock etc. should not be automatically repeated if the key is held down
shouldAutoRepeat(Qt::Key key)446 static inline bool shouldAutoRepeat(Qt::Key key)
447 {
448 switch (key) {
449 case Qt::Key_Shift:
450 case Qt::Key_Control:
451 case Qt::Key_Alt:
452 case Qt::Key_Meta:
453 case Qt::Key_CapsLock:
454 case Qt::Key_NumLock:
455 case Qt::Key_ScrollLock:
456 return false;
457 default:
458 return true;
459 }
460 }
461
qKeyFromCode(quint32 code,int mods)462 static inline Qt::Key qKeyFromCode(quint32 code, int mods)
463 {
464 if (code >= 'a' && code <= 'z')
465 code = toupper(code);
466 if ((mods & Qt::ControlModifier) != 0) {
467 if (code >= 0 && code <= 31) // Ctrl+@..Ctrl+A..CTRL+Z..Ctrl+_
468 code += '@'; // to @..A..Z.._
469 }
470 return static_cast<Qt::Key>(code & 0xff);
471 }
472
473 typedef HRESULT (__stdcall ICoreWindow::*CoreWindowCallbackRemover)(EventRegistrationToken);
qHash(CoreWindowCallbackRemover key)474 uint qHash(CoreWindowCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); }
475 typedef HRESULT (__stdcall IDisplayInformation::*DisplayCallbackRemover)(EventRegistrationToken);
qHash(DisplayCallbackRemover key)476 uint qHash(DisplayCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); }
477 typedef HRESULT (__stdcall ICorePointerRedirector::*RedirectorCallbackRemover)(EventRegistrationToken);
qHash(RedirectorCallbackRemover key)478 uint qHash(RedirectorCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); }
479 typedef HRESULT (__stdcall IApplicationView2::*ApplicationView2CallbackRemover)(EventRegistrationToken);
qHash(ApplicationView2CallbackRemover key)480 uint qHash(ApplicationView2CallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); }
481
482 class QWinRTScreenPrivate
483 {
484 public:
485 QTouchDevice *touchDevice;
486 ComPtr<ICoreWindow> coreWindow;
487 ComPtr<ICorePointerRedirector> redirect;
488 ComPtr<QWinRTCanvas> canvas;
489 ComPtr<IApplicationView> view;
490 ComPtr<IDisplayInformation> displayInformation;
491
492 QScopedPointer<QWinRTCursor> cursor;
493 QHash<quint32, QWindowSystemInterface::TouchPoint> touchPoints;
494 QRectF logicalRect;
495 QRectF visibleRect;
496 QSurfaceFormat surfaceFormat;
497 qreal logicalDpi;
498 QDpi physicalDpi;
499 qreal scaleFactor;
500 Qt::ScreenOrientation nativeOrientation;
501 Qt::ScreenOrientation orientation;
502 QList<QWindow *> visibleWindows;
503 QHash<Qt::Key, KeyInfo> activeKeys;
504 QHash<CoreWindowCallbackRemover, EventRegistrationToken> windowTokens;
505 QHash<DisplayCallbackRemover, EventRegistrationToken> displayTokens;
506 QHash<RedirectorCallbackRemover, EventRegistrationToken> redirectTokens;
507 QHash<ApplicationView2CallbackRemover, EventRegistrationToken> view2Tokens;
508 ComPtr<IApplicationView2> view2;
509 QAtomicPointer<QWinRTWindow> mouseGrabWindow;
510 QAtomicPointer<QWinRTWindow> keyboardGrabWindow;
511 QWindow *currentPressWindow = nullptr;
512 QWindow *currentTargetWindow = nullptr;
513 bool firstMouseMove = true;
514 bool resizePending = false;
515 };
516
517 // To be called from the XAML thread
QWinRTScreen()518 QWinRTScreen::QWinRTScreen()
519 : d_ptr(new QWinRTScreenPrivate)
520 {
521 Q_D(QWinRTScreen);
522 qCDebug(lcQpaWindows) << __FUNCTION__;
523 d->orientation = Qt::PrimaryOrientation;
524 d->touchDevice = nullptr;
525
526 HRESULT hr;
527 ComPtr<Xaml::IWindowStatics> windowStatics;
528 hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Window).Get(),
529 IID_PPV_ARGS(&windowStatics));
530 Q_ASSERT_SUCCEEDED(hr);
531 ComPtr<Xaml::IWindow> window;
532 hr = windowStatics->get_Current(&window);
533 Q_ASSERT_SUCCEEDED(hr);
534 hr = window->Activate();
535 Q_ASSERT_SUCCEEDED(hr);
536
537 hr = window->get_CoreWindow(&d->coreWindow);
538 Q_ASSERT_SUCCEEDED(hr);
539
540 hr = d->coreWindow.As(&d->redirect);
541 Q_ASSERT_SUCCEEDED(hr);
542
543 hr = d->coreWindow->Activate();
544 Q_ASSERT_SUCCEEDED(hr);
545
546 Rect rect;
547 hr = d->coreWindow->get_Bounds(&rect);
548 Q_ASSERT_SUCCEEDED(hr);
549 d->logicalRect = QRectF(0.0f, 0.0f, rect.Width, rect.Height);
550 d->visibleRect = QRectF(0.0f, 0.0f, rect.Width, rect.Height);
551
552 // Orientation handling
553 ComPtr<IDisplayInformationStatics> displayInformationStatics;
554 hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Graphics_Display_DisplayInformation).Get(),
555 IID_PPV_ARGS(&displayInformationStatics));
556 Q_ASSERT_SUCCEEDED(hr);
557
558 hr = displayInformationStatics->GetForCurrentView(&d->displayInformation);
559 Q_ASSERT_SUCCEEDED(hr);
560
561 // Set native orientation
562 DisplayOrientations displayOrientation;
563 hr = d->displayInformation->get_NativeOrientation(&displayOrientation);
564 Q_ASSERT_SUCCEEDED(hr);
565 d->nativeOrientation = static_cast<Qt::ScreenOrientation>(static_cast<int>(qtOrientationsFromNative(displayOrientation)));
566 // Set initial pixel density
567 onDpiChanged(nullptr, nullptr);
568 d->orientation = d->nativeOrientation;
569
570 ComPtr<IApplicationViewStatics2> applicationViewStatics;
571 hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_ViewManagement_ApplicationView).Get(),
572 IID_PPV_ARGS(&applicationViewStatics));
573 RETURN_VOID_IF_FAILED("Could not get ApplicationViewStatics");
574
575 hr = applicationViewStatics->GetForCurrentView(&d->view);
576 RETURN_VOID_IF_FAILED("Could not access currentView");
577
578 d->canvas = Make<QWinRTCanvas>([this]() { return topWindow(); });
579
580 ComPtr<Xaml::IFrameworkElement> frameworkElement;
581 hr = d->canvas.As(&frameworkElement);
582 Q_ASSERT_SUCCEEDED(hr);
583 hr = frameworkElement->put_Width(d->logicalRect.width());
584 Q_ASSERT_SUCCEEDED(hr);
585 hr = frameworkElement->put_Height(d->logicalRect.height());
586 Q_ASSERT_SUCCEEDED(hr);
587
588 ComPtr<Xaml::IUIElement> uiElement;
589 hr = d->canvas.As(&uiElement);
590 Q_ASSERT_SUCCEEDED(hr);
591
592 #if QT_CONFIG(draganddrop)
593 QWinRTDrag::instance()->setUiElement(uiElement);
594 #endif
595 hr = window->put_Content(uiElement.Get());
596 Q_ASSERT_SUCCEEDED(hr);
597
598 d->cursor.reset(new QWinRTCursor);
599
600 hr = d->view.As(&d->view2);
601 Q_ASSERT_SUCCEEDED(hr);
602 }
603
~QWinRTScreen()604 QWinRTScreen::~QWinRTScreen()
605 {
606 Q_D(QWinRTScreen);
607 qCDebug(lcQpaWindows) << __FUNCTION__ << this;
608
609 // Unregister callbacks
610 HRESULT hr;
611 hr = QEventDispatcherWinRT::runOnXamlThread([this, d]() {
612 HRESULT hr;
613 for (QHash<CoreWindowCallbackRemover, EventRegistrationToken>::const_iterator i = d->windowTokens.begin(); i != d->windowTokens.end(); ++i) {
614 hr = (d->coreWindow.Get()->*i.key())(i.value());
615 Q_ASSERT_SUCCEEDED(hr);
616 }
617 for (QHash<DisplayCallbackRemover, EventRegistrationToken>::const_iterator i = d->displayTokens.begin(); i != d->displayTokens.end(); ++i) {
618 hr = (d->displayInformation.Get()->*i.key())(i.value());
619 Q_ASSERT_SUCCEEDED(hr);
620 }
621 for (QHash<RedirectorCallbackRemover, EventRegistrationToken>::const_iterator i = d->redirectTokens.begin(); i != d->redirectTokens.end(); ++i) {
622 hr = (d->redirect.Get()->*i.key())(i.value());
623 Q_ASSERT_SUCCEEDED(hr);
624 }
625 for (QHash<ApplicationView2CallbackRemover, EventRegistrationToken>::const_iterator i = d->view2Tokens.begin(); i != d->view2Tokens.end(); ++i) {
626 hr = (d->view2.Get()->*i.key())(i.value());
627 Q_ASSERT_SUCCEEDED(hr);
628 }
629 return hr;
630 });
631 RETURN_VOID_IF_FAILED("Failed to unregister screen event callbacks");
632 }
633
geometry() const634 QRect QWinRTScreen::geometry() const
635 {
636 Q_D(const QWinRTScreen);
637 return QRect(QPoint(), QSizeF(d->logicalRect.size() * d->scaleFactor).toSize());
638 }
639
availableGeometry() const640 QRect QWinRTScreen::availableGeometry() const
641 {
642 Q_D(const QWinRTScreen);
643 return QRectF((d->visibleRect.x() - d->logicalRect.x())* d->scaleFactor,
644 (d->visibleRect.y() - d->logicalRect.y()) * d->scaleFactor,
645 d->visibleRect.width() * d->scaleFactor,
646 d->visibleRect.height() * d->scaleFactor).toRect();
647 }
648
depth() const649 int QWinRTScreen::depth() const
650 {
651 return 32;
652 }
653
format() const654 QImage::Format QWinRTScreen::format() const
655 {
656 return QImage::Format_RGB32;
657 }
658
physicalSize() const659 QSizeF QWinRTScreen::physicalSize() const
660 {
661 Q_D(const QWinRTScreen);
662 return QSizeF(d->logicalRect.width() * d->scaleFactor / d->physicalDpi.first * qreal(25.4),
663 d->logicalRect.height() * d->scaleFactor / d->physicalDpi.second * qreal(25.4));
664 }
665
logicalDpi() const666 QDpi QWinRTScreen::logicalDpi() const
667 {
668 Q_D(const QWinRTScreen);
669 return QDpi(d->logicalDpi, d->logicalDpi);
670 }
671
scaleFactor() const672 qreal QWinRTScreen::scaleFactor() const
673 {
674 Q_D(const QWinRTScreen);
675 return d->scaleFactor;
676 }
677
cursor() const678 QPlatformCursor *QWinRTScreen::cursor() const
679 {
680 Q_D(const QWinRTScreen);
681 return d->cursor.data();
682 }
683
keyboardModifiers() const684 Qt::KeyboardModifiers QWinRTScreen::keyboardModifiers() const
685 {
686 Q_D(const QWinRTScreen);
687
688 Qt::KeyboardModifiers mods;
689 CoreVirtualKeyStates mod;
690 HRESULT hr = d->coreWindow->GetAsyncKeyState(VirtualKey_Shift, &mod);
691 Q_ASSERT_SUCCEEDED(hr);
692 if (mod & CoreVirtualKeyStates_Down)
693 mods |= Qt::ShiftModifier;
694 hr = d->coreWindow->GetAsyncKeyState(VirtualKey_Menu, &mod);
695 Q_ASSERT_SUCCEEDED(hr);
696 if (mod & CoreVirtualKeyStates_Down)
697 mods |= Qt::AltModifier;
698 hr = d->coreWindow->GetAsyncKeyState(VirtualKey_Control, &mod);
699 Q_ASSERT_SUCCEEDED(hr);
700 if (mod & CoreVirtualKeyStates_Down)
701 mods |= Qt::ControlModifier;
702 hr = d->coreWindow->GetAsyncKeyState(VirtualKey_LeftWindows, &mod);
703 Q_ASSERT_SUCCEEDED(hr);
704 if (mod & CoreVirtualKeyStates_Down) {
705 mods |= Qt::MetaModifier;
706 } else {
707 hr = d->coreWindow->GetAsyncKeyState(VirtualKey_RightWindows, &mod);
708 Q_ASSERT_SUCCEEDED(hr);
709 if (mod & CoreVirtualKeyStates_Down)
710 mods |= Qt::MetaModifier;
711 }
712 return mods;
713 }
714
nativeOrientation() const715 Qt::ScreenOrientation QWinRTScreen::nativeOrientation() const
716 {
717 Q_D(const QWinRTScreen);
718 return d->nativeOrientation;
719 }
720
orientation() const721 Qt::ScreenOrientation QWinRTScreen::orientation() const
722 {
723 Q_D(const QWinRTScreen);
724 return d->orientation;
725 }
726
coreWindow() const727 ICoreWindow *QWinRTScreen::coreWindow() const
728 {
729 Q_D(const QWinRTScreen);
730 return d->coreWindow.Get();
731 }
732
canvas() const733 Xaml::IDependencyObject *QWinRTScreen::canvas() const
734 {
735 Q_D(const QWinRTScreen);
736 Xaml::IDependencyObject *depCanvas;
737 if (SUCCEEDED(d->canvas.CopyTo(&depCanvas)))
738 return depCanvas;
739 return nullptr;
740 }
741
initialize()742 void QWinRTScreen::initialize()
743 {
744 Q_D(QWinRTScreen);
745 HRESULT hr;
746 hr = d->coreWindow->add_KeyDown(Callback<KeyHandler>(this, &QWinRTScreen::onKeyDown).Get(), &d->windowTokens[&ICoreWindow::remove_KeyDown]);
747 Q_ASSERT_SUCCEEDED(hr);
748 hr = d->coreWindow->add_KeyUp(Callback<KeyHandler>(this, &QWinRTScreen::onKeyUp).Get(), &d->windowTokens[&ICoreWindow::remove_KeyUp]);
749 Q_ASSERT_SUCCEEDED(hr);
750 hr = d->coreWindow->add_CharacterReceived(Callback<CharacterReceivedHandler>(this, &QWinRTScreen::onCharacterReceived).Get(), &d->windowTokens[&ICoreWindow::remove_CharacterReceived]);
751 Q_ASSERT_SUCCEEDED(hr);
752 hr = d->coreWindow->add_PointerEntered(Callback<PointerHandler>(this, &QWinRTScreen::onPointerEntered).Get(), &d->windowTokens[&ICoreWindow::remove_PointerEntered]);
753 Q_ASSERT_SUCCEEDED(hr);
754 hr = d->coreWindow->add_PointerExited(Callback<PointerHandler>(this, &QWinRTScreen::onPointerExited).Get(), &d->windowTokens[&ICoreWindow::remove_PointerExited]);
755 Q_ASSERT_SUCCEEDED(hr);
756 hr = d->coreWindow->add_PointerMoved(Callback<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &d->windowTokens[&ICoreWindow::remove_PointerMoved]);
757 Q_ASSERT_SUCCEEDED(hr);
758 hr = d->coreWindow->add_PointerPressed(Callback<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &d->windowTokens[&ICoreWindow::remove_PointerPressed]);
759 Q_ASSERT_SUCCEEDED(hr);
760 hr = d->coreWindow->add_PointerReleased(Callback<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &d->windowTokens[&ICoreWindow::remove_PointerReleased]);
761 Q_ASSERT_SUCCEEDED(hr);
762 hr = d->coreWindow->add_PointerWheelChanged(Callback<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &d->windowTokens[&ICoreWindow::remove_PointerWheelChanged]);
763 Q_ASSERT_SUCCEEDED(hr);
764 hr = d->view2->add_VisibleBoundsChanged(Callback<VisibleBoundsChangedHandler>(this, &QWinRTScreen::onWindowSizeChanged).Get(), &d->view2Tokens[&IApplicationView2::remove_VisibleBoundsChanged]);
765 Q_ASSERT_SUCCEEDED(hr);
766 hr = d->coreWindow->add_Activated(Callback<ActivatedHandler>(this, &QWinRTScreen::onActivated).Get(), &d->windowTokens[&ICoreWindow::remove_Activated]);
767 Q_ASSERT_SUCCEEDED(hr);
768 hr = d->coreWindow->add_Closed(Callback<ClosedHandler>(this, &QWinRTScreen::onClosed).Get(), &d->windowTokens[&ICoreWindow::remove_Closed]);
769 Q_ASSERT_SUCCEEDED(hr);
770 hr = d->coreWindow->add_VisibilityChanged(Callback<VisibilityChangedHandler>(this, &QWinRTScreen::onVisibilityChanged).Get(), &d->windowTokens[&ICoreWindow::remove_VisibilityChanged]);
771 Q_ASSERT_SUCCEEDED(hr);
772 hr = d->displayInformation->add_OrientationChanged(Callback<DisplayInformationHandler>(this, &QWinRTScreen::onOrientationChanged).Get(), &d->displayTokens[&IDisplayInformation::remove_OrientationChanged]);
773 Q_ASSERT_SUCCEEDED(hr);
774 hr = d->displayInformation->add_DpiChanged(Callback<DisplayInformationHandler>(this, &QWinRTScreen::onDpiChanged).Get(), &d->displayTokens[&IDisplayInformation::remove_DpiChanged]);
775 Q_ASSERT_SUCCEEDED(hr);
776 onOrientationChanged(nullptr, nullptr);
777 onVisibilityChanged(nullptr, nullptr);
778
779 hr = d->redirect->add_PointerRoutedReleased(Callback<RedirectHandler>(this, &QWinRTScreen::onRedirectReleased).Get(), &d->redirectTokens[&ICorePointerRedirector::remove_PointerRoutedReleased]);
780 Q_ASSERT_SUCCEEDED(hr);
781 }
782
setCursorRect(const QRectF & cursorRect)783 void QWinRTScreen::setCursorRect(const QRectF &cursorRect)
784 {
785 mCursorRect = cursorRect;
786 }
787
setKeyboardRect(const QRectF & keyboardRect)788 void QWinRTScreen::setKeyboardRect(const QRectF &keyboardRect)
789 {
790 Q_D(QWinRTScreen);
791 QRectF visibleRectF;
792 HRESULT hr;
793 Rect windowSize;
794
795 hr = d->coreWindow->get_Bounds(&windowSize);
796 if (FAILED(hr)) {
797 qErrnoWarning(hr, "Failed to get window bounds");
798 return;
799 }
800 d->logicalRect = QRectF(windowSize.X, windowSize.Y, windowSize.Width, windowSize.Height);
801 Rect visibleRect;
802 hr = d->view2->get_VisibleBounds(&visibleRect);
803 if (FAILED(hr)) {
804 qErrnoWarning(hr, "Failed to get window visible bounds");
805 return;
806 }
807 visibleRectF = QRectF(visibleRect.X, visibleRect.Y, visibleRect.Width, visibleRect.Height);
808 // if keyboard is snapped to the bottom of the screen and would cover the cursor the content is
809 // moved up to make it visible
810 if (keyboardRect.intersects(mCursorRect)
811 && qFuzzyCompare(geometry().height(), keyboardRect.y() + keyboardRect.height())) {
812 visibleRectF.moveTop(visibleRectF.top() - keyboardRect.height() / d->scaleFactor);
813 }
814 d->visibleRect = visibleRectF;
815
816 qCDebug(lcQpaWindows) << __FUNCTION__ << d->visibleRect;
817 QWindowSystemInterface::handleScreenGeometryChange(screen(), geometry(), availableGeometry());
818 QPlatformScreen::resizeMaximizedWindows();
819 handleExpose();
820 }
821
topWindow() const822 QWindow *QWinRTScreen::topWindow() const
823 {
824 Q_D(const QWinRTScreen);
825 return d->visibleWindows.isEmpty() ? 0 : d->visibleWindows.first();
826 }
827
windowAt(const QPoint & pos)828 QWindow *QWinRTScreen::windowAt(const QPoint &pos)
829 {
830 Q_D(const QWinRTScreen);
831 for (auto w : qAsConst(d->visibleWindows)) {
832 if (w->geometry().contains(pos))
833 return w;
834 }
835 qCDebug(lcQpaWindows) << __FUNCTION__ << ": No window found at:" << pos;
836 return nullptr;
837 }
838
addWindow(QWindow * window)839 void QWinRTScreen::addWindow(QWindow *window)
840 {
841 Q_D(QWinRTScreen);
842 qCDebug(lcQpaWindows) << __FUNCTION__ << window;
843 if (window == topWindow() || window->surfaceClass() == QSurface::Offscreen)
844 return;
845
846 d->visibleWindows.prepend(window);
847 const Qt::WindowType type = window->type();
848 if (type != Qt::Popup && type != Qt::ToolTip && type != Qt::Tool) {
849 updateWindowTitle(window->title());
850 QWindowSystemInterface::handleWindowActivated(window, Qt::OtherFocusReason);
851 }
852
853 handleExpose();
854 d->firstMouseMove = true;
855 QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents);
856
857 #if QT_CONFIG(draganddrop)
858 QWinRTDrag::instance()->setDropTarget(window);
859 #endif
860 }
861
removeWindow(QWindow * window)862 void QWinRTScreen::removeWindow(QWindow *window)
863 {
864 Q_D(QWinRTScreen);
865 qCDebug(lcQpaWindows) << __FUNCTION__ << window;
866
867 handleExpose();
868
869 const bool wasTopWindow = window == topWindow();
870 if (!d->visibleWindows.removeAll(window))
871 return;
872
873 const Qt::WindowType type = window->type();
874 if (wasTopWindow && type != Qt::Popup && type != Qt::ToolTip && type != Qt::Tool)
875 QWindowSystemInterface::handleWindowActivated(nullptr, Qt::OtherFocusReason);
876 QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents);
877 #if QT_CONFIG(draganddrop)
878 if (wasTopWindow)
879 QWinRTDrag::instance()->setDropTarget(topWindow());
880 #endif
881 }
882
raise(QWindow * window)883 void QWinRTScreen::raise(QWindow *window)
884 {
885 Q_D(QWinRTScreen);
886 d->visibleWindows.removeAll(window);
887 addWindow(window);
888 }
889
lower(QWindow * window)890 void QWinRTScreen::lower(QWindow *window)
891 {
892 Q_D(QWinRTScreen);
893 const bool wasTopWindow = window == topWindow();
894 if (wasTopWindow && d->visibleWindows.size() == 1)
895 return;
896 if (window->surfaceClass() == QSurface::Offscreen)
897 return;
898 d->visibleWindows.removeAll(window);
899 d->visibleWindows.append(window);
900 if (wasTopWindow)
901 QWindowSystemInterface::handleWindowActivated(window, Qt::OtherFocusReason);
902 handleExpose();
903 }
904
setMouseGrabWindow(QWinRTWindow * window,bool grab)905 bool QWinRTScreen::setMouseGrabWindow(QWinRTWindow *window, bool grab)
906 {
907 Q_D(QWinRTScreen);
908 qCDebug(lcQpaWindows) << __FUNCTION__ << window
909 << "(" << window->window()->objectName() << "):" << grab;
910
911 if (!grab || window == nullptr)
912 d->mouseGrabWindow = nullptr;
913 else if (d->mouseGrabWindow != window)
914 d->mouseGrabWindow = window;
915 return grab;
916 }
917
mouseGrabWindow() const918 QWinRTWindow *QWinRTScreen::mouseGrabWindow() const
919 {
920 Q_D(const QWinRTScreen);
921 return d->mouseGrabWindow;
922 }
923
setKeyboardGrabWindow(QWinRTWindow * window,bool grab)924 bool QWinRTScreen::setKeyboardGrabWindow(QWinRTWindow *window, bool grab)
925 {
926 Q_D(QWinRTScreen);
927 qCDebug(lcQpaWindows) << __FUNCTION__ << window
928 << "(" << window->window()->objectName() << "):" << grab;
929
930 if (!grab || window == nullptr)
931 d->keyboardGrabWindow = nullptr;
932 else if (d->keyboardGrabWindow != window)
933 d->keyboardGrabWindow = window;
934 return grab;
935 }
936
keyboardGrabWindow() const937 QWinRTWindow *QWinRTScreen::keyboardGrabWindow() const
938 {
939 Q_D(const QWinRTScreen);
940 return d->keyboardGrabWindow;
941 }
942
updateWindowTitle(const QString & title)943 void QWinRTScreen::updateWindowTitle(const QString &title)
944 {
945 Q_D(QWinRTScreen);
946
947 HStringReference titleRef(reinterpret_cast<LPCWSTR>(title.utf16()), title.length());
948 HRESULT hr = d->view->put_Title(titleRef.Get());
949 RETURN_VOID_IF_FAILED("Unable to set window title");
950 }
951
handleExpose()952 void QWinRTScreen::handleExpose()
953 {
954 Q_D(QWinRTScreen);
955 if (d->visibleWindows.isEmpty())
956 return;
957 QList<QWindow *>::const_iterator it = d->visibleWindows.constBegin();
958 QWindowSystemInterface::handleExposeEvent(*it, geometry());
959 while (++it != d->visibleWindows.constEnd())
960 QWindowSystemInterface::handleExposeEvent(*it, QRegion());
961 }
962
onKeyDown(ABI::Windows::UI::Core::ICoreWindow *,ABI::Windows::UI::Core::IKeyEventArgs * args)963 HRESULT QWinRTScreen::onKeyDown(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IKeyEventArgs *args)
964 {
965 Q_D(QWinRTScreen);
966 VirtualKey virtualKey;
967 HRESULT hr = args->get_VirtualKey(&virtualKey);
968 Q_ASSERT_SUCCEEDED(hr);
969 CorePhysicalKeyStatus status;
970 hr = args->get_KeyStatus(&status);
971 Q_ASSERT_SUCCEEDED(hr);
972
973 Qt::Key key = qKeyFromVirtual(virtualKey);
974
975 const bool wasPressed = d->activeKeys.contains(key);
976 if (wasPressed) {
977 if (!shouldAutoRepeat(key))
978 return S_OK;
979
980 d->activeKeys[key].isAutoRepeat = true;
981 // If the key was pressed before trigger a key release before the next key press
982 QWindowSystemInterface::handleExtendedKeyEvent(
983 topWindow(),
984 QEvent::KeyRelease,
985 key,
986 keyboardModifiers(),
987 !status.ScanCode ? -1 : status.ScanCode,
988 virtualKey,
989 0,
990 QString(),
991 d->activeKeys.value(key).isAutoRepeat);
992 } else {
993 d->activeKeys.insert(key, KeyInfo(virtualKey));
994 }
995
996 // Defer character key presses to onCharacterReceived
997 if (key == Qt::Key_unknown || (key >= Qt::Key_Space && key <= Qt::Key_ydiaeresis))
998 return S_OK;
999
1000 Qt::KeyboardModifiers modifiers = keyboardModifiers();
1001 // If the key actually pressed is a modifier key, then we remove its modifier key from the
1002 // state, since a modifier-key can't have itself as a modifier (see qwindowskeymapper.cpp)
1003 if (key == Qt::Key_Control)
1004 modifiers = modifiers ^ Qt::ControlModifier;
1005 else if (key == Qt::Key_Shift)
1006 modifiers = modifiers ^ Qt::ShiftModifier;
1007 else if (key == Qt::Key_Alt)
1008 modifiers = modifiers ^ Qt::AltModifier;
1009
1010 QWindowSystemInterface::handleExtendedKeyEvent(
1011 topWindow(),
1012 QEvent::KeyPress,
1013 key,
1014 modifiers,
1015 !status.ScanCode ? -1 : status.ScanCode,
1016 virtualKey,
1017 0,
1018 QString(),
1019 d->activeKeys.value(key).isAutoRepeat);
1020 return S_OK;
1021 }
1022
onKeyUp(ABI::Windows::UI::Core::ICoreWindow *,ABI::Windows::UI::Core::IKeyEventArgs * args)1023 HRESULT QWinRTScreen::onKeyUp(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IKeyEventArgs *args)
1024 {
1025 Q_D(QWinRTScreen);
1026 VirtualKey virtualKey;
1027 HRESULT hr = args->get_VirtualKey(&virtualKey);
1028 Q_ASSERT_SUCCEEDED(hr);
1029 CorePhysicalKeyStatus status;
1030 hr = args->get_KeyStatus(&status);
1031 Q_ASSERT_SUCCEEDED(hr);
1032
1033 Qt::Key key = qKeyFromVirtual(virtualKey);
1034 const KeyInfo info = d->activeKeys.take(key);
1035 QWindowSystemInterface::handleExtendedKeyEvent(
1036 topWindow(),
1037 QEvent::KeyRelease,
1038 key,
1039 keyboardModifiers(),
1040 !status.ScanCode ? -1 : status.ScanCode,
1041 virtualKey,
1042 0,
1043 info.text,
1044 false); // The final key release does not have autoRepeat set on Windows
1045 return S_OK;
1046 }
1047
onCharacterReceived(ICoreWindow *,ICharacterReceivedEventArgs * args)1048 HRESULT QWinRTScreen::onCharacterReceived(ICoreWindow *, ICharacterReceivedEventArgs *args)
1049 {
1050 Q_D(QWinRTScreen);
1051 quint32 keyCode;
1052 HRESULT hr = args->get_KeyCode(&keyCode);
1053 Q_ASSERT_SUCCEEDED(hr);
1054 CorePhysicalKeyStatus status;
1055 hr = args->get_KeyStatus(&status);
1056 Q_ASSERT_SUCCEEDED(hr);
1057
1058 // Don't generate character events for non-printables; the meta key stage is enough
1059 if (qIsNonPrintable(keyCode))
1060 return S_OK;
1061
1062 const Qt::KeyboardModifiers modifiers = keyboardModifiers();
1063 const Qt::Key key = qKeyFromCode(keyCode, modifiers);
1064 const QString text = QChar(keyCode);
1065 KeyInfo &info = d->activeKeys[key];
1066 info.text = text;
1067 QWindowSystemInterface::handleExtendedKeyEvent(
1068 topWindow(),
1069 QEvent::KeyPress,
1070 key,
1071 modifiers,
1072 !status.ScanCode ? -1 : status.ScanCode,
1073 info.virtualKey,
1074 0,
1075 text,
1076 info.isAutoRepeat);
1077 return S_OK;
1078 }
1079
onPointerEntered(ICoreWindow *,IPointerEventArgs * args)1080 HRESULT QWinRTScreen::onPointerEntered(ICoreWindow *, IPointerEventArgs *args)
1081 {
1082 Q_D(QWinRTScreen);
1083 qCDebug(lcQpaEvents) << __FUNCTION__;
1084
1085 ComPtr<IPointerPoint> pointerPoint;
1086 if (SUCCEEDED(args->get_CurrentPoint(&pointerPoint))) {
1087 // Assumes full-screen window
1088 Point point;
1089 pointerPoint->get_Position(&point);
1090 QPoint pos(point.X * d->scaleFactor, point.Y * d->scaleFactor);
1091
1092 d->currentTargetWindow = topWindow();
1093 if (d->mouseGrabWindow)
1094 d->currentTargetWindow = d->mouseGrabWindow.loadRelaxed()->window();
1095
1096 qCDebug(lcQpaEvents) << __FUNCTION__ << "handleEnterEvent" << d->currentTargetWindow << pos;
1097 QWindowSystemInterface::handleEnterEvent(d->currentTargetWindow, pos, pos);
1098 d->firstMouseMove = false;
1099 }
1100 return S_OK;
1101 }
1102
onPointerExited(ICoreWindow *,IPointerEventArgs * args)1103 HRESULT QWinRTScreen::onPointerExited(ICoreWindow *, IPointerEventArgs *args)
1104 {
1105 Q_D(QWinRTScreen);
1106 qCDebug(lcQpaEvents) << __FUNCTION__;
1107 ComPtr<IPointerPoint> pointerPoint;
1108 if (FAILED(args->get_CurrentPoint(&pointerPoint)))
1109 return E_INVALIDARG;
1110
1111 quint32 id;
1112 if (FAILED(pointerPoint->get_PointerId(&id)))
1113 return E_INVALIDARG;
1114
1115 d->touchPoints.remove(id);
1116
1117 if (d->mouseGrabWindow)
1118 d->currentTargetWindow = d->mouseGrabWindow.loadRelaxed()->window();
1119
1120 qCDebug(lcQpaEvents) << __FUNCTION__ << "handleLeaveEvent" << d->currentTargetWindow;
1121 QWindowSystemInterface::handleLeaveEvent(d->currentTargetWindow);
1122 d->currentTargetWindow = nullptr;
1123 return S_OK;
1124 }
1125
1126 // Required for qwinrtdrag.cpp
1127 ComPtr<IPointerPoint> qt_winrt_lastPointerPoint;
1128
onPointerUpdated(ICoreWindow *,IPointerEventArgs * args)1129 HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args)
1130 {
1131 Q_D(QWinRTScreen);
1132 qCDebug(lcQpaEvents) << __FUNCTION__;
1133 ComPtr<IPointerPoint> pointerPoint;
1134 if (FAILED(args->get_CurrentPoint(&pointerPoint)))
1135 return E_INVALIDARG;
1136
1137 qt_winrt_lastPointerPoint = pointerPoint;
1138 // Common traits - point, modifiers, properties
1139 Point point;
1140 pointerPoint->get_Position(&point);
1141 const QPointF pos(point.X * d->scaleFactor, point.Y * d->scaleFactor);
1142 QPointF localPos = pos;
1143
1144 const QPoint posPoint = pos.toPoint();
1145 QWindow *windowUnderPointer = windowAt(QHighDpiScaling::mapPositionFromNative(posPoint, this));
1146 d->currentTargetWindow = windowUnderPointer;
1147
1148 if (d->mouseGrabWindow)
1149 d->currentTargetWindow = d->mouseGrabWindow.loadRelaxed()->window();
1150
1151 if (d->currentTargetWindow) {
1152 const QPointF globalPosDelta = pos - posPoint;
1153 localPos = d->currentTargetWindow->mapFromGlobal(posPoint) + globalPosDelta;
1154 }
1155
1156 VirtualKeyModifiers modifiers;
1157 args->get_KeyModifiers(&modifiers);
1158 Qt::KeyboardModifiers mods;
1159 if (modifiers & VirtualKeyModifiers_Control)
1160 mods |= Qt::ControlModifier;
1161 if (modifiers & VirtualKeyModifiers_Menu)
1162 mods |= Qt::AltModifier;
1163 if (modifiers & VirtualKeyModifiers_Shift)
1164 mods |= Qt::ShiftModifier;
1165 if (modifiers & VirtualKeyModifiers_Windows)
1166 mods |= Qt::MetaModifier;
1167
1168 ComPtr<IPointerPointProperties> properties;
1169 if (FAILED(pointerPoint->get_Properties(&properties)))
1170 return E_INVALIDARG;
1171
1172 ComPtr<IPointerDevice> pointerDevice;
1173 HRESULT hr = pointerPoint->get_PointerDevice(&pointerDevice);
1174 RETURN_OK_IF_FAILED("Failed to get pointer device.");
1175
1176 PointerDeviceType pointerDeviceType;
1177 hr = pointerDevice->get_PointerDeviceType(&pointerDeviceType);
1178 RETURN_OK_IF_FAILED("Failed to get pointer device type.");
1179
1180 switch (pointerDeviceType) {
1181 case PointerDeviceType_Mouse: {
1182 qint32 delta;
1183 properties->get_MouseWheelDelta(&delta);
1184 if (delta) {
1185 boolean isHorizontal;
1186 properties->get_IsHorizontalMouseWheel(&isHorizontal);
1187 QPoint angleDelta(isHorizontal ? delta : 0, isHorizontal ? 0 : delta);
1188 qCDebug(lcQpaEvents) << __FUNCTION__ << "handleWheelEvent" << d->currentTargetWindow
1189 << localPos << pos << angleDelta << mods;
1190 QWindowSystemInterface::handleWheelEvent(d->currentTargetWindow, localPos, pos, QPoint(), angleDelta, mods);
1191 break;
1192 }
1193
1194 boolean isPressed;
1195 Qt::MouseButtons buttons = Qt::NoButton;
1196 properties->get_IsLeftButtonPressed(&isPressed);
1197 if (isPressed)
1198 buttons |= Qt::LeftButton;
1199
1200 properties->get_IsMiddleButtonPressed(&isPressed);
1201 if (isPressed)
1202 buttons |= Qt::MiddleButton;
1203
1204 properties->get_IsRightButtonPressed(&isPressed);
1205 if (isPressed)
1206 buttons |= Qt::RightButton;
1207
1208 properties->get_IsXButton1Pressed(&isPressed);
1209 if (isPressed)
1210 buttons |= Qt::XButton1;
1211
1212 properties->get_IsXButton2Pressed(&isPressed);
1213 if (isPressed)
1214 buttons |= Qt::XButton2;
1215
1216 // In case of a mouse grab we have to store the target of a press event
1217 // to be able to send one additional release event to this target when the mouse
1218 // button is released. This is a similar approach to AutoMouseCapture in the
1219 // windows qpa backend. Otherwise the release might not be propagated and the original
1220 // press event receiver considers a button to still be pressed, as in Qt Quick Controls 1
1221 // menus.
1222 if (buttons != Qt::NoButton && d->currentPressWindow == nullptr && !d->mouseGrabWindow)
1223 d->currentPressWindow = windowUnderPointer;
1224 if (buttons == Qt::NoButton && d->currentPressWindow && d->mouseGrabWindow) {
1225 const QPointF globalPosDelta = pos - posPoint;
1226 const QPointF localPressPos = d->currentPressWindow->mapFromGlobal(posPoint) + globalPosDelta;
1227
1228 qCDebug(lcQpaEvents) << __FUNCTION__ << "handleMouseEvent" << d->currentPressWindow
1229 << localPressPos << pos << buttons << mods;
1230 QWindowSystemInterface::handleMouseEvent(d->currentPressWindow, localPressPos, pos, buttons, mods);
1231 d->currentPressWindow = nullptr;
1232 }
1233 // If the mouse button is released outside of a window, targetWindow is 0, but the event
1234 // has to be delivered to the window, that initially received the mouse press. Do not reset
1235 // d->currentTargetWindow though, as it is used (and reset) in onPointerExited.
1236 if (buttons == Qt::NoButton && d->currentPressWindow && !d->currentTargetWindow) {
1237 d->currentTargetWindow = d->currentPressWindow;
1238 d->currentPressWindow = nullptr;
1239 }
1240
1241 qCDebug(lcQpaEvents) << __FUNCTION__ << "handleMouseEvent" << d->currentTargetWindow
1242 << localPos << pos << buttons << mods;
1243 QWindowSystemInterface::handleMouseEvent(d->currentTargetWindow, localPos, pos, buttons, mods);
1244
1245 break;
1246 }
1247 case PointerDeviceType_Pen:
1248 case PointerDeviceType_Touch: {
1249 if (!d->touchDevice) {
1250 d->touchDevice = new QTouchDevice;
1251 d->touchDevice->setName(QStringLiteral("WinRTTouchScreen"));
1252 d->touchDevice->setType(QTouchDevice::TouchScreen);
1253 d->touchDevice->setCapabilities(QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::Pressure | QTouchDevice::NormalizedPosition);
1254 QWindowSystemInterface::registerTouchDevice(d->touchDevice);
1255 }
1256
1257 quint32 id;
1258 pointerPoint->get_PointerId(&id);
1259
1260 Rect area;
1261 properties->get_ContactRect(&area);
1262
1263 float pressure;
1264 properties->get_Pressure(&pressure);
1265
1266 boolean isPressed;
1267 pointerPoint->get_IsInContact(&isPressed);
1268
1269 // Devices like the Hololens set a static pressure of 0.0 or 0.5
1270 // (depending on the image) independent of the pressed state.
1271 // In those cases we need to synthesize the pressure value. To our
1272 // knowledge this does not apply to pens
1273 if (pointerDeviceType == PointerDeviceType_Touch && (pressure == 0.0f || pressure == 0.5f))
1274 pressure = isPressed ? 1. : 0.;
1275
1276 const QRectF areaRect(area.X * d->scaleFactor, area.Y * d->scaleFactor,
1277 area.Width * d->scaleFactor, area.Height * d->scaleFactor);
1278
1279 QHash<quint32, QWindowSystemInterface::TouchPoint>::iterator it = d->touchPoints.find(id);
1280 if (it == d->touchPoints.end()) {
1281 it = d->touchPoints.insert(id, QWindowSystemInterface::TouchPoint());
1282 it.value().id = id;
1283 }
1284
1285 const bool wasPressEvent = isPressed && it.value().pressure == 0.;
1286 if (wasPressEvent)
1287 it.value().state = Qt::TouchPointPressed;
1288 else if (!isPressed && it.value().pressure > 0.)
1289 it.value().state = Qt::TouchPointReleased;
1290 else if (it.value().area == areaRect)
1291 it.value().state = Qt::TouchPointStationary;
1292 else
1293 it.value().state = Qt::TouchPointMoved;
1294
1295 it.value().area = areaRect;
1296 it.value().normalPosition = QPointF(point.X/d->logicalRect.width(), point.Y/d->logicalRect.height());
1297 it.value().pressure = pressure;
1298
1299 qCDebug(lcQpaEvents) << __FUNCTION__ << "handleTouchEvent" << d->currentTargetWindow
1300 << d->touchDevice << d->touchPoints.values() << mods;
1301 QWindowSystemInterface::handleTouchEvent(d->currentTargetWindow, d->touchDevice, d->touchPoints.values(), mods);
1302 if (wasPressEvent)
1303 it.value().state = Qt::TouchPointStationary;
1304
1305 // Fall-through for pen to generate tablet event
1306 if (pointerDeviceType != PointerDeviceType_Pen)
1307 break;
1308
1309 boolean isEraser;
1310 properties->get_IsEraser(&isEraser);
1311 int pointerType = isEraser ? 3 : 1;
1312
1313 float xTilt;
1314 properties->get_XTilt(&xTilt);
1315
1316 float yTilt;
1317 properties->get_YTilt(&yTilt);
1318
1319 float rotation;
1320 properties->get_Twist(&rotation);
1321
1322 qCDebug(lcQpaEvents) << __FUNCTION__ << "handleTabletEvent" << d->currentTargetWindow
1323 << isPressed << pos << pointerType << pressure << xTilt << yTilt
1324 << rotation << id << mods;
1325 QWindowSystemInterface::handleTabletEvent(d->currentTargetWindow, isPressed, pos, pos, 0,
1326 pointerType, pressure, xTilt, yTilt,
1327 0, rotation, 0, id, mods);
1328
1329 break;
1330 }
1331 }
1332
1333 return S_OK;
1334 }
1335
emulateMouseMove(const QPointF & point,MousePositionTransition transition)1336 void QWinRTScreen::emulateMouseMove(const QPointF &point, MousePositionTransition transition)
1337 {
1338 Q_D(QWinRTScreen);
1339 qCDebug(lcQpaEvents) << __FUNCTION__ << point << transition;
1340 if (transition == MousePositionTransition::StayedOut)
1341 return;
1342 qt_winrt_lastPointerPoint = nullptr;
1343 const QPointF pos(point.x() * d->scaleFactor, point.y() * d->scaleFactor);
1344 QPointF localPos = pos;
1345
1346 const QPoint posPoint = pos.toPoint();
1347 QWindow *windowUnderPointer = windowAt(QHighDpiScaling::mapPositionFromNative(posPoint, this));
1348 d->currentTargetWindow = windowUnderPointer;
1349
1350 if (d->mouseGrabWindow)
1351 d->currentTargetWindow = d->mouseGrabWindow.loadRelaxed()->window();
1352
1353 if (d->currentTargetWindow) {
1354 const QPointF globalPosDelta = pos - posPoint;
1355 localPos = d->currentTargetWindow->mapFromGlobal(posPoint) + globalPosDelta;
1356 }
1357
1358 // In case of a mouse grab we have to store the target of a press event
1359 // to be able to send one additional release event to this target when the mouse
1360 // button is released. This is a similar approach to AutoMouseCapture in the
1361 // windows qpa backend. Otherwise the release might not be propagated and the original
1362 // press event receiver considers a button to still be pressed, as in Qt Quick Controls 1
1363 // menus.
1364 if (d->currentPressWindow && d->mouseGrabWindow) {
1365 const QPointF globalPosDelta = pos - posPoint;
1366 const QPointF localPressPos = d->currentPressWindow->mapFromGlobal(posPoint) + globalPosDelta;
1367
1368 qCDebug(lcQpaEvents) << __FUNCTION__ << "handleMouseEvent" << d->currentPressWindow
1369 << localPressPos << pos << Qt::NoButton << Qt::NoModifier;
1370 QWindowSystemInterface::handleMouseEvent(d->currentPressWindow, localPressPos, pos,
1371 Qt::NoButton, Qt::NoModifier);
1372 d->currentPressWindow = nullptr;
1373 }
1374 // If the mouse button is released outside of a window, targetWindow is 0, but the event
1375 // has to be delivered to the window, that initially received the mouse press. Do not reset
1376 // d->currentTargetWindow though, as it is used (and reset) in onPointerExited.
1377 if (d->currentPressWindow && !d->currentTargetWindow) {
1378 d->currentTargetWindow = d->currentPressWindow;
1379 d->currentPressWindow = nullptr;
1380 }
1381
1382 if (transition == MousePositionTransition::MovedOut) {
1383 qCDebug(lcQpaEvents) << __FUNCTION__ << "handleLeaveEvent" << d->currentTargetWindow;
1384 QWindowSystemInterface::handleLeaveEvent(d->currentTargetWindow);
1385 return;
1386 }
1387
1388 if (transition == MousePositionTransition::MovedIn || d->firstMouseMove) {
1389 qCDebug(lcQpaEvents) << __FUNCTION__ << "handleEnterEvent" << d->currentTargetWindow
1390 << localPos << pos;
1391 QWindowSystemInterface::handleEnterEvent(d->currentTargetWindow, localPos, pos);
1392 d->firstMouseMove = false;
1393 }
1394 qCDebug(lcQpaEvents) << __FUNCTION__ << "handleMouseEvent" << d->currentTargetWindow
1395 << localPos << pos << Qt::NoButton << Qt::NoModifier;
1396 QWindowSystemInterface::handleMouseEvent(d->currentTargetWindow, localPos, pos, Qt::NoButton,
1397 Qt::NoModifier);
1398 }
1399
setResizePending()1400 void QWinRTScreen::setResizePending()
1401 {
1402 Q_D(QWinRTScreen);
1403 d->resizePending = true;
1404 }
1405
resizePending() const1406 bool QWinRTScreen::resizePending() const
1407 {
1408 Q_D(const QWinRTScreen);
1409 return d->resizePending;
1410 }
1411
onActivated(ICoreWindow *,IWindowActivatedEventArgs * args)1412 HRESULT QWinRTScreen::onActivated(ICoreWindow *, IWindowActivatedEventArgs *args)
1413 {
1414 Q_D(QWinRTScreen);
1415 qCDebug(lcQpaWindows) << __FUNCTION__;
1416
1417 CoreWindowActivationState activationState;
1418 args->get_WindowActivationState(&activationState);
1419 if (activationState == CoreWindowActivationState_Deactivated) {
1420 QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive);
1421 return S_OK;
1422 }
1423
1424 QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive);
1425
1426 // Activate topWindow
1427 if (!d->visibleWindows.isEmpty()) {
1428 Qt::FocusReason focusReason = activationState == CoreWindowActivationState_PointerActivated
1429 ? Qt::MouseFocusReason : Qt::ActiveWindowFocusReason;
1430 QWindowSystemInterface::handleWindowActivated(topWindow(), focusReason);
1431 }
1432 return S_OK;
1433 }
1434
onClosed(ICoreWindow *,ICoreWindowEventArgs *)1435 HRESULT QWinRTScreen::onClosed(ICoreWindow *, ICoreWindowEventArgs *)
1436 {
1437 qCDebug(lcQpaWindows) << __FUNCTION__;
1438
1439 foreach (QWindow *w, QGuiApplication::topLevelWindows())
1440 QWindowSystemInterface::handleCloseEvent(w);
1441 return S_OK;
1442 }
1443
onVisibilityChanged(ICoreWindow *,IVisibilityChangedEventArgs * args)1444 HRESULT QWinRTScreen::onVisibilityChanged(ICoreWindow *, IVisibilityChangedEventArgs *args)
1445 {
1446 Q_D(QWinRTScreen);
1447 boolean visible;
1448 HRESULT hr = args ? args->get_Visible(&visible) : d->coreWindow->get_Visible(&visible);
1449 RETURN_OK_IF_FAILED("Failed to get visibility.");
1450 qCDebug(lcQpaWindows) << __FUNCTION__ << visible;
1451 QWindowSystemInterface::handleApplicationStateChanged(visible ? Qt::ApplicationActive : Qt::ApplicationHidden);
1452 if (visible) {
1453 handleExpose();
1454 onWindowSizeChanged(nullptr, nullptr);
1455 }
1456 return S_OK;
1457 }
1458
onOrientationChanged(IDisplayInformation *,IInspectable *)1459 HRESULT QWinRTScreen::onOrientationChanged(IDisplayInformation *, IInspectable *)
1460 {
1461 Q_D(QWinRTScreen);
1462 qCDebug(lcQpaWindows) << __FUNCTION__;
1463 DisplayOrientations displayOrientation;
1464 HRESULT hr = d->displayInformation->get_CurrentOrientation(&displayOrientation);
1465 RETURN_OK_IF_FAILED("Failed to get current orientations.");
1466
1467 Qt::ScreenOrientation newOrientation = static_cast<Qt::ScreenOrientation>(static_cast<int>(qtOrientationsFromNative(displayOrientation)));
1468 if (d->orientation != newOrientation) {
1469 d->orientation = newOrientation;
1470 qCDebug(lcQpaWindows) << " New orientation:" << newOrientation;
1471 onWindowSizeChanged(nullptr, nullptr);
1472 QWindowSystemInterface::handleScreenOrientationChange(screen(), d->orientation);
1473 handleExpose(); // Clean broken frames caused by race between Qt and ANGLE
1474 }
1475 return S_OK;
1476 }
1477
onDpiChanged(IDisplayInformation *,IInspectable *)1478 HRESULT QWinRTScreen::onDpiChanged(IDisplayInformation *, IInspectable *)
1479 {
1480 Q_D(QWinRTScreen);
1481
1482 HRESULT hr;
1483 ResolutionScale resolutionScale;
1484 hr = d->displayInformation->get_ResolutionScale(&resolutionScale);
1485 d->scaleFactor = qreal(resolutionScale) / 100;
1486
1487 qCDebug(lcQpaWindows) << __FUNCTION__ << "Scale Factor:" << d->scaleFactor;
1488
1489 RETURN_OK_IF_FAILED("Failed to get scale factor");
1490
1491 FLOAT dpi;
1492 hr = d->displayInformation->get_LogicalDpi(&dpi);
1493 RETURN_OK_IF_FAILED("Failed to get logical DPI.");
1494 d->logicalDpi = dpi;
1495
1496 hr = d->displayInformation->get_RawDpiX(&dpi);
1497 RETURN_OK_IF_FAILED("Failed to get x raw DPI.");
1498 d->physicalDpi.first = dpi ? dpi : 96.0;
1499
1500 hr = d->displayInformation->get_RawDpiY(&dpi);
1501 RETURN_OK_IF_FAILED("Failed to get y raw DPI.");
1502 d->physicalDpi.second = dpi ? dpi : 96.0;
1503 qCDebug(lcQpaWindows) << __FUNCTION__ << "Logical DPI:" << d->logicalDpi
1504 << "Physical DPI:" << d->physicalDpi;
1505
1506 return S_OK;
1507 }
1508
onRedirectReleased(ICorePointerRedirector *,IPointerEventArgs * args)1509 HRESULT QWinRTScreen::onRedirectReleased(ICorePointerRedirector *, IPointerEventArgs *args)
1510 {
1511 // When dragging ends with a non-mouse input device then onRedirectRelease is invoked.
1512 // QTBUG-58781
1513 qCDebug(lcQpaEvents) << __FUNCTION__;
1514 return onPointerUpdated(nullptr, args);
1515 }
1516
onWindowSizeChanged(IApplicationView * w,IInspectable *)1517 HRESULT QWinRTScreen::onWindowSizeChanged(IApplicationView *w, IInspectable *)
1518 {
1519 Q_D(QWinRTScreen);
1520
1521 HRESULT hr;
1522 Rect windowSize;
1523
1524 hr = d->coreWindow->get_Bounds(&windowSize);
1525 RETURN_OK_IF_FAILED("Failed to get window bounds");
1526 d->logicalRect = QRectF(windowSize.X, windowSize.Y, windowSize.Width, windowSize.Height);
1527
1528 Rect visibleRect;
1529 hr = d->view2->get_VisibleBounds(&visibleRect);
1530 RETURN_OK_IF_FAILED("Failed to get window visible bounds");
1531 d->visibleRect = QRectF(visibleRect.X, visibleRect.Y, visibleRect.Width, visibleRect.Height);
1532
1533 qCDebug(lcQpaWindows) << __FUNCTION__ << d->logicalRect;
1534 QWindowSystemInterface::handleScreenGeometryChange(screen(), geometry(), availableGeometry());
1535 QPlatformScreen::resizeMaximizedWindows();
1536 handleExpose();
1537 // If we "emulate" a resize, w will be nullptr.Checking w shows whether it's a real resize
1538 if (w)
1539 d->resizePending = false;
1540 return S_OK;
1541 }
1542
1543 QT_END_NAMESPACE
1544