winrt: Avoid blocking the XAML thread

Blocking the XAML thread can lead to a deadlock, so switch to the
non-blocking version of handleExtendendKeyEvent.

Task-Id: QTBUG-49051
Change-Id: I65a348af1f77b6afcd7d0fb9a80c70d60fc94c27
Reviewed-by: Andrew Knight <andrew.knight@intopalo.com>
Reviewed-by: Oliver Wolff <oliver.wolff@theqtcompany.com>
bb10
Samuel Nevala 2015-10-30 17:00:46 +02:00
parent cf0843c5f5
commit 96c9817575
1 changed files with 89 additions and 34 deletions

View File

@ -89,6 +89,27 @@ typedef ITypedEventHandler<StatusBar*, IInspectable*> StatusBarHandler;
QT_BEGIN_NAMESPACE
struct KeyInfo {
KeyInfo()
: virtualKey(0)
{
}
KeyInfo(const QString &text, quint32 virtualKey)
: text(text)
, virtualKey(virtualKey)
{
}
KeyInfo(quint32 virtualKey)
: virtualKey(virtualKey)
{
}
QString text;
quint32 virtualKey;
};
static inline Qt::ScreenOrientations qtOrientationsFromNative(DisplayOrientations native)
{
Qt::ScreenOrientations orientations = Qt::PrimaryOrientation;
@ -435,10 +456,7 @@ public:
Qt::ScreenOrientation nativeOrientation;
Qt::ScreenOrientation orientation;
QList<QWindow *> visibleWindows;
#ifndef Q_OS_WINPHONE
QHash<quint32, QPair<Qt::Key, QString>> activeKeys;
#endif
QHash<Qt::Key, KeyInfo> activeKeys;
QHash<CoreWindowCallbackRemover, EventRegistrationToken> windowTokens;
QHash<DisplayCallbackRemover, EventRegistrationToken> displayTokens;
#ifdef Q_OS_WINPHONE
@ -827,57 +845,94 @@ void QWinRTScreen::handleExpose()
HRESULT QWinRTScreen::onKeyDown(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IKeyEventArgs *args)
{
Q_D(QWinRTScreen);
VirtualKey virtualKey;
args->get_VirtualKey(&virtualKey);
HRESULT hr = args->get_VirtualKey(&virtualKey);
Q_ASSERT_SUCCEEDED(hr);
CorePhysicalKeyStatus status;
hr = args->get_KeyStatus(&status);
Q_ASSERT_SUCCEEDED(hr);
Qt::Key key = qKeyFromVirtual(virtualKey);
// Defer character key presses to onCharacterReceived
if (key == Qt::Key_unknown || (key >= Qt::Key_Space && key <= Qt::Key_ydiaeresis))
if (key == Qt::Key_unknown || (key >= Qt::Key_Space && key <= Qt::Key_ydiaeresis)) {
d->activeKeys.insert(key, KeyInfo(virtualKey));
return S_OK;
QWindowSystemInterface::handleKeyEvent(topWindow(), QEvent::KeyPress, key, keyboardModifiers());
}
QWindowSystemInterface::handleExtendedKeyEvent(
topWindow(),
QEvent::KeyPress,
key,
keyboardModifiers(),
!status.ScanCode ? -1 : status.ScanCode,
virtualKey,
0,
QString(),
status.RepeatCount > 1,
!status.RepeatCount ? 1 : status.RepeatCount,
false);
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);
HRESULT hr = args->get_VirtualKey(&virtualKey);
Q_ASSERT_SUCCEEDED(hr);
CorePhysicalKeyStatus status;
hr = args->get_KeyStatus(&status);
Q_ASSERT_SUCCEEDED(hr);
Qt::Key key = qKeyFromVirtual(virtualKey);
const KeyInfo info = d->activeKeys.take(key);
QWindowSystemInterface::handleExtendedKeyEvent(
topWindow(),
QEvent::KeyRelease,
key,
keyboardModifiers(),
!status.ScanCode ? -1 : status.ScanCode,
virtualKey,
0,
info.text,
status.RepeatCount > 1,
!status.RepeatCount ? 1 : status.RepeatCount,
false);
return S_OK;
}
HRESULT QWinRTScreen::onCharacterReceived(ICoreWindow *, ICharacterReceivedEventArgs *args)
{
Q_D(QWinRTScreen);
quint32 keyCode;
args->get_KeyCode(&keyCode);
HRESULT hr = args->get_KeyCode(&keyCode);
Q_ASSERT_SUCCEEDED(hr);
CorePhysicalKeyStatus status;
hr = args->get_KeyStatus(&status);
Q_ASSERT_SUCCEEDED(hr);
// 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);
const Qt::KeyboardModifiers modifiers = keyboardModifiers();
const Qt::Key key = qKeyFromCode(keyCode, modifiers);
const QString text = QChar(keyCode);
const quint32 virtualKey = d->activeKeys.value(key).virtualKey;
QWindowSystemInterface::handleExtendedKeyEvent(
topWindow(),
QEvent::KeyPress,
key,
modifiers,
!status.ScanCode ? -1 : status.ScanCode,
virtualKey,
0,
text,
status.RepeatCount > 1,
!status.RepeatCount ? 1 : status.RepeatCount,
false);
d->activeKeys.insert(key, KeyInfo(text, virtualKey));
return S_OK;
}