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