From fc0f784e54d5dce72cc6a7e4b1fad243dadfcd76 Mon Sep 17 00:00:00 2001 From: Andrew Knight Date: Mon, 30 Sep 2013 01:31:27 +0300 Subject: Windows RT and Windows Phone QPA Change-Id: I6ab8af31f73439172e43fb709831821482b1cc99 Done-with: Kamil Trzcinski Done-with: Oliver Wolff Reviewed-by: Friedemann Kleint --- src/plugins/platforms/winrt/qwinrtscreen.cpp | 1012 ++++++++++++++++++++++++++ 1 file changed, 1012 insertions(+) create mode 100644 src/plugins/platforms/winrt/qwinrtscreen.cpp (limited to 'src/plugins/platforms/winrt/qwinrtscreen.cpp') diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp new file mode 100644 index 0000000000..93c2736238 --- /dev/null +++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp @@ -0,0 +1,1012 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 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 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwinrtscreen.h" + +#include "qwinrtbackingstore.h" +#include "qwinrtinputcontext.h" +#include "qwinrtcursor.h" +#include "qwinrteglcontext.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace Microsoft::WRL; +using namespace Microsoft::WRL::Wrappers; +using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::System; +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 ActivatedHandler; +typedef ITypedEventHandler ClosedHandler; +typedef ITypedEventHandler CharacterReceivedHandler; +typedef ITypedEventHandler InputEnabledHandler; +typedef ITypedEventHandler KeyHandler; +typedef ITypedEventHandler PointerHandler; +typedef ITypedEventHandler SizeChangedHandler; +typedef ITypedEventHandler VisibilityChangedHandler; +typedef ITypedEventHandler AutomationProviderRequestedHandler; + +QT_BEGIN_NAMESPACE + +static inline Qt::ScreenOrientation qOrientationFromNative(DisplayOrientations orientation) +{ + switch (orientation) { + default: + case DisplayOrientations_None: + return Qt::PrimaryOrientation; + case DisplayOrientations_Landscape: + return Qt::LandscapeOrientation; + case DisplayOrientations_LandscapeFlipped: + return Qt::InvertedLandscapeOrientation; + case DisplayOrientations_Portrait: + return Qt::PortraitOrientation; + case DisplayOrientations_PortraitFlipped: + return Qt::InvertedPortraitOrientation; + } +} + +static inline Qt::KeyboardModifiers qKeyModifiers(ICoreWindow *window) +{ + Qt::KeyboardModifiers mods; + CoreVirtualKeyStates mod; + window->GetAsyncKeyState(VirtualKey_Shift, &mod); + if (mod == CoreVirtualKeyStates_Down) + mods |= Qt::ShiftModifier; + window->GetAsyncKeyState(VirtualKey_Menu, &mod); + if (mod == CoreVirtualKeyStates_Down) + mods |= Qt::AltModifier; + window->GetAsyncKeyState(VirtualKey_Control, &mod); + if (mod == CoreVirtualKeyStates_Down) + mods |= Qt::ControlModifier; + window->GetAsyncKeyState(VirtualKey_LeftWindows, &mod); + if (mod == CoreVirtualKeyStates_Down) { + mods |= Qt::MetaModifier; + } else { + window->GetAsyncKeyState(VirtualKey_RightWindows, &mod); + if (mod == CoreVirtualKeyStates_Down) + mods |= Qt::MetaModifier; + } + return mods; +} + +// Return Qt meta key from VirtualKey (discard character keys) +static inline Qt::Key qMetaKeyFromVirtual(VirtualKey key) +{ + switch (key) { + + default: + return Qt::Key_unknown; + + // 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_Back: + return Qt::Key_Back; + 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_Space: + return Qt::Key_Space; + 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 - pass through. + case VirtualKey_Enter: + case VirtualKey_Tab: + case VirtualKey_Number0: + case VirtualKey_Number1: + case VirtualKey_Number2: + case VirtualKey_Number3: + case VirtualKey_Number4: + case VirtualKey_Number5: + case VirtualKey_Number6: + case VirtualKey_Number7: + case VirtualKey_Number8: + case VirtualKey_Number9: + case VirtualKey_A: + case VirtualKey_B: + case VirtualKey_C: + case VirtualKey_D: + case VirtualKey_E: + case VirtualKey_F: + case VirtualKey_G: + case VirtualKey_H: + case VirtualKey_I: + case VirtualKey_J: + case VirtualKey_K: + case VirtualKey_L: + case VirtualKey_M: + case VirtualKey_N: + case VirtualKey_O: + case VirtualKey_P: + case VirtualKey_Q: + case VirtualKey_R: + case VirtualKey_S: + case VirtualKey_T: + case VirtualKey_U: + case VirtualKey_V: + case VirtualKey_W: + case VirtualKey_X: + case VirtualKey_Y: + case VirtualKey_Z: + case VirtualKey_Multiply: + case VirtualKey_Add: + case VirtualKey_Separator: + case VirtualKey_Subtract: + case VirtualKey_Decimal: + case VirtualKey_Divide:*/ + + /* NumberPad keys. No special Alt handling is needed, as WinRT doesn't send events if Alt is pressed. + case VirtualKey_NumberPad0: + case VirtualKey_NumberPad1: + case VirtualKey_NumberPad2: + case VirtualKey_NumberPad3: + case VirtualKey_NumberPad4: + case VirtualKey_NumberPad5: + case VirtualKey_NumberPad6: + case VirtualKey_NumberPad7: + case VirtualKey_NumberPad8: + case VirtualKey_NumberPad9:*/ + + /* 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:*/ + } +} + +// Map Qt keys from char +static inline Qt::Key qKeyFromChar(quint32 code, Qt::KeyboardModifiers mods = Qt::NoModifier) +{ + switch (code) { + case 0x1: + case 'a': + case 'A': + return Qt::Key_A; + case 0x2: + case 'b': + case 'B': + return Qt::Key_B; + case 0x3: + case 'c': + case 'C': + return Qt::Key_C; + case 0x4: + case 'd': + case 'D': + return Qt::Key_D; + case 0x5: + case 'e': + case 'E': + return Qt::Key_E; + case 0x6: + case 'f': + case 'F': + return Qt::Key_F; + case 0x7: + case 'g': + case 'G': + return Qt::Key_G; + case 0x8: + //case '\b': + return mods & Qt::ControlModifier ? Qt::Key_H : Qt::Key_Backspace; + case 'h': + case 'H': + return Qt::Key_H; + case 0x9: + //case '\t': + return mods & Qt::ControlModifier ? Qt::Key_I : Qt::Key_Tab; + case 'i': + case 'I': + return Qt::Key_I; + case 0xa: + //case '\n': + return mods & Qt::ControlModifier ? Qt::Key_J : Qt::Key_Enter; + case 'j': + case 'J': + return Qt::Key_J; + case 0xb: + case 'k': + case 'K': + return Qt::Key_K; + case 0xc: + case 'l': + case 'L': + return Qt::Key_L; + case 0xd: + case 'm': + case 'M': + return Qt::Key_M; + case 0xe: + case 'n': + case 'N': + return Qt::Key_N; + case 0xf: + case 'o': + case 'O': + return Qt::Key_O; + case 0x10: + case 'p': + case 'P': + return Qt::Key_P; + case 0x11: + case 'q': + case 'Q': + return Qt::Key_Q; + case 0x12: + case 'r': + case 'R': + return Qt::Key_R; + case 0x13: + case 's': + case 'S': + return Qt::Key_S; + case 0x14: + case 't': + case 'T': + return Qt::Key_T; + case 0x15: + case 'u': + case 'U': + return Qt::Key_U; + case 0x16: + case 'v': + case 'V': + return Qt::Key_V; + case 0x17: + case 'w': + case 'W': + return Qt::Key_W; + case 0x18: + case 'x': + case 'X': + return Qt::Key_X; + case 0x19: + case 'y': + case 'Y': + return Qt::Key_Y; + case 0x1A: + case 'z': + case 'Z': + return Qt::Key_Z; + } + return Qt::Key_unknown; +} + +QWinRTScreen::QWinRTScreen(ICoreWindow *window) + : m_coreWindow(window) + , m_depth(32) + , m_format(QImage::Format_ARGB32_Premultiplied) +#ifdef Q_OS_WINPHONE + , m_inputContext(new QWinRTInputContext(m_coreWindow)) +#else + , m_inputContext(Make(m_coreWindow).Detach()) +#endif + , m_cursor(new QWinRTCursor(window)) + , m_orientation(Qt::PrimaryOrientation) +{ +#ifdef Q_OS_WINPHONE // On phone, there can be only one touch device + QTouchDevice *touchDevice = new QTouchDevice; + touchDevice->setCapabilities(QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::Pressure); + touchDevice->setType(QTouchDevice::TouchScreen); + touchDevice->setName(QStringLiteral("WinPhoneTouchScreen")); + Pointer pointer = { Pointer::TouchScreen, touchDevice }; + m_pointers.insert(0, pointer); + QWindowSystemInterface::registerTouchDevice(touchDevice); +#endif + + Rect rect; + window->get_Bounds(&rect); + m_geometry = QRect(0, 0, rect.Width, rect.Height); + + m_surfaceFormat.setAlphaBufferSize(0); + m_surfaceFormat.setRedBufferSize(8); + m_surfaceFormat.setGreenBufferSize(8); + m_surfaceFormat.setBlueBufferSize(8); + + m_surfaceFormat.setRenderableType(QSurfaceFormat::OpenGLES); + m_surfaceFormat.setSamples(1); + m_surfaceFormat.setSwapBehavior(QSurfaceFormat::DoubleBuffer); + m_surfaceFormat.setDepthBufferSize(24); + m_surfaceFormat.setStencilBufferSize(8); + + m_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (m_eglDisplay == EGL_NO_DISPLAY) + qFatal("Qt WinRT platform plugin: failed to initialize EGL display."); + + if (!eglInitialize(m_eglDisplay, NULL, NULL)) + qFatal("Qt WinRT platform plugin: failed to initialize EGL. This can happen if you haven't included the D3D compiler DLL in your application package."); + + // TODO: move this to Window + m_eglSurface = eglCreateWindowSurface(m_eglDisplay, q_configFromGLFormat(m_eglDisplay, m_surfaceFormat), window, NULL); + if (m_eglSurface == EGL_NO_SURFACE) + qFatal("Could not create EGL surface, error 0x%X", eglGetError()); + + // Event handlers mapped to QEvents + m_coreWindow->add_KeyDown(Callback(this, &QWinRTScreen::onKey).Get(), &m_tokens[QEvent::KeyPress]); + m_coreWindow->add_KeyUp(Callback(this, &QWinRTScreen::onKey).Get(), &m_tokens[QEvent::KeyRelease]); + m_coreWindow->add_CharacterReceived(Callback(this, &QWinRTScreen::onCharacterReceived).Get(), &m_tokens[QEvent::User]); + m_coreWindow->add_PointerEntered(Callback(this, &QWinRTScreen::onPointerEntered).Get(), &m_tokens[QEvent::Enter]); + m_coreWindow->add_PointerExited(Callback(this, &QWinRTScreen::onPointerExited).Get(), &m_tokens[QEvent::Leave]); + m_coreWindow->add_PointerMoved(Callback(this, &QWinRTScreen::onPointerUpdated).Get(), &m_tokens[QEvent::MouseMove]); + m_coreWindow->add_PointerPressed(Callback(this, &QWinRTScreen::onPointerUpdated).Get(), &m_tokens[QEvent::MouseButtonPress]); + m_coreWindow->add_PointerReleased(Callback(this, &QWinRTScreen::onPointerUpdated).Get(), &m_tokens[QEvent::MouseButtonRelease]); + m_coreWindow->add_PointerWheelChanged(Callback(this, &QWinRTScreen::onPointerUpdated).Get(), &m_tokens[QEvent::Wheel]); + m_coreWindow->add_SizeChanged(Callback(this, &QWinRTScreen::onSizeChanged).Get(), &m_tokens[QEvent::Resize]); + + // Window event handlers + m_coreWindow->add_Activated(Callback(this, &QWinRTScreen::onActivated).Get(), &m_tokens[QEvent::WindowActivate]); + m_coreWindow->add_Closed(Callback(this, &QWinRTScreen::onClosed).Get(), &m_tokens[QEvent::WindowDeactivate]); + m_coreWindow->add_VisibilityChanged(Callback(this, &QWinRTScreen::onVisibilityChanged).Get(), &m_tokens[QEvent::Show]); + m_coreWindow->add_AutomationProviderRequested(Callback(this, &QWinRTScreen::onAutomationProviderRequested).Get(), &m_tokens[QEvent::InputMethodQuery]); + + // Orientation handling + if (SUCCEEDED(GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Graphics_Display_DisplayProperties).Get(), + &m_displayProperties))) { + // Set native orientation + DisplayOrientations displayOrientation; + m_displayProperties->get_NativeOrientation(&displayOrientation); + m_nativeOrientation = qOrientationFromNative(displayOrientation); + + // Set initial orientation + onOrientationChanged(0); + + m_displayProperties->add_OrientationChanged(Callback(this, &QWinRTScreen::onOrientationChanged).Get(), + &m_tokens[QEvent::OrientationChange]); + } + +#ifndef Q_OS_WINPHONE + GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_ViewManagement_ApplicationView).Get(), + &m_applicationView); +#endif +} + +QRect QWinRTScreen::geometry() const +{ + return m_geometry; +} + +int QWinRTScreen::depth() const +{ + return m_depth; +} + +QImage::Format QWinRTScreen::format() const +{ + return m_format; +} + +QSurfaceFormat QWinRTScreen::surfaceFormat() const +{ + return m_surfaceFormat; +} + +QWinRTInputContext *QWinRTScreen::inputContext() const +{ + return m_inputContext; +} + +QPlatformCursor *QWinRTScreen::cursor() const +{ + return m_cursor; +} + +Qt::ScreenOrientation QWinRTScreen::nativeOrientation() const +{ + return m_nativeOrientation; +} + +Qt::ScreenOrientation QWinRTScreen::orientation() const +{ + return m_orientation; +} + +ICoreWindow *QWinRTScreen::coreWindow() const +{ + return m_coreWindow; +} + +EGLDisplay QWinRTScreen::eglDisplay() const +{ + return m_eglDisplay; +} + +EGLSurface QWinRTScreen::eglSurface() const +{ + return m_eglSurface; +} + +QWindow *QWinRTScreen::topWindow() const +{ + return m_visibleWindows.isEmpty() ? 0 : m_visibleWindows.first(); +} + +void QWinRTScreen::addWindow(QWindow *window) +{ + if (window == topWindow()) + return; + m_visibleWindows.prepend(window); + QWindowSystemInterface::handleWindowActivated(window, Qt::OtherFocusReason); + handleExpose(); +} + +void QWinRTScreen::removeWindow(QWindow *window) +{ + const bool wasTopWindow = window == topWindow(); + if (!m_visibleWindows.removeAll(window)) + return; + if (wasTopWindow) + QWindowSystemInterface::handleWindowActivated(window, Qt::OtherFocusReason); + handleExpose(); +} + +void QWinRTScreen::raise(QWindow *window) +{ + m_visibleWindows.removeAll(window); + addWindow(window); +} + +void QWinRTScreen::lower(QWindow *window) +{ + const bool wasTopWindow = window == topWindow(); + if (wasTopWindow && m_visibleWindows.size() == 1) + return; + m_visibleWindows.removeAll(window); + m_visibleWindows.append(window); + if (wasTopWindow) + QWindowSystemInterface::handleWindowActivated(window, Qt::OtherFocusReason); + handleExpose(); +} + +void QWinRTScreen::handleExpose() +{ + if (m_visibleWindows.isEmpty()) + return; + QList::const_iterator it = m_visibleWindows.constBegin(); + QWindowSystemInterface::handleExposeEvent(*it, m_geometry); + while (++it != m_visibleWindows.constEnd()) + QWindowSystemInterface::handleExposeEvent(*it, QRegion()); + QWindowSystemInterface::flushWindowSystemEvents(); +} + +HRESULT QWinRTScreen::onKey(ABI::Windows::UI::Core::ICoreWindow *window, ABI::Windows::UI::Core::IKeyEventArgs *args) +{ + Q_UNUSED(window); + + // Windows Phone documentation claims this will throw, but doesn't seem to + CorePhysicalKeyStatus keyStatus; + args->get_KeyStatus(&keyStatus); + + VirtualKey virtualKey; + args->get_VirtualKey(&virtualKey); + + // Filter meta keys + Qt::Key key = qMetaKeyFromVirtual(virtualKey); + + // Get keyboard modifiers. This could alternatively be tracked by key presses, but + // WinRT doesn't send key events for Alt unless Ctrl is also pressed. + // If the key that caused this event is a modifier, it is not returned in the flags. + Qt::KeyboardModifiers mods = qKeyModifiers(m_coreWindow); + + if (m_activeKeys.contains(keyStatus.ScanCode)) { // Handle tracked keys (release/repeat) + QString text = keyStatus.IsKeyReleased ? m_activeKeys.take(keyStatus.ScanCode) : m_activeKeys.value(keyStatus.ScanCode); + QWindowSystemInterface::handleKeyEvent(topWindow(), QEvent::KeyRelease, key, mods, text); + + if (!keyStatus.IsKeyReleased) // Repeating key + QWindowSystemInterface::handleKeyEvent(topWindow(), QEvent::KeyPress, key, mods, text); + + } else if (keyStatus.IsKeyReleased) { // Unlikely, but possible if key is held before application is focused + QWindowSystemInterface::handleKeyEvent(topWindow(), QEvent::KeyRelease, key, mods); + + } else { // Handle key presses + if (key != Qt::Key_unknown) // Handle non-character key presses here, others in onCharacterReceived + QWindowSystemInterface::handleKeyEvent(topWindow(), QEvent::KeyPress, key, mods); + + m_activeKeys.insert(keyStatus.ScanCode, QString()); + } + + return S_OK; +} + +HRESULT QWinRTScreen::onCharacterReceived(ICoreWindow *window, ICharacterReceivedEventArgs *args) +{ + Q_UNUSED(window); + + quint32 keyCode; + args->get_KeyCode(&keyCode); + + // Windows Phone documentation claims this will throw, but doesn't seem to + CorePhysicalKeyStatus keyStatus; + args->get_KeyStatus(&keyStatus); + + QString text = QChar(keyCode); + + Qt::KeyboardModifiers mods = qKeyModifiers(m_coreWindow); + Qt::Key key = qKeyFromChar(keyCode, mods); + + QWindowSystemInterface::handleKeyEvent(topWindow(), QEvent::KeyPress, key, mods, text); + + // Note that we can receive a character without corresponding press/release events, such as + // the case of an Alt-combo. In this case, we should send the release immediately. + if (m_activeKeys.contains(keyStatus.ScanCode)) + m_activeKeys.insert(keyStatus.ScanCode, text); + else + QWindowSystemInterface::handleKeyEvent(topWindow(), QEvent::KeyRelease, key, mods, text); + + return S_OK; +} + +HRESULT QWinRTScreen::onPointerEntered(ICoreWindow *window, IPointerEventArgs *args) +{ + Q_UNUSED(window); + IPointerPoint *pointerPoint; + if (SUCCEEDED(args->get_CurrentPoint(&pointerPoint))) { + // Assumes full-screen window + Point point; + pointerPoint->get_Position(&point); + QPoint pos(point.X, point.Y); + + QWindowSystemInterface::handleEnterEvent(topWindow(), pos, pos); + pointerPoint->Release(); + } + return S_OK; +} + +HRESULT QWinRTScreen::onPointerExited(ICoreWindow *window, IPointerEventArgs *args) +{ + Q_UNUSED(window); + Q_UNUSED(args); + QWindowSystemInterface::handleLeaveEvent(0); + return S_OK; +} + +HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *window, IPointerEventArgs *args) +{ + Q_UNUSED(window); + + 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, point.Y); + + 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; + + IPointerPointProperties *properties; + if (FAILED(pointerPoint->get_Properties(&properties))) + return E_INVALIDARG; + +#ifdef Q_OS_WINPHONE + quint32 pointerId = 0; + Pointer pointer = m_pointers.value(pointerId); +#else + Pointer pointer = { Pointer::Unknown, 0 }; + quint32 pointerId; + pointerPoint->get_PointerId(&pointerId); + if (m_pointers.contains(pointerId)) { + pointer = m_pointers.value(pointerId); + } else { // We have not yet enumerated this device. Do so now... + IPointerDevice *device; + if (SUCCEEDED(pointerPoint->get_PointerDevice(&device))) { + PointerDeviceType type; + device->get_PointerDeviceType(&type); + switch (type) { + case PointerDeviceType_Touch: + pointer.type = Pointer::TouchScreen; + pointer.device = new QTouchDevice; + pointer.device->setName(QStringLiteral("WinRT TouchScreen ") + QString::number(pointerId)); + // TODO: We may want to probe the device usage flags for more accurate values for these next two + pointer.device->setType(QTouchDevice::TouchScreen); + pointer.device->setCapabilities(QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::Pressure); + QWindowSystemInterface::registerTouchDevice(pointer.device); + break; + + case PointerDeviceType_Pen: + pointer.type = Pointer::Tablet; + break; + + case PointerDeviceType_Mouse: + pointer.type = Pointer::Mouse; + break; + } + + m_pointers.insert(pointerId, pointer); + device->Release(); + } + } +#endif + switch (pointer.type) { + case Pointer::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 Pointer::TouchScreen: { + quint32 id; + pointerPoint->get_PointerId(&id); + + Rect area; + properties->get_ContactRect(&area); + + float pressure; + properties->get_Pressure(&pressure); + + QHash::iterator it = m_touchPoints.find(id); + if (it != m_touchPoints.end()) { + boolean isPressed; + pointerPoint->get_IsInContact(&isPressed); + it.value().state = isPressed ? Qt::TouchPointMoved : Qt::TouchPointReleased; + } else { + it = m_touchPoints.insert(id, QWindowSystemInterface::TouchPoint()); + it.value().state = Qt::TouchPointPressed; + it.value().id = id; + } + it.value().area = QRectF(area.X, area.Y, area.Width, area.Height); + it.value().normalPosition = QPointF(pos.x()/m_geometry.width(), pos.y()/m_geometry.height()); + it.value().pressure = pressure; + + QWindowSystemInterface::handleTouchEvent(topWindow(), pointer.device, m_touchPoints.values(), mods); + + // Remove released points, station others + for (QHash::iterator i = m_touchPoints.begin(); i != m_touchPoints.end();) { + if (i.value().state == Qt::TouchPointReleased) + i = m_touchPoints.erase(i); + else + (i++).value().state = Qt::TouchPointStationary; + } + + break; + } + case Pointer::Tablet: { + 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, pointerId, + pointerType, pressure, xTilt, yTilt, + 0, rotation, 0, id, mods); + + break; + } + } + + properties->Release(); + pointerPoint->Release(); + + return S_OK; +} + +HRESULT QWinRTScreen::onAutomationProviderRequested(ICoreWindow *, IAutomationProviderRequestedEventArgs *args) +{ +#ifndef Q_OS_WINPHONE + args->put_AutomationProvider(m_inputContext); +#endif + return S_OK; +} + +HRESULT QWinRTScreen::onSizeChanged(ICoreWindow *window, IWindowSizeChangedEventArgs *args) +{ + Q_UNUSED(window); + + Size size; + if (FAILED(args->get_Size(&size))) { + qWarning(Q_FUNC_INFO ": failed to get size"); + return S_OK; + } + + // Regardless of state, all top-level windows are viewport-sized - this might change if + // a more advanced compositor is written. + m_geometry.setSize(QSize(size.Width, size.Height)); + QWindowSystemInterface::handleScreenGeometryChange(screen(), m_geometry); + QWindowSystemInterface::handleScreenAvailableGeometryChange(screen(), m_geometry); + QPlatformScreen::resizeMaximizedWindows(); + handleExpose(); + + return S_OK; +} + +HRESULT QWinRTScreen::onActivated(ICoreWindow *window, IWindowActivatedEventArgs *args) +{ + Q_UNUSED(window); + + CoreWindowActivationState activationState; + args->get_WindowActivationState(&activationState); + if (activationState == CoreWindowActivationState_Deactivated) { + QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive); + return S_OK; + } + + // Activate topWindow + if (!m_visibleWindows.isEmpty()) { + Qt::FocusReason focusReason = activationState == CoreWindowActivationState_PointerActivated + ? Qt::MouseFocusReason : Qt::ActiveWindowFocusReason; + QWindowSystemInterface::handleWindowActivated(topWindow(), focusReason); + } + return S_OK; +} + +HRESULT QWinRTScreen::onClosed(ICoreWindow *window, ICoreWindowEventArgs *args) +{ + Q_UNUSED(window); + Q_UNUSED(args); + + foreach (QWindow *w, QGuiApplication::topLevelWindows()) + QWindowSystemInterface::handleCloseEvent(w); + return S_OK; +} + +HRESULT QWinRTScreen::onVisibilityChanged(ICoreWindow *window, IVisibilityChangedEventArgs *args) +{ + Q_UNUSED(window); + Q_UNUSED(args); + + boolean visible; + args->get_Visible(&visible); + QWindowSystemInterface::handleApplicationStateChanged(visible ? Qt::ApplicationActive : Qt::ApplicationHidden); + return S_OK; +} + +HRESULT QWinRTScreen::onOrientationChanged(IInspectable *) +{ + DisplayOrientations displayOrientation; + m_displayProperties->get_CurrentOrientation(&displayOrientation); + Qt::ScreenOrientation newOrientation = qOrientationFromNative(displayOrientation); + if (m_orientation != newOrientation) { + m_orientation = newOrientation; + QWindowSystemInterface::handleScreenOrientationChange(screen(), m_orientation); + } + + return S_OK; +} + +QT_END_NAMESPACE -- cgit v1.2.3