qt6-bb10/src/plugins/platforms/winrt/qwinrtscreen.cpp

1168 lines
40 KiB
C++

/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or later as published by the Free
** Software Foundation and appearing in the file LICENSE.GPL included in
** the packaging of this file. Please review the following information to
** ensure the GNU General Public License version 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qwinrtscreen.h"
#include "qwinrtbackingstore.h"
#include "qwinrtinputcontext.h"
#include "qwinrtcursor.h"
#include <private/qeventdispatcher_winrt_p.h>
#include <QtGui/QSurfaceFormat>
#include <QtGui/QGuiApplication>
#include <qpa/qwindowsysteminterface.h>
#include <QtCore/qt_windows.h>
#include <QtCore/qfunctions_winrt.h>
#include <functional>
#include <wrl.h>
#include <windows.system.h>
#include <Windows.Applicationmodel.h>
#include <Windows.ApplicationModel.core.h>
#include <windows.devices.input.h>
#include <windows.ui.h>
#include <windows.ui.core.h>
#include <windows.ui.input.h>
#include <windows.ui.xaml.h>
#include <windows.ui.viewmanagement.h>
#include <windows.graphics.display.h>
#include <windows.foundation.h>
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
using namespace ABI::Windows::ApplicationModel;
using namespace ABI::Windows::ApplicationModel::Core;
using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::System;
using namespace ABI::Windows::UI;
using namespace ABI::Windows::UI::Core;
using namespace ABI::Windows::UI::Input;
using namespace ABI::Windows::UI::ViewManagement;
using namespace ABI::Windows::Devices::Input;
using namespace ABI::Windows::Graphics::Display;
typedef ITypedEventHandler<CoreWindow*, WindowActivatedEventArgs*> ActivatedHandler;
typedef ITypedEventHandler<CoreWindow*, CoreWindowEventArgs*> ClosedHandler;
typedef ITypedEventHandler<CoreWindow*, CharacterReceivedEventArgs*> CharacterReceivedHandler;
typedef ITypedEventHandler<CoreWindow*, InputEnabledEventArgs*> InputEnabledHandler;
typedef ITypedEventHandler<CoreWindow*, KeyEventArgs*> KeyHandler;
typedef ITypedEventHandler<CoreWindow*, PointerEventArgs*> PointerHandler;
typedef ITypedEventHandler<CoreWindow*, WindowSizeChangedEventArgs*> SizeChangedHandler;
typedef ITypedEventHandler<CoreWindow*, VisibilityChangedEventArgs*> VisibilityChangedHandler;
typedef ITypedEventHandler<DisplayInformation*, IInspectable*> DisplayInformationHandler;
#ifdef Q_OS_WINPHONE
typedef ITypedEventHandler<StatusBar*, IInspectable*> StatusBarHandler;
#endif
QT_BEGIN_NAMESPACE
static inline Qt::ScreenOrientations qtOrientationsFromNative(DisplayOrientations native)
{
Qt::ScreenOrientations orientations = Qt::PrimaryOrientation;
if (native & DisplayOrientations_Portrait)
orientations |= Qt::PortraitOrientation;
if (native & DisplayOrientations_PortraitFlipped)
orientations |= Qt::InvertedPortraitOrientation;
if (native & DisplayOrientations_Landscape)
orientations |= Qt::LandscapeOrientation;
if (native & DisplayOrientations_LandscapeFlipped)
orientations |= Qt::InvertedLandscapeOrientation;
return orientations;
}
static inline DisplayOrientations nativeOrientationsFromQt(Qt::ScreenOrientations orientation)
{
DisplayOrientations native = DisplayOrientations_None;
if (orientation & Qt::PortraitOrientation)
native |= DisplayOrientations_Portrait;
if (orientation & Qt::InvertedPortraitOrientation)
native |= DisplayOrientations_PortraitFlipped;
if (orientation & Qt::LandscapeOrientation)
native |= DisplayOrientations_Landscape;
if (orientation & Qt::InvertedLandscapeOrientation)
native |= DisplayOrientations_LandscapeFlipped;
return native;
}
static inline bool qIsNonPrintable(quint32 keyCode)
{
switch (keyCode) {
case '\b':
case '\n':
case '\t':
case '\r':
case '\v':
case '\f':
return true;
default:
return false;
}
}
// Return Qt meta key from VirtualKey
static inline Qt::Key qKeyFromVirtual(VirtualKey key)
{
switch (key) {
default:
return Qt::Key_unknown;
// Non-printable characters
case VirtualKey_Enter:
return Qt::Key_Enter;
case VirtualKey_Tab:
return Qt::Key_Tab;
case VirtualKey_Back:
return Qt::Key_Backspace;
// Modifiers
case VirtualKey_Shift:
case VirtualKey_LeftShift:
case VirtualKey_RightShift:
return Qt::Key_Shift;
case VirtualKey_Control:
case VirtualKey_LeftControl:
case VirtualKey_RightControl:
return Qt::Key_Control;
case VirtualKey_Menu:
case VirtualKey_LeftMenu:
case VirtualKey_RightMenu:
return Qt::Key_Alt;
case VirtualKey_LeftWindows:
case VirtualKey_RightWindows:
return Qt::Key_Meta;
// Toggle keys
case VirtualKey_CapitalLock:
return Qt::Key_CapsLock;
case VirtualKey_NumberKeyLock:
return Qt::Key_NumLock;
case VirtualKey_Scroll:
return Qt::Key_ScrollLock;
// East-Asian language keys
case VirtualKey_Kana:
//case VirtualKey_Hangul: // Same enum as Kana
return Qt::Key_Kana_Shift;
case VirtualKey_Junja:
return Qt::Key_Hangul_Jeonja;
case VirtualKey_Kanji:
//case VirtualKey_Hanja: // Same enum as Kanji
return Qt::Key_Kanji;
case VirtualKey_ModeChange:
return Qt::Key_Mode_switch;
case VirtualKey_Convert:
return Qt::Key_Henkan;
case VirtualKey_NonConvert:
return Qt::Key_Muhenkan;
// Misc. keys
case VirtualKey_Cancel:
return Qt::Key_Cancel;
case VirtualKey_Clear:
return Qt::Key_Clear;
case VirtualKey_Application:
return Qt::Key_ApplicationLeft;
case VirtualKey_Sleep:
return Qt::Key_Sleep;
case VirtualKey_Pause:
return Qt::Key_Pause;
case VirtualKey_PageUp:
return Qt::Key_PageUp;
case VirtualKey_PageDown:
return Qt::Key_PageDown;
case VirtualKey_End:
return Qt::Key_End;
case VirtualKey_Home:
return Qt::Key_Home;
case VirtualKey_Left:
return Qt::Key_Left;
case VirtualKey_Up:
return Qt::Key_Up;
case VirtualKey_Right:
return Qt::Key_Right;
case VirtualKey_Down:
return Qt::Key_Down;
case VirtualKey_Select:
return Qt::Key_Select;
case VirtualKey_Print:
return Qt::Key_Print;
case VirtualKey_Execute:
return Qt::Key_Execute;
case VirtualKey_Insert:
return Qt::Key_Insert;
case VirtualKey_Delete:
return Qt::Key_Delete;
case VirtualKey_Help:
return Qt::Key_Help;
case VirtualKey_Snapshot:
return Qt::Key_Camera;
case VirtualKey_Escape:
return Qt::Key_Escape;
// Function Keys
case VirtualKey_F1:
return Qt::Key_F1;
case VirtualKey_F2:
return Qt::Key_F2;
case VirtualKey_F3:
return Qt::Key_F3;
case VirtualKey_F4:
return Qt::Key_F4;
case VirtualKey_F5:
return Qt::Key_F5;
case VirtualKey_F6:
return Qt::Key_F6;
case VirtualKey_F7:
return Qt::Key_F7;
case VirtualKey_F8:
return Qt::Key_F8;
case VirtualKey_F9:
return Qt::Key_F9;
case VirtualKey_F10:
return Qt::Key_F10;
case VirtualKey_F11:
return Qt::Key_F11;
case VirtualKey_F12:
return Qt::Key_F12;
case VirtualKey_F13:
return Qt::Key_F13;
case VirtualKey_F14:
return Qt::Key_F14;
case VirtualKey_F15:
return Qt::Key_F15;
case VirtualKey_F16:
return Qt::Key_F16;
case VirtualKey_F17:
return Qt::Key_F17;
case VirtualKey_F18:
return Qt::Key_F18;
case VirtualKey_F19:
return Qt::Key_F19;
case VirtualKey_F20:
return Qt::Key_F20;
case VirtualKey_F21:
return Qt::Key_F21;
case VirtualKey_F22:
return Qt::Key_F22;
case VirtualKey_F23:
return Qt::Key_F23;
case VirtualKey_F24:
return Qt::Key_F24;
// Character keys
case VirtualKey_Space:
return Qt::Key_Space;
case VirtualKey_Number0:
case VirtualKey_NumberPad0:
return Qt::Key_0;
case VirtualKey_Number1:
case VirtualKey_NumberPad1:
return Qt::Key_1;
case VirtualKey_Number2:
case VirtualKey_NumberPad2:
return Qt::Key_2;
case VirtualKey_Number3:
case VirtualKey_NumberPad3:
return Qt::Key_3;
case VirtualKey_Number4:
case VirtualKey_NumberPad4:
return Qt::Key_4;
case VirtualKey_Number5:
case VirtualKey_NumberPad5:
return Qt::Key_5;
case VirtualKey_Number6:
case VirtualKey_NumberPad6:
return Qt::Key_6;
case VirtualKey_Number7:
case VirtualKey_NumberPad7:
return Qt::Key_7;
case VirtualKey_Number8:
case VirtualKey_NumberPad8:
return Qt::Key_8;
case VirtualKey_Number9:
case VirtualKey_NumberPad9:
return Qt::Key_9;
case VirtualKey_A:
return Qt::Key_A;
case VirtualKey_B:
return Qt::Key_B;
case VirtualKey_C:
return Qt::Key_C;
case VirtualKey_D:
return Qt::Key_D;
case VirtualKey_E:
return Qt::Key_E;
case VirtualKey_F:
return Qt::Key_F;
case VirtualKey_G:
return Qt::Key_G;
case VirtualKey_H:
return Qt::Key_H;
case VirtualKey_I:
return Qt::Key_I;
case VirtualKey_J:
return Qt::Key_J;
case VirtualKey_K:
return Qt::Key_K;
case VirtualKey_L:
return Qt::Key_L;
case VirtualKey_M:
return Qt::Key_M;
case VirtualKey_N:
return Qt::Key_N;
case VirtualKey_O:
return Qt::Key_O;
case VirtualKey_P:
return Qt::Key_P;
case VirtualKey_Q:
return Qt::Key_Q;
case VirtualKey_R:
return Qt::Key_R;
case VirtualKey_S:
return Qt::Key_S;
case VirtualKey_T:
return Qt::Key_T;
case VirtualKey_U:
return Qt::Key_U;
case VirtualKey_V:
return Qt::Key_V;
case VirtualKey_W:
return Qt::Key_W;
case VirtualKey_X:
return Qt::Key_X;
case VirtualKey_Y:
return Qt::Key_Y;
case VirtualKey_Z:
return Qt::Key_Z;
case VirtualKey_Multiply:
return Qt::Key_9;
case VirtualKey_Add:
return Qt::Key_9;
case VirtualKey_Separator:
return Qt::Key_9;
case VirtualKey_Subtract:
return Qt::Key_9;
case VirtualKey_Decimal:
return Qt::Key_9;
case VirtualKey_Divide:
return Qt::Key_9;
/* Keys with no matching Qt enum (?)
case VirtualKey_None:
case VirtualKey_LeftButton:
case VirtualKey_RightButton:
case VirtualKey_MiddleButton:
case VirtualKey_XButton1:
case VirtualKey_XButton2:
case VirtualKey_Final:
case VirtualKey_Accept:*/
}
}
static inline Qt::Key qKeyFromCode(quint32 code, int mods)
{
if (code >= 'a' && code <= 'z')
code = toupper(code);
if ((mods & Qt::ControlModifier) != 0) {
if (code >= 0 && code <= 31) // Ctrl+@..Ctrl+A..CTRL+Z..Ctrl+_
code += '@'; // to @..A..Z.._
}
return static_cast<Qt::Key>(code & 0xff);
}
typedef HRESULT (__stdcall ICoreWindow::*CoreWindowCallbackRemover)(EventRegistrationToken);
uint qHash(CoreWindowCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); }
typedef HRESULT (__stdcall IDisplayInformation::*DisplayCallbackRemover)(EventRegistrationToken);
uint qHash(DisplayCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); }
#ifdef Q_OS_WINPHONE
typedef HRESULT (__stdcall IStatusBar::*StatusBarCallbackRemover)(EventRegistrationToken);
uint qHash(StatusBarCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); }
#endif
class QWinRTScreenPrivate
{
public:
QTouchDevice *touchDevice;
ComPtr<ICoreWindow> coreWindow;
ComPtr<Xaml::IDependencyObject> canvas;
ComPtr<IApplicationView> view;
ComPtr<IDisplayInformation> displayInformation;
#ifdef Q_OS_WINPHONE
ComPtr<IStatusBar> statusBar;
#endif
QScopedPointer<QWinRTCursor> cursor;
QHash<quint32, QWindowSystemInterface::TouchPoint> touchPoints;
QSizeF logicalSize;
QSurfaceFormat surfaceFormat;
qreal logicalDpi;
QDpi physicalDpi;
qreal scaleFactor;
Qt::ScreenOrientation nativeOrientation;
Qt::ScreenOrientation orientation;
QList<QWindow *> visibleWindows;
#ifndef Q_OS_WINPHONE
QHash<quint32, QPair<Qt::Key, QString>> activeKeys;
#endif
QHash<CoreWindowCallbackRemover, EventRegistrationToken> windowTokens;
QHash<DisplayCallbackRemover, EventRegistrationToken> displayTokens;
#ifdef Q_OS_WINPHONE
QHash<StatusBarCallbackRemover, EventRegistrationToken> statusBarTokens;
#endif
};
// To be called from the XAML thread
QWinRTScreen::QWinRTScreen(Xaml::IWindow *xamlWindow)
: d_ptr(new QWinRTScreenPrivate)
{
Q_D(QWinRTScreen);
d->orientation = Qt::PrimaryOrientation;
d->touchDevice = Q_NULLPTR;
HRESULT hr;
hr = xamlWindow->get_CoreWindow(&d->coreWindow);
Q_ASSERT_SUCCEEDED(hr);
hr = d->coreWindow->Activate();
Q_ASSERT_SUCCEEDED(hr);
Rect rect;
hr = d->coreWindow->get_Bounds(&rect);
Q_ASSERT_SUCCEEDED(hr);
d->logicalSize = QSizeF(rect.Width, rect.Height);
hr = d->coreWindow->add_KeyDown(Callback<KeyHandler>(this, &QWinRTScreen::onKeyDown).Get(), &d->windowTokens[&ICoreWindow::remove_KeyDown]);
Q_ASSERT_SUCCEEDED(hr);
hr = d->coreWindow->add_KeyUp(Callback<KeyHandler>(this, &QWinRTScreen::onKeyUp).Get(), &d->windowTokens[&ICoreWindow::remove_KeyUp]);
Q_ASSERT_SUCCEEDED(hr);
hr = d->coreWindow->add_CharacterReceived(Callback<CharacterReceivedHandler>(this, &QWinRTScreen::onCharacterReceived).Get(), &d->windowTokens[&ICoreWindow::remove_CharacterReceived]);
Q_ASSERT_SUCCEEDED(hr);
hr = d->coreWindow->add_PointerEntered(Callback<PointerHandler>(this, &QWinRTScreen::onPointerEntered).Get(), &d->windowTokens[&ICoreWindow::remove_PointerEntered]);
Q_ASSERT_SUCCEEDED(hr);
hr = d->coreWindow->add_PointerExited(Callback<PointerHandler>(this, &QWinRTScreen::onPointerExited).Get(), &d->windowTokens[&ICoreWindow::remove_PointerExited]);
Q_ASSERT_SUCCEEDED(hr);
hr = d->coreWindow->add_PointerMoved(Callback<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &d->windowTokens[&ICoreWindow::remove_PointerMoved]);
Q_ASSERT_SUCCEEDED(hr);
hr = d->coreWindow->add_PointerPressed(Callback<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &d->windowTokens[&ICoreWindow::remove_PointerPressed]);
Q_ASSERT_SUCCEEDED(hr);
hr = d->coreWindow->add_PointerReleased(Callback<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &d->windowTokens[&ICoreWindow::remove_PointerReleased]);
Q_ASSERT_SUCCEEDED(hr);
hr = d->coreWindow->add_PointerWheelChanged(Callback<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &d->windowTokens[&ICoreWindow::remove_PointerWheelChanged]);
Q_ASSERT_SUCCEEDED(hr);
#ifndef Q_OS_WINPHONE
hr = d->coreWindow->add_SizeChanged(Callback<SizeChangedHandler>(this, &QWinRTScreen::onSizeChanged).Get(), &d->windowTokens[&ICoreWindow::remove_SizeChanged]);
Q_ASSERT_SUCCEEDED(hr);
#endif
hr = d->coreWindow->add_Activated(Callback<ActivatedHandler>(this, &QWinRTScreen::onActivated).Get(), &d->windowTokens[&ICoreWindow::remove_Activated]);
Q_ASSERT_SUCCEEDED(hr);
hr = d->coreWindow->add_Closed(Callback<ClosedHandler>(this, &QWinRTScreen::onClosed).Get(), &d->windowTokens[&ICoreWindow::remove_Closed]);
Q_ASSERT_SUCCEEDED(hr);
hr = d->coreWindow->add_VisibilityChanged(Callback<VisibilityChangedHandler>(this, &QWinRTScreen::onVisibilityChanged).Get(), &d->windowTokens[&ICoreWindow::remove_VisibilityChanged]);
Q_ASSERT_SUCCEEDED(hr);
// Orientation handling
ComPtr<IDisplayInformationStatics> displayInformationStatics;
hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Graphics_Display_DisplayInformation).Get(),
IID_PPV_ARGS(&displayInformationStatics));
Q_ASSERT_SUCCEEDED(hr);
hr = displayInformationStatics->GetForCurrentView(&d->displayInformation);
Q_ASSERT_SUCCEEDED(hr);
// Set native orientation
DisplayOrientations displayOrientation;
hr = d->displayInformation->get_NativeOrientation(&displayOrientation);
Q_ASSERT_SUCCEEDED(hr);
d->nativeOrientation = static_cast<Qt::ScreenOrientation>(static_cast<int>(qtOrientationsFromNative(displayOrientation)));
hr = d->displayInformation->add_OrientationChanged(Callback<DisplayInformationHandler>(this, &QWinRTScreen::onOrientationChanged).Get(), &d->displayTokens[&IDisplayInformation::remove_OrientationChanged]);
Q_ASSERT_SUCCEEDED(hr);
hr = d->displayInformation->add_DpiChanged(Callback<DisplayInformationHandler>(this, &QWinRTScreen::onDpiChanged).Get(), &d->displayTokens[&IDisplayInformation::remove_DpiChanged]);
Q_ASSERT_SUCCEEDED(hr);
// Set initial orientation & pixel density
onDpiChanged(Q_NULLPTR, Q_NULLPTR);
d->orientation = d->nativeOrientation;
onOrientationChanged(Q_NULLPTR, Q_NULLPTR);
ComPtr<IApplicationViewStatics2> applicationViewStatics;
hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_ViewManagement_ApplicationView).Get(),
IID_PPV_ARGS(&applicationViewStatics));
RETURN_VOID_IF_FAILED("Could not get ApplicationViewStatics");
hr = applicationViewStatics->GetForCurrentView(&d->view);
RETURN_VOID_IF_FAILED("Could not access currentView");
// Create a canvas and set it as the window content. Eventually, this should have its own method so multiple "screens" can be added
ComPtr<Xaml::Controls::ICanvas> canvas;
hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Controls_Canvas).Get(), &canvas);
Q_ASSERT_SUCCEEDED(hr);
ComPtr<Xaml::IFrameworkElement> frameworkElement;
hr = canvas.As(&frameworkElement);
Q_ASSERT_SUCCEEDED(hr);
hr = frameworkElement->put_Width(d->logicalSize.width());
Q_ASSERT_SUCCEEDED(hr);
hr = frameworkElement->put_Height(d->logicalSize.height());
Q_ASSERT_SUCCEEDED(hr);
ComPtr<Xaml::IUIElement> uiElement;
hr = canvas.As(&uiElement);
Q_ASSERT_SUCCEEDED(hr);
hr = xamlWindow->put_Content(uiElement.Get());
Q_ASSERT_SUCCEEDED(hr);
hr = canvas.As(&d->canvas);
Q_ASSERT_SUCCEEDED(hr);
d->cursor.reset(new QWinRTCursor);
#ifdef Q_OS_WINPHONE
ComPtr<IStatusBarStatics> statusBarStatics;
hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_ViewManagement_StatusBar).Get(),
IID_PPV_ARGS(&statusBarStatics));
Q_ASSERT_SUCCEEDED(hr);
hr = statusBarStatics->GetForCurrentView(&d->statusBar);
Q_ASSERT_SUCCEEDED(hr);
hr = d->statusBar->add_Showing(Callback<StatusBarHandler>(this, &QWinRTScreen::onStatusBarShowing).Get(), &d->statusBarTokens[&IStatusBar::remove_Showing]);
Q_ASSERT_SUCCEEDED(hr);
hr = d->statusBar->add_Hiding(Callback<StatusBarHandler>(this, &QWinRTScreen::onStatusBarHiding).Get(), &d->statusBarTokens[&IStatusBar::remove_Hiding]);
Q_ASSERT_SUCCEEDED(hr);
#endif // Q_OS_WINPHONE
}
QWinRTScreen::~QWinRTScreen()
{
Q_D(QWinRTScreen);
// Unregister callbacks
HRESULT hr;
hr = QEventDispatcherWinRT::runOnXamlThread([this, d]() {
HRESULT hr;
for (QHash<CoreWindowCallbackRemover, EventRegistrationToken>::const_iterator i = d->windowTokens.begin(); i != d->windowTokens.end(); ++i) {
hr = (d->coreWindow.Get()->*i.key())(i.value());
Q_ASSERT_SUCCEEDED(hr);
}
for (QHash<DisplayCallbackRemover, EventRegistrationToken>::const_iterator i = d->displayTokens.begin(); i != d->displayTokens.end(); ++i) {
hr = (d->displayInformation.Get()->*i.key())(i.value());
Q_ASSERT_SUCCEEDED(hr);
}
#ifdef Q_OS_WINPHONE
for (QHash<StatusBarCallbackRemover, EventRegistrationToken>::const_iterator i = d->statusBarTokens.begin(); i != d->statusBarTokens.end(); ++i) {
hr = (d->statusBar.Get()->*i.key())(i.value());
Q_ASSERT_SUCCEEDED(hr);
}
#endif //Q_OS_WINPHONE
return hr;
});
RETURN_VOID_IF_FAILED("Failed to unregister screen event callbacks");
}
QRect QWinRTScreen::geometry() const
{
Q_D(const QWinRTScreen);
return QRect(QPoint(), (d->logicalSize * d->scaleFactor).toSize());
}
#ifdef Q_OS_WINPHONE
QRect QWinRTScreen::availableGeometry() const
{
Q_D(const QWinRTScreen);
QRect statusBar;
QEventDispatcherWinRT::runOnXamlThread([d, &statusBar]() {
HRESULT hr;
Rect rect;
hr = d->statusBar->get_OccludedRect(&rect);
Q_ASSERT_SUCCEEDED(hr);
statusBar.setRect(qRound(rect.X * d->scaleFactor),
qRound(rect.Y * d->scaleFactor),
qRound(rect.Width * d->scaleFactor),
qRound(rect.Height * d->scaleFactor));
return S_OK;
});
return geometry().adjusted(
d->orientation == Qt::LandscapeOrientation ? statusBar.width() : 0,
d->orientation == Qt::PortraitOrientation ? statusBar.height() : 0,
d->orientation == Qt::InvertedLandscapeOrientation ? -statusBar.width() : 0,
0);
}
#endif //Q_OS_WINPHONE
int QWinRTScreen::depth() const
{
return 32;
}
QImage::Format QWinRTScreen::format() const
{
return QImage::Format_ARGB32_Premultiplied;
}
QSizeF QWinRTScreen::physicalSize() const
{
Q_D(const QWinRTScreen);
return QSizeF(d->logicalSize.width() * d->scaleFactor / d->physicalDpi.first * qreal(25.4),
d->logicalSize.height() * d->scaleFactor / d->physicalDpi.second * qreal(25.4));
}
QDpi QWinRTScreen::logicalDpi() const
{
Q_D(const QWinRTScreen);
return QDpi(d->logicalDpi, d->logicalDpi);
}
qreal QWinRTScreen::scaleFactor() const
{
Q_D(const QWinRTScreen);
return d->scaleFactor;
}
QPlatformCursor *QWinRTScreen::cursor() const
{
Q_D(const QWinRTScreen);
return d->cursor.data();
}
Qt::KeyboardModifiers QWinRTScreen::keyboardModifiers() const
{
Q_D(const QWinRTScreen);
Qt::KeyboardModifiers mods;
CoreVirtualKeyStates mod;
d->coreWindow->GetAsyncKeyState(VirtualKey_Shift, &mod);
if (mod == CoreVirtualKeyStates_Down)
mods |= Qt::ShiftModifier;
d->coreWindow->GetAsyncKeyState(VirtualKey_Menu, &mod);
if (mod == CoreVirtualKeyStates_Down)
mods |= Qt::AltModifier;
d->coreWindow->GetAsyncKeyState(VirtualKey_Control, &mod);
if (mod == CoreVirtualKeyStates_Down)
mods |= Qt::ControlModifier;
d->coreWindow->GetAsyncKeyState(VirtualKey_LeftWindows, &mod);
if (mod == CoreVirtualKeyStates_Down) {
mods |= Qt::MetaModifier;
} else {
d->coreWindow->GetAsyncKeyState(VirtualKey_RightWindows, &mod);
if (mod == CoreVirtualKeyStates_Down)
mods |= Qt::MetaModifier;
}
return mods;
}
Qt::ScreenOrientation QWinRTScreen::nativeOrientation() const
{
Q_D(const QWinRTScreen);
return d->nativeOrientation;
}
Qt::ScreenOrientation QWinRTScreen::orientation() const
{
Q_D(const QWinRTScreen);
return d->orientation;
}
ICoreWindow *QWinRTScreen::coreWindow() const
{
Q_D(const QWinRTScreen);
return d->coreWindow.Get();
}
Xaml::IDependencyObject *QWinRTScreen::canvas() const
{
Q_D(const QWinRTScreen);
return d->canvas.Get();
}
#ifdef Q_OS_WINPHONE
void QWinRTScreen::setStatusBarVisibility(bool visible, QWindow *window)
{
Q_D(QWinRTScreen);
if (!window || (window->flags() & Qt::WindowType_Mask) != Qt::Window)
return;
QEventDispatcherWinRT::runOnXamlThread([d, visible]() {
HRESULT hr;
ComPtr<IAsyncAction> op;
if (visible)
hr = d->statusBar->ShowAsync(&op);
else
hr = d->statusBar->HideAsync(&op);
Q_ASSERT_SUCCEEDED(hr);
return S_OK;
});
}
#endif //Q_OS_WINPHONE
QWindow *QWinRTScreen::topWindow() const
{
Q_D(const QWinRTScreen);
return d->visibleWindows.isEmpty() ? 0 : d->visibleWindows.first();
}
void QWinRTScreen::addWindow(QWindow *window)
{
Q_D(QWinRTScreen);
if (window == topWindow())
return;
#ifdef Q_OS_WINPHONE
if (window->visibility() != QWindow::Maximized && window->visibility() != QWindow::Windowed)
setStatusBarVisibility(false, window);
#endif
d->visibleWindows.prepend(window);
QWindowSystemInterface::handleWindowActivated(window, Qt::OtherFocusReason);
handleExpose();
}
void QWinRTScreen::removeWindow(QWindow *window)
{
Q_D(QWinRTScreen);
#ifdef Q_OS_WINPHONE
if (window->visibility() == QWindow::Minimized)
setStatusBarVisibility(false, window);
#endif
const bool wasTopWindow = window == topWindow();
if (!d->visibleWindows.removeAll(window))
return;
if (wasTopWindow)
QWindowSystemInterface::handleWindowActivated(window, Qt::OtherFocusReason);
handleExpose();
}
void QWinRTScreen::raise(QWindow *window)
{
Q_D(QWinRTScreen);
d->visibleWindows.removeAll(window);
addWindow(window);
}
void QWinRTScreen::lower(QWindow *window)
{
Q_D(QWinRTScreen);
const bool wasTopWindow = window == topWindow();
if (wasTopWindow && d->visibleWindows.size() == 1)
return;
d->visibleWindows.removeAll(window);
d->visibleWindows.append(window);
if (wasTopWindow)
QWindowSystemInterface::handleWindowActivated(window, Qt::OtherFocusReason);
handleExpose();
}
void QWinRTScreen::updateWindowTitle()
{
Q_D(QWinRTScreen);
QWindow *window = topWindow();
if (!window)
return;
const QString title = window->title();
HStringReference titleRef(reinterpret_cast<LPCWSTR>(title.utf16()), title.length());
HRESULT hr = d->view->put_Title(titleRef.Get());
RETURN_VOID_IF_FAILED("Unable to set window title");
}
void QWinRTScreen::handleExpose()
{
Q_D(QWinRTScreen);
if (d->visibleWindows.isEmpty())
return;
QList<QWindow *>::const_iterator it = d->visibleWindows.constBegin();
QWindowSystemInterface::handleExposeEvent(*it, geometry());
while (++it != d->visibleWindows.constEnd())
QWindowSystemInterface::handleExposeEvent(*it, QRegion());
}
HRESULT QWinRTScreen::onKeyDown(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IKeyEventArgs *args)
{
VirtualKey virtualKey;
args->get_VirtualKey(&virtualKey);
Qt::Key key = qKeyFromVirtual(virtualKey);
// Defer character key presses to onCharacterReceived
if (key == Qt::Key_unknown || (key >= Qt::Key_Space && key <= Qt::Key_ydiaeresis))
return S_OK;
QWindowSystemInterface::handleKeyEvent(topWindow(), QEvent::KeyPress, key, keyboardModifiers());
return S_OK;
}
HRESULT QWinRTScreen::onKeyUp(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IKeyEventArgs *args)
{
Qt::KeyboardModifiers mods = keyboardModifiers();
#ifndef Q_OS_WINPHONE
Q_D(QWinRTScreen);
CorePhysicalKeyStatus status; // Look for a pressed character key
if (SUCCEEDED(args->get_KeyStatus(&status)) && d->activeKeys.contains(status.ScanCode)) {
QPair<Qt::Key, QString> keyStatus = d->activeKeys.take(status.ScanCode);
QWindowSystemInterface::handleKeyEvent(topWindow(), QEvent::KeyRelease,
keyStatus.first, mods, keyStatus.second);
return S_OK;
}
#endif // !Q_OS_WINPHONE
VirtualKey virtualKey;
args->get_VirtualKey(&virtualKey);
QWindowSystemInterface::handleKeyEvent(topWindow(), QEvent::KeyRelease,
qKeyFromVirtual(virtualKey), mods);
return S_OK;
}
HRESULT QWinRTScreen::onCharacterReceived(ICoreWindow *, ICharacterReceivedEventArgs *args)
{
quint32 keyCode;
args->get_KeyCode(&keyCode);
// Don't generate character events for non-printables; the meta key stage is enough
if (qIsNonPrintable(keyCode))
return S_OK;
Qt::KeyboardModifiers mods = keyboardModifiers();
Qt::Key key = qKeyFromCode(keyCode, mods);
QString text = QChar(keyCode);
QWindowSystemInterface::handleKeyEvent(topWindow(), QEvent::KeyPress, key, mods, text);
#ifndef Q_OS_WINPHONE
Q_D(QWinRTScreen);
CorePhysicalKeyStatus status; // Defer release to onKeyUp for physical keys
if (SUCCEEDED(args->get_KeyStatus(&status)) && !status.IsKeyReleased) {
d->activeKeys.insert(status.ScanCode, qMakePair(key, text));
return S_OK;
}
#endif // !Q_OS_WINPHONE
QWindowSystemInterface::handleKeyEvent(topWindow(), QEvent::KeyRelease, key, mods, text);
return S_OK;
}
HRESULT QWinRTScreen::onPointerEntered(ICoreWindow *, IPointerEventArgs *args)
{
Q_D(QWinRTScreen);
ComPtr<IPointerPoint> pointerPoint;
if (SUCCEEDED(args->get_CurrentPoint(&pointerPoint))) {
// Assumes full-screen window
Point point;
pointerPoint->get_Position(&point);
QPoint pos(point.X * d->scaleFactor, point.Y * d->scaleFactor);
QWindowSystemInterface::handleEnterEvent(topWindow(), pos, pos);
}
return S_OK;
}
HRESULT QWinRTScreen::onPointerExited(ICoreWindow *, IPointerEventArgs *)
{
QWindowSystemInterface::handleLeaveEvent(0);
return S_OK;
}
HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args)
{
Q_D(QWinRTScreen);
ComPtr<IPointerPoint> pointerPoint;
if (FAILED(args->get_CurrentPoint(&pointerPoint)))
return E_INVALIDARG;
// Common traits - point, modifiers, properties
Point point;
pointerPoint->get_Position(&point);
QPointF pos(point.X * d->scaleFactor, point.Y * d->scaleFactor);
VirtualKeyModifiers modifiers;
args->get_KeyModifiers(&modifiers);
Qt::KeyboardModifiers mods;
if (modifiers & VirtualKeyModifiers_Control)
mods |= Qt::ControlModifier;
if (modifiers & VirtualKeyModifiers_Menu)
mods |= Qt::AltModifier;
if (modifiers & VirtualKeyModifiers_Shift)
mods |= Qt::ShiftModifier;
if (modifiers & VirtualKeyModifiers_Windows)
mods |= Qt::MetaModifier;
ComPtr<IPointerPointProperties> properties;
if (FAILED(pointerPoint->get_Properties(&properties)))
return E_INVALIDARG;
ComPtr<IPointerDevice> pointerDevice;
HRESULT hr = pointerPoint->get_PointerDevice(&pointerDevice);
RETURN_OK_IF_FAILED("Failed to get pointer device.");
PointerDeviceType pointerDeviceType;
hr = pointerDevice->get_PointerDeviceType(&pointerDeviceType);
RETURN_OK_IF_FAILED("Failed to get pointer device type.");
switch (pointerDeviceType) {
case PointerDeviceType_Mouse: {
qint32 delta;
properties->get_MouseWheelDelta(&delta);
if (delta) {
boolean isHorizontal;
properties->get_IsHorizontalMouseWheel(&isHorizontal);
QPoint angleDelta(isHorizontal ? delta : 0, isHorizontal ? 0 : delta);
QWindowSystemInterface::handleWheelEvent(topWindow(), pos, pos, QPoint(), angleDelta, mods);
break;
}
boolean isPressed;
Qt::MouseButtons buttons = Qt::NoButton;
properties->get_IsLeftButtonPressed(&isPressed);
if (isPressed)
buttons |= Qt::LeftButton;
properties->get_IsMiddleButtonPressed(&isPressed);
if (isPressed)
buttons |= Qt::MiddleButton;
properties->get_IsRightButtonPressed(&isPressed);
if (isPressed)
buttons |= Qt::RightButton;
properties->get_IsXButton1Pressed(&isPressed);
if (isPressed)
buttons |= Qt::XButton1;
properties->get_IsXButton2Pressed(&isPressed);
if (isPressed)
buttons |= Qt::XButton2;
QWindowSystemInterface::handleMouseEvent(topWindow(), pos, pos, buttons, mods);
break;
}
case PointerDeviceType_Touch: {
if (!d->touchDevice) {
d->touchDevice = new QTouchDevice;
d->touchDevice->setName(QStringLiteral("WinRTTouchScreen"));
d->touchDevice->setType(QTouchDevice::TouchScreen);
d->touchDevice->setCapabilities(QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::Pressure | QTouchDevice::NormalizedPosition);
QWindowSystemInterface::registerTouchDevice(d->touchDevice);
}
quint32 id;
pointerPoint->get_PointerId(&id);
Rect area;
properties->get_ContactRect(&area);
float pressure;
properties->get_Pressure(&pressure);
QHash<quint32, QWindowSystemInterface::TouchPoint>::iterator it = d->touchPoints.find(id);
if (it != d->touchPoints.end()) {
boolean isPressed;
#ifndef Q_OS_WINPHONE
pointerPoint->get_IsInContact(&isPressed);
#else
properties->get_IsLeftButtonPressed(&isPressed); // IsInContact not reliable on phone
#endif
it.value().state = isPressed ? Qt::TouchPointMoved : Qt::TouchPointReleased;
} else {
it = d->touchPoints.insert(id, QWindowSystemInterface::TouchPoint());
it.value().state = Qt::TouchPointPressed;
it.value().id = id;
}
it.value().area = QRectF(area.X * d->scaleFactor, area.Y * d->scaleFactor,
area.Width * d->scaleFactor, area.Height * d->scaleFactor);
it.value().normalPosition = QPointF(point.X/d->logicalSize.width(), point.Y/d->logicalSize.height());
it.value().pressure = pressure;
QWindowSystemInterface::handleTouchEvent(topWindow(), d->touchDevice, d->touchPoints.values(), mods);
// Remove released points, station others
for (QHash<quint32, QWindowSystemInterface::TouchPoint>::iterator i = d->touchPoints.begin(); i != d->touchPoints.end();) {
if (i.value().state == Qt::TouchPointReleased)
i = d->touchPoints.erase(i);
else
(i++).value().state = Qt::TouchPointStationary;
}
break;
}
case PointerDeviceType_Pen: {
quint32 id;
pointerPoint->get_PointerId(&id);
boolean isPressed;
pointerPoint->get_IsInContact(&isPressed);
boolean isEraser;
properties->get_IsEraser(&isEraser);
int pointerType = isEraser ? 3 : 1;
float pressure;
properties->get_Pressure(&pressure);
float xTilt;
properties->get_XTilt(&xTilt);
float yTilt;
properties->get_YTilt(&yTilt);
float rotation;
properties->get_Twist(&rotation);
QWindowSystemInterface::handleTabletEvent(topWindow(), isPressed, pos, pos, 0,
pointerType, pressure, xTilt, yTilt,
0, rotation, 0, id, mods);
break;
}
}
return S_OK;
}
HRESULT QWinRTScreen::onSizeChanged(ICoreWindow *, IWindowSizeChangedEventArgs *)
{
Q_D(QWinRTScreen);
Rect size;
HRESULT hr;
hr = d->coreWindow->get_Bounds(&size);
RETURN_OK_IF_FAILED("Failed to get window bounds");
d->logicalSize = QSizeF(size.Width, size.Height);
QWindowSystemInterface::handleScreenGeometryChange(screen(), geometry(), availableGeometry());
QPlatformScreen::resizeMaximizedWindows();
handleExpose();
return S_OK;
}
HRESULT QWinRTScreen::onActivated(ICoreWindow *, IWindowActivatedEventArgs *args)
{
Q_D(QWinRTScreen);
CoreWindowActivationState activationState;
args->get_WindowActivationState(&activationState);
if (activationState == CoreWindowActivationState_Deactivated) {
QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive);
return S_OK;
}
// Activate topWindow
if (!d->visibleWindows.isEmpty()) {
Qt::FocusReason focusReason = activationState == CoreWindowActivationState_PointerActivated
? Qt::MouseFocusReason : Qt::ActiveWindowFocusReason;
QWindowSystemInterface::handleWindowActivated(topWindow(), focusReason);
}
return S_OK;
}
HRESULT QWinRTScreen::onClosed(ICoreWindow *, ICoreWindowEventArgs *)
{
foreach (QWindow *w, QGuiApplication::topLevelWindows())
QWindowSystemInterface::handleCloseEvent(w);
return S_OK;
}
HRESULT QWinRTScreen::onVisibilityChanged(ICoreWindow *, IVisibilityChangedEventArgs *args)
{
boolean visible;
args->get_Visible(&visible);
QWindowSystemInterface::handleApplicationStateChanged(visible ? Qt::ApplicationActive : Qt::ApplicationHidden);
if (visible)
handleExpose();
return S_OK;
}
HRESULT QWinRTScreen::onOrientationChanged(IDisplayInformation *, IInspectable *)
{
Q_D(QWinRTScreen);
DisplayOrientations displayOrientation;
HRESULT hr = d->displayInformation->get_CurrentOrientation(&displayOrientation);
RETURN_OK_IF_FAILED("Failed to get current orientations.");
Qt::ScreenOrientation newOrientation = static_cast<Qt::ScreenOrientation>(static_cast<int>(qtOrientationsFromNative(displayOrientation)));
if (d->orientation != newOrientation) {
d->orientation = newOrientation;
#ifdef Q_OS_WINPHONE
onSizeChanged(nullptr, nullptr);
#endif
QWindowSystemInterface::handleScreenOrientationChange(screen(), d->orientation);
handleExpose(); // Clean broken frames caused by race between Qt and ANGLE
}
return S_OK;
}
HRESULT QWinRTScreen::onDpiChanged(IDisplayInformation *, IInspectable *)
{
Q_D(QWinRTScreen);
HRESULT hr;
#ifdef Q_OS_WINPHONE
ComPtr<IDisplayInformation2> displayInformation;
hr = d->displayInformation.As(&displayInformation);
RETURN_OK_IF_FAILED("Failed to cast display information.");
hr = displayInformation->get_RawPixelsPerViewPixel(&d->scaleFactor);
#else
ResolutionScale resolutionScale;
hr = d->displayInformation->get_ResolutionScale(&resolutionScale);
d->scaleFactor = qreal(resolutionScale) / 100;
#endif
RETURN_OK_IF_FAILED("Failed to get scale factor");
FLOAT dpi;
hr = d->displayInformation->get_LogicalDpi(&dpi);
RETURN_OK_IF_FAILED("Failed to get logical DPI.");
d->logicalDpi = dpi;
hr = d->displayInformation->get_RawDpiX(&dpi);
RETURN_OK_IF_FAILED("Failed to get x raw DPI.");
d->physicalDpi.first = dpi ? dpi : 96.0;
hr = d->displayInformation->get_RawDpiY(&dpi);
RETURN_OK_IF_FAILED("Failed to get y raw DPI.");
d->physicalDpi.second = dpi ? dpi : 96.0;
return S_OK;
}
#ifdef Q_OS_WINPHONE
HRESULT QWinRTScreen::onStatusBarShowing(IStatusBar *, IInspectable *)
{
onSizeChanged(nullptr, nullptr);
return S_OK;
}
HRESULT QWinRTScreen::onStatusBarHiding(IStatusBar *, IInspectable *)
{
onSizeChanged(nullptr, nullptr);
return S_OK;
}
#endif //Q_OS_WINPHONE
QT_END_NAMESPACE