summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAndrew Knight <andrew.knight@digia.com>2013-10-12 02:07:39 +0300
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-10-16 15:13:56 +0200
commitaf4284401d2ee5675fe6d06211a0686a5732af23 (patch)
treee41d53ef122166a92a03e3feac7c0e98eeadfca0 /src
parent0232fa3979e0e5d8485de94950f514bfd861d22b (diff)
WinRT QPA: Improve key handling
Simplify key handling by providing a cleaner tracking of physical key presses and associated character events. Change-Id: I5aa8990e0b24e101b348c04d1ada2cbcd1b0b6be Reviewed-by: Maurice Kalinowski <maurice.kalinowski@digia.com> Reviewed-by: Oliver Wolff <oliver.wolff@digia.com>
Diffstat (limited to 'src')
-rw-r--r--src/plugins/platforms/winrt/qwinrtintegration.cpp5
-rw-r--r--src/plugins/platforms/winrt/qwinrtintegration.h1
-rw-r--r--src/plugins/platforms/winrt/qwinrtscreen.cpp353
-rw-r--r--src/plugins/platforms/winrt/qwinrtscreen.h8
4 files changed, 160 insertions, 207 deletions
diff --git a/src/plugins/platforms/winrt/qwinrtintegration.cpp b/src/plugins/platforms/winrt/qwinrtintegration.cpp
index 4cc7eb31f1..22c50e67f3 100644
--- a/src/plugins/platforms/winrt/qwinrtintegration.cpp
+++ b/src/plugins/platforms/winrt/qwinrtintegration.cpp
@@ -186,4 +186,9 @@ QPlatformServices *QWinRTIntegration::services() const
return m_services;
}
+Qt::KeyboardModifiers QWinRTIntegration::queryKeyboardModifiers() const
+{
+ return m_screen->keyboardModifiers();
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/winrt/qwinrtintegration.h b/src/plugins/platforms/winrt/qwinrtintegration.h
index 6cf2c3e5f2..d9438bcb3a 100644
--- a/src/plugins/platforms/winrt/qwinrtintegration.h
+++ b/src/plugins/platforms/winrt/qwinrtintegration.h
@@ -72,6 +72,7 @@ public:
QPlatformFontDatabase *fontDatabase() const;
QPlatformInputContext *inputContext() const;
QPlatformServices *services() const;
+ Qt::KeyboardModifiers queryKeyboardModifiers() const;
private:
bool m_success;
diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp
index 8bc778ef11..911d3619fe 100644
--- a/src/plugins/platforms/winrt/qwinrtscreen.cpp
+++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp
@@ -112,38 +112,37 @@ static inline DisplayOrientations nativeOrientationsFromQt(Qt::ScreenOrientation
return native;
}
-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;
+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 mods;
}
-// Return Qt meta key from VirtualKey (discard character keys)
-static inline Qt::Key qMetaKeyFromVirtual(VirtualKey key)
+// 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:
@@ -188,8 +187,6 @@ static inline Qt::Key qMetaKeyFromVirtual(VirtualKey key)
// 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:
@@ -198,8 +195,6 @@ static inline Qt::Key qMetaKeyFromVirtual(VirtualKey key)
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:
@@ -283,63 +278,103 @@ static inline Qt::Key qMetaKeyFromVirtual(VirtualKey key)
case VirtualKey_F24:
return Qt::Key_F24;
- /* Character keys - pass through.
- case VirtualKey_Enter:
- case VirtualKey_Tab:
+ // 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:
- 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:*/
+ return Qt::Key_9;
+ case VirtualKey_Divide:
+ return Qt::Key_9;
/* Keys with no matching Qt enum (?)
case VirtualKey_None:
@@ -353,122 +388,15 @@ static inline Qt::Key qMetaKeyFromVirtual(VirtualKey key)
}
}
-// Map Qt keys from char
-static inline Qt::Key qKeyFromChar(quint32 code, Qt::KeyboardModifiers mods = Qt::NoModifier)
+static inline Qt::Key qKeyFromCode(quint32 code, int mods)
{
- 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;
+ 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 Qt::Key_unknown;
+ return static_cast<Qt::Key>(code & 0xff);
}
QWinRTScreen::QWinRTScreen(ICoreWindow *window)
@@ -521,8 +449,8 @@ QWinRTScreen::QWinRTScreen(ICoreWindow *window)
qFatal("Could not create EGL surface, error 0x%X", eglGetError());
// Event handlers mapped to QEvents
- m_coreWindow->add_KeyDown(Callback<KeyHandler>(this, &QWinRTScreen::onKey).Get(), &m_tokens[QEvent::KeyPress]);
- m_coreWindow->add_KeyUp(Callback<KeyHandler>(this, &QWinRTScreen::onKey).Get(), &m_tokens[QEvent::KeyRelease]);
+ m_coreWindow->add_KeyDown(Callback<KeyHandler>(this, &QWinRTScreen::onKeyDown).Get(), &m_tokens[QEvent::KeyPress]);
+ m_coreWindow->add_KeyUp(Callback<KeyHandler>(this, &QWinRTScreen::onKeyUp).Get(), &m_tokens[QEvent::KeyRelease]);
m_coreWindow->add_CharacterReceived(Callback<CharacterReceivedHandler>(this, &QWinRTScreen::onCharacterReceived).Get(), &m_tokens[QEvent::User]);
m_coreWindow->add_PointerEntered(Callback<PointerHandler>(this, &QWinRTScreen::onPointerEntered).Get(), &m_tokens[QEvent::Enter]);
m_coreWindow->add_PointerExited(Callback<PointerHandler>(this, &QWinRTScreen::onPointerExited).Get(), &m_tokens[QEvent::Leave]);
@@ -589,6 +517,30 @@ QPlatformCursor *QWinRTScreen::cursor() const
return m_cursor;
}
+Qt::KeyboardModifiers QWinRTScreen::keyboardModifiers() const
+{
+ Qt::KeyboardModifiers mods;
+ CoreVirtualKeyStates mod;
+ m_coreWindow->GetAsyncKeyState(VirtualKey_Shift, &mod);
+ if (mod == CoreVirtualKeyStates_Down)
+ mods |= Qt::ShiftModifier;
+ m_coreWindow->GetAsyncKeyState(VirtualKey_Menu, &mod);
+ if (mod == CoreVirtualKeyStates_Down)
+ mods |= Qt::AltModifier;
+ m_coreWindow->GetAsyncKeyState(VirtualKey_Control, &mod);
+ if (mod == CoreVirtualKeyStates_Down)
+ mods |= Qt::ControlModifier;
+ m_coreWindow->GetAsyncKeyState(VirtualKey_LeftWindows, &mod);
+ if (mod == CoreVirtualKeyStates_Down) {
+ mods |= Qt::MetaModifier;
+ } else {
+ m_coreWindow->GetAsyncKeyState(VirtualKey_RightWindows, &mod);
+ if (mod == CoreVirtualKeyStates_Down)
+ mods |= Qt::MetaModifier;
+ }
+ return mods;
+}
+
Qt::ScreenOrientation QWinRTScreen::nativeOrientation() const
{
return m_nativeOrientation;
@@ -672,42 +624,36 @@ void QWinRTScreen::handleExpose()
QWindowSystemInterface::flushWindowSystemEvents();
}
-HRESULT QWinRTScreen::onKey(ABI::Windows::UI::Core::ICoreWindow *window, ABI::Windows::UI::Core::IKeyEventArgs *args)
+HRESULT QWinRTScreen::onKeyDown(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);
+ 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;
+}
- // 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());
+HRESULT QWinRTScreen::onKeyUp(ABI::Windows::UI::Core::ICoreWindow *window, ABI::Windows::UI::Core::IKeyEventArgs *args)
+{
+ Q_UNUSED(window);
+ Qt::KeyboardModifiers mods = keyboardModifiers();
+#ifndef Q_OS_WINPHONE
+ CorePhysicalKeyStatus status; // Look for a pressed character key
+ if (SUCCEEDED(args->get_KeyStatus(&status)) && m_activeKeys.contains(status.ScanCode)) {
+ QPair<Qt::Key, QString> keyStatus = m_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;
}
@@ -717,25 +663,22 @@ HRESULT QWinRTScreen::onCharacterReceived(ICoreWindow *window, ICharacterReceive
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;
- // Windows Phone documentation claims this will throw, but doesn't seem to
- CorePhysicalKeyStatus keyStatus;
- args->get_KeyStatus(&keyStatus);
-
+ Qt::KeyboardModifiers mods = keyboardModifiers();
+ Qt::Key key = qKeyFromCode(keyCode, mods);
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);
-
+#ifndef Q_OS_WINPHONE
+ CorePhysicalKeyStatus status; // Defer release to onKeyUp for physical keys
+ if (SUCCEEDED(args->get_KeyStatus(&status)) && !status.IsKeyReleased) {
+ m_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;
}
diff --git a/src/plugins/platforms/winrt/qwinrtscreen.h b/src/plugins/platforms/winrt/qwinrtscreen.h
index 83f359ce6d..21e50fa10a 100644
--- a/src/plugins/platforms/winrt/qwinrtscreen.h
+++ b/src/plugins/platforms/winrt/qwinrtscreen.h
@@ -102,6 +102,7 @@ public:
QSurfaceFormat surfaceFormat() const;
QWinRTInputContext *inputContext() const;
QPlatformCursor *cursor() const;
+ Qt::KeyboardModifiers keyboardModifiers() const;
Qt::ScreenOrientation nativeOrientation() const;
Qt::ScreenOrientation orientation() const;
@@ -123,7 +124,8 @@ private:
// Event handlers
QHash<QEvent::Type, EventRegistrationToken> m_tokens;
- HRESULT onKey(ABI::Windows::UI::Core::ICoreWindow *window, ABI::Windows::UI::Core::IKeyEventArgs *args);
+ HRESULT onKeyDown(ABI::Windows::UI::Core::ICoreWindow *window, ABI::Windows::UI::Core::IKeyEventArgs *args);
+ HRESULT onKeyUp(ABI::Windows::UI::Core::ICoreWindow *window, ABI::Windows::UI::Core::IKeyEventArgs *args);
HRESULT onCharacterReceived(ABI::Windows::UI::Core::ICoreWindow *window, ABI::Windows::UI::Core::ICharacterReceivedEventArgs *args);
HRESULT onPointerEntered(ABI::Windows::UI::Core::ICoreWindow *window, ABI::Windows::UI::Core::IPointerEventArgs *args);
HRESULT onPointerExited(ABI::Windows::UI::Core::ICoreWindow *window, ABI::Windows::UI::Core::IPointerEventArgs *args);
@@ -154,7 +156,9 @@ private:
Qt::ScreenOrientation m_nativeOrientation;
Qt::ScreenOrientation m_orientation;
- QHash<quint32, QString> m_activeKeys;
+#ifndef Q_OS_WINPHONE
+ QHash<quint32, QPair<Qt::Key, QString> > m_activeKeys;
+#endif
QHash<quint32, Pointer> m_pointers;
QHash<quint32, QWindowSystemInterface::TouchPoint> m_touchPoints;
};