Fix the handling of dead keys and test the mechanism

An effort has been made to support more keyboard layouts that provide
dead keys (US international, Mac-specific dead keys).

The dead key is translated now at the event conversion phase, not
when it is actually used for modifying keys, which simplifies the logic.

Unittests have been created to check the translation mechanism.

Fixes: QTBUG-86272
Change-Id: I07f7d63f5a37f8469c693b034b400da99379f519
Reviewed-by: Lorn Potter <lorn.potter@gmail.com>
This commit is contained in:
Mikolaj Boc 2023-02-10 15:06:36 +01:00
parent 6d17697913
commit 3dc6fdc6d8
4 changed files with 605 additions and 84 deletions

View File

@ -7,6 +7,7 @@
#include <QtCore/private/qmakearray_p.h>
#include <QtCore/private/qstringiterator_p.h>
#include <QtCore/qregularexpression.h>
QT_BEGIN_NAMESPACE
@ -18,19 +19,57 @@ bool isDeadKeyEvent(const char *key)
return qstrncmp(key, WebDeadKeyValue.data(), WebDeadKeyValue.size()) == 0;
}
Qt::Key webKeyToQtKey(const std::string &code, const std::string &key, bool isDeadKey)
Qt::Key getKeyFromCode(const std::string &code)
{
if (auto mapping = QWasmKeyTranslator::mapWebKeyTextToQtKey(code.c_str()))
return *mapping;
static QRegularExpression regex(QString(QStringLiteral(R"re((?:Key|Digit)(\w))re")));
const auto codeQString = QString::fromStdString(code);
const auto match = regex.match(codeQString);
if (!match.hasMatch())
return Qt::Key_unknown;
constexpr size_t CharacterIndex = 1;
return static_cast<Qt::Key>(match.capturedView(CharacterIndex).at(0).toLatin1());
}
Qt::Key webKeyToQtKey(const std::string &code, const std::string &key, bool isDeadKey,
QFlags<Qt::KeyboardModifier> modifiers)
{
if (isDeadKey) {
if (auto mapping = QWasmKeyTranslator::mapWebKeyTextToQtKey(code.c_str()))
return *mapping;
}
if (auto mapping = QWasmKeyTranslator::mapWebKeyTextToQtKey(key.c_str()))
auto mapped = getKeyFromCode(code);
switch (mapped) {
case Qt::Key_U:
return Qt::Key_Dead_Diaeresis;
case Qt::Key_E:
return Qt::Key_Dead_Acute;
case Qt::Key_I:
return Qt::Key_Dead_Circumflex;
case Qt::Key_N:
return Qt::Key_Dead_Tilde;
case Qt::Key_QuoteLeft:
return modifiers.testFlag(Qt::ShiftModifier) ? Qt::Key_Dead_Tilde : Qt::Key_Dead_Grave;
case Qt::Key_6:
return Qt::Key_Dead_Circumflex;
case Qt::Key_Apostrophe:
return modifiers.testFlag(Qt::ShiftModifier) ? Qt::Key_Dead_Diaeresis
: Qt::Key_Dead_Acute;
case Qt::Key_AsciiTilde:
return Qt::Key_Dead_Tilde;
default:
return Qt::Key_unknown;
}
} else if (auto mapping = QWasmKeyTranslator::mapWebKeyTextToQtKey(key.c_str())) {
return *mapping;
if (isDeadKey)
return Qt::Key_unknown;
}
// cast to unicode key
QString str = QString::fromUtf8(key.c_str()).toUpper();
if (str.length() > 1)
return Qt::Key_unknown;
QStringIterator i(str);
return static_cast<Qt::Key>(i.next(0));
}
@ -65,9 +104,9 @@ KeyEvent::KeyEvent(EventType type, emscripten::val event) : Event(type, event["t
const auto webKey = event["key"].as<std::string>();
deadKey = isDeadKeyEvent(webKey.c_str());
key = webKeyToQtKey(code, webKey, deadKey);
modifiers = KeyboardModifier::getForEvent(event);
key = webKeyToQtKey(code, webKey, deadKey, modifiers);
text = QString::fromUtf8(webKey);
if (text.size() > 1)
text.clear();

View File

@ -52,34 +52,17 @@ template<unsigned int Qt, char... WebChar>
constexpr char Web2Qt<Qt, WebChar...>::storage[];
static constexpr const auto WebToQtKeyCodeMappings = qMakeArray(
QSortedData<Web2Qt<Qt::Key_Escape, 'E', 's', 'c', 'a', 'p', 'e'>,
Web2Qt<Qt::Key_Tab, 'T', 'a', 'b'>,
Web2Qt<Qt::Key_Backspace, 'B', 'a', 'c', 'k', 's', 'p', 'a', 'c', 'e'>,
Web2Qt<Qt::Key_Return, 'E', 'n', 't', 'e', 'r'>,
Web2Qt<Qt::Key_Insert, 'I', 'n', 's', 'e', 'r', 't'>,
Web2Qt<Qt::Key_Delete, 'D', 'e', 'l', 'e', 't', 'e'>,
Web2Qt<Qt::Key_Pause, 'P', 'a', 'u', 's', 'e'>,
Web2Qt<Qt::Key_Pause, 'C', 'l', 'e', 'a', 'r'>,
Web2Qt<Qt::Key_Home, 'H', 'o', 'm', 'e'>, Web2Qt<Qt::Key_End, 'E', 'n', 'd'>,
Web2Qt<Qt::Key_Left, 'A', 'r', 'r', 'o', 'w', 'L', 'e', 'f', 't'>,
Web2Qt<Qt::Key_Up, 'A', 'r', 'r', 'o', 'w', 'U', 'p'>,
Web2Qt<Qt::Key_Right, 'A', 'r', 'r', 'o', 'w', 'R', 'i', 'g', 'h', 't'>,
Web2Qt<Qt::Key_Down, 'A', 'r', 'r', 'o', 'w', 'D', 'o', 'w', 'n'>,
Web2Qt<Qt::Key_PageUp, 'P', 'a', 'g', 'e', 'U', 'p'>,
Web2Qt<Qt::Key_PageDown, 'P', 'a', 'g', 'e', 'D', 'o', 'w', 'n'>,
Web2Qt<Qt::Key_Shift, 'S', 'h', 'i', 'f', 't'>,
Web2Qt<Qt::Key_Control, 'C', 'o', 'n', 't', 'r', 'o', 'l'>,
Web2Qt<Qt::Key_Meta, 'M', 'e', 't', 'a'>, Web2Qt<Qt::Key_Meta, 'O', 'S'>,
Web2Qt<Qt::Key_Alt, 'A', 'l', 't', 'L', 'e', 'f', 't'>,
QSortedData<Web2Qt<Qt::Key_Alt, 'A', 'l', 't', 'L', 'e', 'f', 't'>,
Web2Qt<Qt::Key_Alt, 'A', 'l', 't'>,
Web2Qt<Qt::Key_AltGr, 'A', 'l', 't', 'R', 'i', 'g', 'h', 't'>,
Web2Qt<Qt::Key_Apostrophe, 'Q', 'u', 'o', 't', 'e'>,
Web2Qt<Qt::Key_Backspace, 'B', 'a', 'c', 'k', 's', 'p', 'a', 'c', 'e'>,
Web2Qt<Qt::Key_CapsLock, 'C', 'a', 'p', 's', 'L', 'o', 'c', 'k'>,
Web2Qt<Qt::Key_NumLock, 'N', 'u', 'm', 'L', 'o', 'c', 'k'>,
Web2Qt<Qt::Key_ScrollLock, 'S', 'c', 'r', 'o', 'l', 'l', 'L', 'o', 'c', 'k'>,
Web2Qt<Qt::Key_Control, 'C', 'o', 'n', 't', 'r', 'o', 'l'>,
Web2Qt<Qt::Key_Delete, 'D', 'e', 'l', 'e', 't', 'e'>,
Web2Qt<Qt::Key_Down, 'A', 'r', 'r', 'o', 'w', 'D', 'o', 'w', 'n'>,
Web2Qt<Qt::Key_Escape, 'E', 's', 'c', 'a', 'p', 'e'>,
Web2Qt<Qt::Key_F1, 'F', '1'>, Web2Qt<Qt::Key_F2, 'F', '2'>,
Web2Qt<Qt::Key_F3, 'F', '3'>, Web2Qt<Qt::Key_F4, 'F', '4'>,
Web2Qt<Qt::Key_F5, 'F', '5'>, Web2Qt<Qt::Key_F6, 'F', '6'>,
Web2Qt<Qt::Key_F7, 'F', '7'>, Web2Qt<Qt::Key_F8, 'F', '8'>,
Web2Qt<Qt::Key_F9, 'F', '9'>, Web2Qt<Qt::Key_F10, 'F', '1', '0'>,
Web2Qt<Qt::Key_F11, 'F', '1', '1'>, Web2Qt<Qt::Key_F12, 'F', '1', '2'>,
Web2Qt<Qt::Key_F13, 'F', '1', '3'>, Web2Qt<Qt::Key_F14, 'F', '1', '4'>,
Web2Qt<Qt::Key_F15, 'F', '1', '5'>, Web2Qt<Qt::Key_F16, 'F', '1', '6'>,
@ -87,34 +70,99 @@ static constexpr const auto WebToQtKeyCodeMappings = qMakeArray(
Web2Qt<Qt::Key_F19, 'F', '1', '9'>, Web2Qt<Qt::Key_F20, 'F', '2', '0'>,
Web2Qt<Qt::Key_F21, 'F', '2', '1'>, Web2Qt<Qt::Key_F22, 'F', '2', '2'>,
Web2Qt<Qt::Key_F23, 'F', '2', '3'>,
Web2Qt<Qt::Key_Paste, 'P', 'a', 's', 't', 'e'>,
Web2Qt<Qt::Key_AltGr, 'A', 'l', 't', 'R', 'i', 'g', 'h', 't'>,
Web2Qt<Qt::Key_F3, 'F', '3'>, Web2Qt<Qt::Key_F4, 'F', '4'>,
Web2Qt<Qt::Key_F5, 'F', '5'>, Web2Qt<Qt::Key_F6, 'F', '6'>,
Web2Qt<Qt::Key_F7, 'F', '7'>, Web2Qt<Qt::Key_F8, 'F', '8'>,
Web2Qt<Qt::Key_F9, 'F', '9'>, Web2Qt<Qt::Key_F10, 'F', '1', '0'>,
Web2Qt<Qt::Key_Help, 'H', 'e', 'l', 'p'>,
Web2Qt<Qt::Key_yen, 'I', 'n', 't', 'l', 'Y', 'e', 'n'>,
Web2Qt<Qt::Key_Menu, 'C', 'o', 'n', 't', 'e', 'x', 't', 'M', 'e', 'n',
'u'>>::Data{});
Web2Qt<Qt::Key_Home, 'H', 'o', 'm', 'e'>, Web2Qt<Qt::Key_End, 'E', 'n', 'd'>,
Web2Qt<Qt::Key_Insert, 'I', 'n', 's', 'e', 'r', 't'>,
Web2Qt<Qt::Key_Left, 'A', 'r', 'r', 'o', 'w', 'L', 'e', 'f', 't'>,
Web2Qt<Qt::Key_Meta, 'M', 'e', 't', 'a'>, Web2Qt<Qt::Key_Meta, 'O', 'S'>,
Web2Qt<Qt::Key_Menu, 'C', 'o', 'n', 't', 'e', 'x', 't', 'M', 'e', 'n', 'u'>,
Web2Qt<Qt::Key_NumLock, 'N', 'u', 'm', 'L', 'o', 'c', 'k'>,
Web2Qt<Qt::Key_PageDown, 'P', 'a', 'g', 'e', 'D', 'o', 'w', 'n'>,
Web2Qt<Qt::Key_PageUp, 'P', 'a', 'g', 'e', 'U', 'p'>,
Web2Qt<Qt::Key_Paste, 'P', 'a', 's', 't', 'e'>,
Web2Qt<Qt::Key_Pause, 'C', 'l', 'e', 'a', 'r'>,
Web2Qt<Qt::Key_Pause, 'P', 'a', 'u', 's', 'e'>,
Web2Qt<Qt::Key_QuoteLeft, 'B', 'a', 'c', 'k', 'q', 'u', 'o', 't', 'e'>,
Web2Qt<Qt::Key_QuoteLeft, 'I', 'n', 't', 'l', 'B', 'a', 'c', 'k', 's', 'l', 'a', 's', 'h'>,
Web2Qt<Qt::Key_Return, 'E', 'n', 't', 'e', 'r'>,
Web2Qt<Qt::Key_Right, 'A', 'r', 'r', 'o', 'w', 'R', 'i', 'g', 'h', 't'>,
Web2Qt<Qt::Key_ScrollLock, 'S', 'c', 'r', 'o', 'l', 'l', 'L', 'o', 'c', 'k'>,
Web2Qt<Qt::Key_Shift, 'S', 'h', 'i', 'f', 't'>,
Web2Qt<Qt::Key_Tab, 'T', 'a', 'b'>,
Web2Qt<Qt::Key_Up, 'A', 'r', 'r', 'o', 'w', 'U', 'p'>,
Web2Qt<Qt::Key_yen, 'I', 'n', 't', 'l', 'Y', 'e', 'n'>>::Data{});
static constexpr const auto WebToQtKeyCodeMappingsWithShift = qMakeArray(
static constexpr const auto DiacriticalCharsKeyToTextLowercase = qMakeArray(
QSortedData<
// shifted
Web2Qt<Qt::Key_Agrave, '\xc3', '\x80'>, Web2Qt<Qt::Key_Aacute, '\xc3', '\x81'>,
Web2Qt<Qt::Key_Aacute, '\xc3', '\xa1'>,
Web2Qt<Qt::Key_Acircumflex, '\xc3', '\xa2'>,
Web2Qt<Qt::Key_Adiaeresis, '\xc3', '\xa4'>,
Web2Qt<Qt::Key_AE, '\xc3', '\xa6'>,
Web2Qt<Qt::Key_Agrave, '\xc3', '\xa0'>,
Web2Qt<Qt::Key_Aring, '\xc3', '\xa5'>,
Web2Qt<Qt::Key_Atilde, '\xc3', '\xa3'>,
Web2Qt<Qt::Key_Ccedilla, '\xc3', '\xa7'>,
Web2Qt<Qt::Key_Eacute, '\xc3', '\xa9'>,
Web2Qt<Qt::Key_Ecircumflex, '\xc3', '\xaa'>,
Web2Qt<Qt::Key_Ediaeresis, '\xc3', '\xab'>,
Web2Qt<Qt::Key_Egrave, '\xc3', '\xa8'>,
Web2Qt<Qt::Key_Iacute, '\xc3', '\xad'>,
Web2Qt<Qt::Key_Icircumflex, '\xc3', '\xae'>,
Web2Qt<Qt::Key_Idiaeresis, '\xc3', '\xaf'>,
Web2Qt<Qt::Key_Igrave, '\xc3', '\xac'>,
Web2Qt<Qt::Key_Ntilde, '\xc3', '\xb1'>,
Web2Qt<Qt::Key_Oacute, '\xc3', '\xb3'>,
Web2Qt<Qt::Key_Ocircumflex, '\xc3', '\xb4'>,
Web2Qt<Qt::Key_Odiaeresis, '\xc3', '\xb6'>,
Web2Qt<Qt::Key_Ograve, '\xc3', '\xb2'>,
Web2Qt<Qt::Key_Ooblique, '\xc3', '\xb8'>,
Web2Qt<Qt::Key_Otilde, '\xc3', '\xb5'>,
Web2Qt<Qt::Key_Uacute, '\xc3', '\xba'>,
Web2Qt<Qt::Key_Ucircumflex, '\xc3', '\xbb'>,
Web2Qt<Qt::Key_Udiaeresis, '\xc3', '\xbc'>,
Web2Qt<Qt::Key_Ugrave, '\xc3', '\xb9'>,
Web2Qt<Qt::Key_Yacute, '\xc3', '\xbd'>,
Web2Qt<Qt::Key_ydiaeresis, '\xc3', '\xbf'>>::Data{});
static constexpr const auto DiacriticalCharsKeyToTextUppercase = qMakeArray(
QSortedData<
Web2Qt<Qt::Key_Aacute, '\xc3', '\x81'>,
Web2Qt<Qt::Key_Acircumflex, '\xc3', '\x82'>,
Web2Qt<Qt::Key_Adiaeresis, '\xc3', '\x84'>, Web2Qt<Qt::Key_AE, '\xc3', '\x86'>,
Web2Qt<Qt::Key_Atilde, '\xc3', '\x83'>, Web2Qt<Qt::Key_Aring, '\xc3', '\x85'>,
Web2Qt<Qt::Key_Egrave, '\xc3', '\x88'>, Web2Qt<Qt::Key_Eacute, '\xc3', '\x89'>,
Web2Qt<Qt::Key_Ecircumflex, '\xc3', '\x8a'>,
Web2Qt<Qt::Key_Ediaeresis, '\xc3', '\x8b'>, Web2Qt<Qt::Key_Iacute, '\xc3', '\x8d'>,
Web2Qt<Qt::Key_Icircumflex, '\xc3', '\x8e'>,
Web2Qt<Qt::Key_Idiaeresis, '\xc3', '\x8f'>, Web2Qt<Qt::Key_Igrave, '\xc3', '\x8c'>,
Web2Qt<Qt::Key_Ocircumflex, '\xc3', '\x94'>,
Web2Qt<Qt::Key_Odiaeresis, '\xc3', '\x96'>, Web2Qt<Qt::Key_Ograve, '\xc3', '\x92'>,
Web2Qt<Qt::Key_Oacute, '\xc3', '\x93'>, Web2Qt<Qt::Key_Ooblique, '\xc3', '\x98'>,
Web2Qt<Qt::Key_Otilde, '\xc3', '\x95'>, Web2Qt<Qt::Key_Ucircumflex, '\xc3', '\x9b'>,
Web2Qt<Qt::Key_Udiaeresis, '\xc3', '\x9c'>, Web2Qt<Qt::Key_Ugrave, '\xc3', '\x99'>,
Web2Qt<Qt::Key_Uacute, '\xc3', '\x9a'>, Web2Qt<Qt::Key_Ntilde, '\xc3', '\x91'>,
Web2Qt<Qt::Key_Adiaeresis, '\xc3', '\x84'>,
Web2Qt<Qt::Key_AE, '\xc3', '\x86'>,
Web2Qt<Qt::Key_Agrave, '\xc3', '\x80'>,
Web2Qt<Qt::Key_Aring, '\xc3', '\x85'>,
Web2Qt<Qt::Key_Atilde, '\xc3', '\x83'>,
Web2Qt<Qt::Key_Ccedilla, '\xc3', '\x87'>,
Web2Qt<Qt::Key_ydiaeresis, '\xc3', '\x8f'>,
Web2Qt<Qt::Key_Yacute, '\xc3', '\x9d'>>::Data{});
Web2Qt<Qt::Key_Eacute, '\xc3', '\x89'>,
Web2Qt<Qt::Key_Ecircumflex, '\xc3', '\x8a'>,
Web2Qt<Qt::Key_Ediaeresis, '\xc3', '\x8b'>,
Web2Qt<Qt::Key_Egrave, '\xc3', '\x88'>,
Web2Qt<Qt::Key_Iacute, '\xc3', '\x8d'>,
Web2Qt<Qt::Key_Icircumflex, '\xc3', '\x8e'>,
Web2Qt<Qt::Key_Idiaeresis, '\xc3', '\x8f'>,
Web2Qt<Qt::Key_Igrave, '\xc3', '\x8c'>,
Web2Qt<Qt::Key_Ntilde, '\xc3', '\x91'>,
Web2Qt<Qt::Key_Oacute, '\xc3', '\x93'>,
Web2Qt<Qt::Key_Ocircumflex, '\xc3', '\x94'>,
Web2Qt<Qt::Key_Odiaeresis, '\xc3', '\x96'>,
Web2Qt<Qt::Key_Ograve, '\xc3', '\x92'>,
Web2Qt<Qt::Key_Ooblique, '\xc3', '\x98'>,
Web2Qt<Qt::Key_Otilde, '\xc3', '\x95'>,
Web2Qt<Qt::Key_Uacute, '\xc3', '\x9a'>,
Web2Qt<Qt::Key_Ucircumflex, '\xc3', '\x9b'>,
Web2Qt<Qt::Key_Udiaeresis, '\xc3', '\x9c'>,
Web2Qt<Qt::Key_Ugrave, '\xc3', '\x99'>,
Web2Qt<Qt::Key_Yacute, '\xc3', '\x9d'>,
Web2Qt<Qt::Key_ydiaeresis, '\xc5', '\xb8'>>::Data{});
static_assert(DiacriticalCharsKeyToTextLowercase.size()
== DiacriticalCharsKeyToTextUppercase.size(),
"Add the new key to both arrays");
struct KeyMapping
{
@ -169,23 +217,15 @@ static Qt::Key find(const KeyMapping (&map)[N], Qt::Key key) noexcept
Qt::Key translateBaseKeyUsingDeadKey(Qt::Key accentBaseKey, Qt::Key deadKey)
{
switch (deadKey) {
case Qt::Key_QuoteLeft: {
// ` macOS: Key_Dead_Grave
return platform() == Platform::MacOS ? find(graveKeyTable, accentBaseKey)
: find(diaeresisKeyTable, accentBaseKey);
}
case Qt::Key_O: // ´ Key_Dead_Grave
case Qt::Key_Dead_Grave:
return find(graveKeyTable, accentBaseKey);
case Qt::Key_E: // ´ Key_Dead_Acute
case Qt::Key_Dead_Acute:
return find(acuteKeyTable, accentBaseKey);
case Qt::Key_AsciiTilde:
case Qt::Key_N: // Key_Dead_Tilde
case Qt::Key_Dead_Tilde:
return find(tildeKeyTable, accentBaseKey);
case Qt::Key_U: // ¨ Key_Dead_Diaeresis
case Qt::Key_Dead_Diaeresis:
return find(diaeresisKeyTable, accentBaseKey);
case Qt::Key_I: // macOS Key_Dead_Circumflex
case Qt::Key_6: // linux
case Qt::Key_Apostrophe: // linux
case Qt::Key_Dead_Circumflex:
return find(circumflexKeyTable, accentBaseKey);
default:
return Qt::Key_unknown;
@ -216,32 +256,38 @@ QWasmDeadKeySupport::~QWasmDeadKeySupport() = default;
void QWasmDeadKeySupport::applyDeadKeyTranslations(KeyEvent *event)
{
if (event->deadKey || event->key == Qt::Key_AltGr) {
if (event->modifiers.testFlag(Qt::ShiftModifier) && event->key == Qt::Key_QuoteLeft)
event->key = Qt::Key_AsciiTilde;
if (event->deadKey) {
m_activeDeadKey = event->key;
} else if (m_activeDeadKey != Qt::Key_unknown
&& (m_keyModifiedByDeadKeyOnPress == Qt::Key_unknown
|| m_keyModifiedByDeadKeyOnPress == event->key)) {
&& (((m_keyModifiedByDeadKeyOnPress == Qt::Key_unknown
&& event->type == EventType::KeyDown))
|| (m_keyModifiedByDeadKeyOnPress == event->key
&& event->type == EventType::KeyUp))) {
const Qt::Key baseKey = event->key;
const Qt::Key translatedKey = translateBaseKeyUsingDeadKey(baseKey, m_activeDeadKey);
if (translatedKey != Qt::Key_unknown)
if (translatedKey != Qt::Key_unknown) {
event->key = translatedKey;
if (auto foundText = event->modifiers.testFlag(Qt::ShiftModifier)
? findKeyTextByKeyId(WebToQtKeyCodeMappingsWithShift, event->key)
: findKeyTextByKeyId(WebToQtKeyCodeMappings, event->key)) {
auto foundText = event->modifiers.testFlag(Qt::ShiftModifier)
? findKeyTextByKeyId(DiacriticalCharsKeyToTextUppercase, event->key)
: findKeyTextByKeyId(DiacriticalCharsKeyToTextLowercase, event->key);
Q_ASSERT(foundText.has_value());
event->text = foundText->size() == 1 ? *foundText : QString();
}
if (!event->text.isEmpty()) {
if (event->type == EventType::KeyDown) {
Q_ASSERT(m_keyModifiedByDeadKeyOnPress == Qt::Key_unknown);
m_activeDeadKey = Qt::Key_unknown;
// Assume the first keypress with an active dead key is treated as modified,
// regardless of whether it has actually been modified or not. Take into account
// only events that produce actual key text.
if (!event->text.isEmpty())
m_keyModifiedByDeadKeyOnPress = baseKey;
} else {
Q_ASSERT(event->type == EventType::KeyUp);
Q_ASSERT(m_keyModifiedByDeadKeyOnPress == baseKey);
m_activeDeadKey = Qt::Key_unknown;
m_keyModifiedByDeadKeyOnPress = Qt::Key_unknown;
m_activeDeadKey = Qt::Key_unknown;
}
event->text = foundText->size() == 1 ? *foundText : QString();
return;
}
}
}

View File

@ -29,3 +29,14 @@ qt_internal_add_test(tst_qwasmwindowstack
Qt::Gui
Qt::Widgets
)
qt_internal_add_test(tst_qwasmkeytranslator
SOURCES
tst_qwasmkeytranslator.cpp
DEFINES
QT_NO_FOREACH
LIBRARIES
Qt::GuiPrivate
PUBLIC_LIBRARIES
Qt::Core
)

View File

@ -0,0 +1,425 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "../../../src/plugins/platforms/wasm/qwasmkeytranslator.h"
#include "../../../src/plugins/platforms/wasm/qwasmevent.h"
#include <QTest>
#include <emscripten/val.h>
namespace {
emscripten::val makeDeadKeyJsEvent(QString code, Qt::KeyboardModifiers modifiers)
{
auto jsEvent = emscripten::val::object();
jsEvent.set("code", emscripten::val(code.toStdString()));
jsEvent.set("key", emscripten::val("Dead"));
jsEvent.set("shiftKey", emscripten::val(modifiers.testFlag(Qt::ShiftModifier)));
jsEvent.set("ctrlKey", emscripten::val(false));
jsEvent.set("altKey", emscripten::val(false));
jsEvent.set("metaKey", emscripten::val(false));
return jsEvent;
}
emscripten::val makeKeyJsEvent(QString code, QString key, Qt::KeyboardModifiers modifiers)
{
auto jsEvent = emscripten::val::object();
jsEvent.set("code", emscripten::val(code.toStdString()));
jsEvent.set("key", emscripten::val(key.toStdString()));
jsEvent.set("shiftKey", emscripten::val(modifiers.testFlag(Qt::ShiftModifier)));
jsEvent.set("ctrlKey", emscripten::val(modifiers.testFlag(Qt::ControlModifier)));
jsEvent.set("altKey", emscripten::val(modifiers.testFlag(Qt::AltModifier)));
jsEvent.set("metaKey", emscripten::val(modifiers.testFlag(Qt::MetaModifier)));
return jsEvent;
}
} // unnamed namespace
class tst_QWasmKeyTranslator : public QObject
{
Q_OBJECT
public:
tst_QWasmKeyTranslator() = default;
private slots:
void init();
void modifyByDeadKey_data();
void modifyByDeadKey();
void deadKeyModifiesOnlyOneKeyPressAndUp();
void deadKeyIgnoresKeyUpPrecedingKeyDown();
void onlyKeysProducingTextAreModifiedByDeadKeys();
};
void tst_QWasmKeyTranslator::init() { }
void tst_QWasmKeyTranslator::modifyByDeadKey_data()
{
QTest::addColumn<QString>("deadKeyCode");
QTest::addColumn<Qt::KeyboardModifiers>("deadKeyModifiers");
QTest::addColumn<QString>("targetKeyCode");
QTest::addColumn<QString>("targetKey");
QTest::addColumn<Qt::Key>("targetQtKey");
QTest::addColumn<Qt::KeyboardModifiers>("modifiers");
QTest::addColumn<QString>("expectedModifiedKey");
QTest::newRow("à (Backquote)") << "Backquote" << Qt::KeyboardModifiers() << "KeyA"
<< "a" << Qt::Key_Agrave << Qt::KeyboardModifiers() << "à";
QTest::newRow("À (Backquote)")
<< "Backquote" << Qt::KeyboardModifiers() << "KeyA"
<< "A" << Qt::Key_Agrave << Qt::KeyboardModifiers(Qt::ShiftModifier) << "À";
QTest::newRow("à (IntlBackslash)") << "IntlBackslash" << Qt::KeyboardModifiers() << "KeyA"
<< "a" << Qt::Key_Agrave << Qt::KeyboardModifiers() << "à";
QTest::newRow("À (IntlBackslash)")
<< "IntlBackslash" << Qt::KeyboardModifiers() << "KeyA"
<< "A" << Qt::Key_Agrave << Qt::KeyboardModifiers(Qt::ShiftModifier) << "À";
QTest::newRow("á (Quote)") << "Quote" << Qt::KeyboardModifiers() << "KeyA"
<< "a" << Qt::Key_Aacute << Qt::KeyboardModifiers() << "á";
QTest::newRow("Á (Quote)") << "Quote" << Qt::KeyboardModifiers() << "KeyA"
<< "A" << Qt::Key_Aacute << Qt::KeyboardModifiers(Qt::ShiftModifier)
<< "Á";
QTest::newRow("á") << "KeyE" << Qt::KeyboardModifiers() << "KeyA"
<< "a" << Qt::Key_Aacute << Qt::KeyboardModifiers() << "á";
QTest::newRow("Á") << "KeyE" << Qt::KeyboardModifiers() << "KeyA"
<< "A" << Qt::Key_Aacute << Qt::KeyboardModifiers(Qt::ShiftModifier) << "Á";
QTest::newRow("ä (Mac Umlaut)") << "KeyU" << Qt::KeyboardModifiers() << "KeyA"
<< "a" << Qt::Key_Adiaeresis << Qt::KeyboardModifiers() << "ä";
QTest::newRow("Ä (Mac Umlaut)")
<< "KeyU" << Qt::KeyboardModifiers() << "KeyA"
<< "A" << Qt::Key_Adiaeresis << Qt::KeyboardModifiers(Qt::ShiftModifier) << "Ä";
QTest::newRow("ä (Shift+Quote)")
<< "Quote" << Qt::KeyboardModifiers(Qt::ShiftModifier) << "KeyA"
<< "a" << Qt::Key_Adiaeresis << Qt::KeyboardModifiers() << "ä";
QTest::newRow("Ä (Shift+Quote)")
<< "Quote" << Qt::KeyboardModifiers(Qt::ShiftModifier) << "KeyA"
<< "A" << Qt::Key_Adiaeresis << Qt::KeyboardModifiers(Qt::ShiftModifier) << "Ä";
QTest::newRow("â") << "KeyI" << Qt::KeyboardModifiers() << "KeyA"
<< "a" << Qt::Key_Acircumflex << Qt::KeyboardModifiers() << "â";
QTest::newRow("Â") << "KeyI" << Qt::KeyboardModifiers() << "KeyA"
<< "A" << Qt::Key_Acircumflex << Qt::KeyboardModifiers(Qt::ShiftModifier)
<< "Â";
QTest::newRow("â (^ key)") << "Digit6" << Qt::KeyboardModifiers(Qt::ShiftModifier) << "KeyA"
<< "a" << Qt::Key_Acircumflex << Qt::KeyboardModifiers() << "â";
QTest::newRow("Â (^ key)") << "Digit6" << Qt::KeyboardModifiers(Qt::ShiftModifier) << "KeyA"
<< "A" << Qt::Key_Acircumflex
<< Qt::KeyboardModifiers(Qt::ShiftModifier) << "Â";
QTest::newRow("ã") << "KeyN" << Qt::KeyboardModifiers() << "KeyA"
<< "a" << Qt::Key_Atilde << Qt::KeyboardModifiers() << "ã";
QTest::newRow("Ã") << "KeyN" << Qt::KeyboardModifiers() << "KeyA"
<< "A" << Qt::Key_Atilde << Qt::KeyboardModifiers(Qt::ShiftModifier) << "Ã";
QTest::newRow("è (Backquote)") << "Backquote" << Qt::KeyboardModifiers() << "KeyE"
<< "e" << Qt::Key_Egrave << Qt::KeyboardModifiers() << "è";
QTest::newRow("È (Backquote)")
<< "Backquote" << Qt::KeyboardModifiers() << "KeyE"
<< "E" << Qt::Key_Egrave << Qt::KeyboardModifiers(Qt::ShiftModifier) << "È";
QTest::newRow("è") << "IntlBackslash" << Qt::KeyboardModifiers() << "KeyE"
<< "e" << Qt::Key_Egrave << Qt::KeyboardModifiers() << "è";
QTest::newRow("È") << "IntlBackslash" << Qt::KeyboardModifiers() << "KeyE"
<< "E" << Qt::Key_Egrave << Qt::KeyboardModifiers(Qt::ShiftModifier) << "È";
QTest::newRow("é") << "KeyE" << Qt::KeyboardModifiers() << "KeyE"
<< "e" << Qt::Key_Eacute << Qt::KeyboardModifiers() << "é";
QTest::newRow("É") << "KeyE" << Qt::KeyboardModifiers() << "KeyE"
<< "E" << Qt::Key_Eacute << Qt::KeyboardModifiers(Qt::ShiftModifier) << "É";
QTest::newRow("é (Quote)") << "Quote" << Qt::KeyboardModifiers() << "KeyE"
<< "e" << Qt::Key_Eacute << Qt::KeyboardModifiers() << "é";
QTest::newRow("É (Quote)") << "Quote" << Qt::KeyboardModifiers() << "KeyE"
<< "E" << Qt::Key_Eacute << Qt::KeyboardModifiers(Qt::ShiftModifier)
<< "É";
QTest::newRow("ë (Mac Umlaut)") << "KeyU" << Qt::KeyboardModifiers() << "KeyE"
<< "e" << Qt::Key_Ediaeresis << Qt::KeyboardModifiers() << "ë";
QTest::newRow("Ë (Mac Umlaut)")
<< "KeyU" << Qt::KeyboardModifiers() << "KeyE"
<< "E" << Qt::Key_Ediaeresis << Qt::KeyboardModifiers(Qt::ShiftModifier) << "Ë";
QTest::newRow("ë (Shift+Quote)")
<< "Quote" << Qt::KeyboardModifiers(Qt::ShiftModifier) << "KeyE"
<< "e" << Qt::Key_Ediaeresis << Qt::KeyboardModifiers() << "ë";
QTest::newRow("Ë (Shift+Quote)")
<< "Quote" << Qt::KeyboardModifiers(Qt::ShiftModifier) << "KeyE"
<< "E" << Qt::Key_Ediaeresis << Qt::KeyboardModifiers(Qt::ShiftModifier) << "Ë";
QTest::newRow("ê") << "KeyI" << Qt::KeyboardModifiers() << "KeyE"
<< "e" << Qt::Key_Ecircumflex << Qt::KeyboardModifiers() << "ê";
QTest::newRow("Ê") << "KeyI" << Qt::KeyboardModifiers() << "KeyE"
<< "E" << Qt::Key_Ecircumflex << Qt::KeyboardModifiers(Qt::ShiftModifier)
<< "Ê";
QTest::newRow("ê (^ key)") << "Digit6" << Qt::KeyboardModifiers(Qt::ShiftModifier) << "KeyE"
<< "e" << Qt::Key_Ecircumflex << Qt::KeyboardModifiers() << "ê";
QTest::newRow("Ê (^ key)") << "Digit6" << Qt::KeyboardModifiers(Qt::ShiftModifier) << "KeyE"
<< "E" << Qt::Key_Ecircumflex
<< Qt::KeyboardModifiers(Qt::ShiftModifier) << "Ê";
QTest::newRow("ì (Backquote)") << "Backquote" << Qt::KeyboardModifiers() << "KeyI"
<< "i" << Qt::Key_Igrave << Qt::KeyboardModifiers() << "ì";
QTest::newRow("Ì (Backquote)")
<< "Backquote" << Qt::KeyboardModifiers() << "KeyI"
<< "I" << Qt::Key_Igrave << Qt::KeyboardModifiers(Qt::ShiftModifier) << "Ì";
QTest::newRow("ì") << "IntlBackslash" << Qt::KeyboardModifiers() << "KeyI"
<< "i" << Qt::Key_Igrave << Qt::KeyboardModifiers() << "ì";
QTest::newRow("Ì") << "IntlBackslash" << Qt::KeyboardModifiers() << "KeyI"
<< "I" << Qt::Key_Igrave << Qt::KeyboardModifiers(Qt::ShiftModifier) << "Ì";
QTest::newRow("í") << "KeyE" << Qt::KeyboardModifiers() << "KeyI"
<< "i" << Qt::Key_Iacute << Qt::KeyboardModifiers() << "í";
QTest::newRow("Í") << "KeyE" << Qt::KeyboardModifiers() << "KeyI"
<< "I" << Qt::Key_Iacute << Qt::KeyboardModifiers(Qt::ShiftModifier) << "Í";
QTest::newRow("í (Quote)") << "Quote" << Qt::KeyboardModifiers() << "KeyI"
<< "i" << Qt::Key_Iacute << Qt::KeyboardModifiers() << "í";
QTest::newRow("Í (Quote)") << "Quote" << Qt::KeyboardModifiers() << "KeyI"
<< "I" << Qt::Key_Iacute << Qt::KeyboardModifiers(Qt::ShiftModifier)
<< "Í";
QTest::newRow("ï (Mac Umlaut)") << "KeyU" << Qt::KeyboardModifiers() << "KeyI"
<< "i" << Qt::Key_Idiaeresis << Qt::KeyboardModifiers() << "ï";
QTest::newRow("Ï (Mac Umlaut)")
<< "KeyU" << Qt::KeyboardModifiers() << "KeyI"
<< "I" << Qt::Key_Idiaeresis << Qt::KeyboardModifiers(Qt::ShiftModifier) << "Ï";
QTest::newRow("ï (Shift+Quote)")
<< "Quote" << Qt::KeyboardModifiers(Qt::ShiftModifier) << "KeyI"
<< "i" << Qt::Key_Idiaeresis << Qt::KeyboardModifiers() << "ï";
QTest::newRow("Ï (Shift+Quote)")
<< "Quote" << Qt::KeyboardModifiers(Qt::ShiftModifier) << "KeyI"
<< "I" << Qt::Key_Idiaeresis << Qt::KeyboardModifiers(Qt::ShiftModifier) << "Ï";
QTest::newRow("î") << "KeyI" << Qt::KeyboardModifiers() << "KeyI"
<< "i" << Qt::Key_Icircumflex << Qt::KeyboardModifiers() << "î";
QTest::newRow("Î") << "KeyI" << Qt::KeyboardModifiers() << "KeyI"
<< "I" << Qt::Key_Icircumflex << Qt::KeyboardModifiers(Qt::ShiftModifier)
<< "Î";
QTest::newRow("î (^ key)") << "Digit6" << Qt::KeyboardModifiers() << "KeyI"
<< "i" << Qt::Key_Icircumflex << Qt::KeyboardModifiers() << "î";
QTest::newRow("Î (^ key)") << "Digit6" << Qt::KeyboardModifiers() << "KeyI"
<< "I" << Qt::Key_Icircumflex
<< Qt::KeyboardModifiers(Qt::ShiftModifier) << "Î";
QTest::newRow("ñ") << "KeyN" << Qt::KeyboardModifiers() << "KeyN"
<< "n" << Qt::Key_Ntilde << Qt::KeyboardModifiers() << "ñ";
QTest::newRow("Ñ") << "KeyN" << Qt::KeyboardModifiers() << "KeyN"
<< "N" << Qt::Key_Ntilde << Qt::KeyboardModifiers(Qt::ShiftModifier) << "Ñ";
QTest::newRow("ò (Backquote)") << "Backquote" << Qt::KeyboardModifiers() << "KeyO"
<< "o" << Qt::Key_Ograve << Qt::KeyboardModifiers() << "ò";
QTest::newRow("Ò (Backquote)")
<< "Backquote" << Qt::KeyboardModifiers() << "KeyO"
<< "O" << Qt::Key_Ograve << Qt::KeyboardModifiers(Qt::ShiftModifier) << "Ò";
QTest::newRow("ò") << "IntlBackslash" << Qt::KeyboardModifiers() << "KeyO"
<< "o" << Qt::Key_Ograve << Qt::KeyboardModifiers() << "ò";
QTest::newRow("Ò") << "IntlBackslash" << Qt::KeyboardModifiers() << "KeyO"
<< "O" << Qt::Key_Ograve << Qt::KeyboardModifiers(Qt::ShiftModifier) << "Ò";
QTest::newRow("ó") << "KeyE" << Qt::KeyboardModifiers() << "KeyO"
<< "o" << Qt::Key_Oacute << Qt::KeyboardModifiers() << "ó";
QTest::newRow("Ó") << "KeyE" << Qt::KeyboardModifiers() << "KeyO"
<< "O" << Qt::Key_Oacute << Qt::KeyboardModifiers(Qt::ShiftModifier) << "Ó";
QTest::newRow("ó (Quote)") << "Quote" << Qt::KeyboardModifiers() << "KeyO"
<< "o" << Qt::Key_Oacute << Qt::KeyboardModifiers() << "ó";
QTest::newRow("Ó (Quote)") << "Quote" << Qt::KeyboardModifiers() << "KeyO"
<< "O" << Qt::Key_Oacute << Qt::KeyboardModifiers(Qt::ShiftModifier)
<< "Ó";
QTest::newRow("ö (Mac Umlaut)") << "KeyU" << Qt::KeyboardModifiers() << "KeyO"
<< "o" << Qt::Key_Odiaeresis << Qt::KeyboardModifiers() << "ö";
QTest::newRow("Ö (Mac Umlaut)")
<< "KeyU" << Qt::KeyboardModifiers() << "KeyO"
<< "O" << Qt::Key_Odiaeresis << Qt::KeyboardModifiers(Qt::ShiftModifier) << "Ö";
QTest::newRow("ö (Shift+Quote)")
<< "Quote" << Qt::KeyboardModifiers(Qt::ShiftModifier) << "KeyO"
<< "o" << Qt::Key_Odiaeresis << Qt::KeyboardModifiers() << "ö";
QTest::newRow("Ö (Shift+Quote)")
<< "Quote" << Qt::KeyboardModifiers(Qt::ShiftModifier) << "KeyO"
<< "O" << Qt::Key_Odiaeresis << Qt::KeyboardModifiers(Qt::ShiftModifier) << "Ö";
QTest::newRow("ô") << "KeyI" << Qt::KeyboardModifiers() << "KeyO"
<< "o" << Qt::Key_Ocircumflex << Qt::KeyboardModifiers() << "ô";
QTest::newRow("Ô") << "KeyI" << Qt::KeyboardModifiers() << "KeyO"
<< "O" << Qt::Key_Ocircumflex << Qt::KeyboardModifiers(Qt::ShiftModifier)
<< "Ô";
QTest::newRow("ô (^ key)") << "Digit6" << Qt::KeyboardModifiers(Qt::ShiftModifier) << "KeyO"
<< "o" << Qt::Key_Ocircumflex << Qt::KeyboardModifiers() << "ô";
QTest::newRow("Ô (^ key)") << "Digit6" << Qt::KeyboardModifiers(Qt::ShiftModifier) << "KeyO"
<< "O" << Qt::Key_Ocircumflex
<< Qt::KeyboardModifiers(Qt::ShiftModifier) << "Ô";
QTest::newRow("õ") << "KeyN" << Qt::KeyboardModifiers() << "KeyO"
<< "o" << Qt::Key_Otilde << Qt::KeyboardModifiers() << "õ";
QTest::newRow("Õ") << "KeyN" << Qt::KeyboardModifiers() << "KeyO"
<< "O" << Qt::Key_Otilde << Qt::KeyboardModifiers(Qt::ShiftModifier) << "Õ";
QTest::newRow("ù (Backquote)") << "Backquote" << Qt::KeyboardModifiers() << "KeyU"
<< "u" << Qt::Key_Ugrave << Qt::KeyboardModifiers() << "ù";
QTest::newRow("Ù (Backquote)")
<< "Backquote" << Qt::KeyboardModifiers() << "KeyU"
<< "U" << Qt::Key_Ugrave << Qt::KeyboardModifiers(Qt::ShiftModifier) << "Ù";
QTest::newRow("ù") << "IntlBackslash" << Qt::KeyboardModifiers() << "KeyU"
<< "u" << Qt::Key_Ugrave << Qt::KeyboardModifiers() << "ù";
QTest::newRow("Ù") << "IntlBackslash" << Qt::KeyboardModifiers() << "KeyU"
<< "U" << Qt::Key_Ugrave << Qt::KeyboardModifiers(Qt::ShiftModifier) << "Ù";
QTest::newRow("ú") << "KeyE" << Qt::KeyboardModifiers() << "KeyU"
<< "u" << Qt::Key_Uacute << Qt::KeyboardModifiers() << "ú";
QTest::newRow("Ú") << "KeyE" << Qt::KeyboardModifiers() << "KeyU"
<< "U" << Qt::Key_Uacute << Qt::KeyboardModifiers(Qt::ShiftModifier) << "Ú";
QTest::newRow("ú (Quote)") << "Quote" << Qt::KeyboardModifiers() << "KeyU"
<< "u" << Qt::Key_Uacute << Qt::KeyboardModifiers() << "ú";
QTest::newRow("Ú (Quote)") << "Quote" << Qt::KeyboardModifiers() << "KeyU"
<< "U" << Qt::Key_Uacute << Qt::KeyboardModifiers(Qt::ShiftModifier)
<< "Ú";
QTest::newRow("ü (Mac Umlaut)") << "KeyU" << Qt::KeyboardModifiers() << "KeyU"
<< "u" << Qt::Key_Udiaeresis << Qt::KeyboardModifiers() << "ü";
QTest::newRow("Ü (Mac Umlaut)")
<< "KeyU" << Qt::KeyboardModifiers() << "KeyU"
<< "U" << Qt::Key_Udiaeresis << Qt::KeyboardModifiers(Qt::ShiftModifier) << "Ü";
QTest::newRow("ü (Shift+Quote)")
<< "Quote" << Qt::KeyboardModifiers(Qt::ShiftModifier) << "KeyU"
<< "u" << Qt::Key_Udiaeresis << Qt::KeyboardModifiers() << "ü";
QTest::newRow("Ü (Shift+Quote)")
<< "Quote" << Qt::KeyboardModifiers(Qt::ShiftModifier) << "KeyU"
<< "U" << Qt::Key_Udiaeresis << Qt::KeyboardModifiers(Qt::ShiftModifier) << "Ü";
QTest::newRow("û") << "KeyI" << Qt::KeyboardModifiers() << "KeyU"
<< "û" << Qt::Key_Ucircumflex << Qt::KeyboardModifiers() << "û";
QTest::newRow("Û") << "KeyI" << Qt::KeyboardModifiers() << "KeyU"
<< "U" << Qt::Key_Ucircumflex << Qt::KeyboardModifiers(Qt::ShiftModifier)
<< "Û";
QTest::newRow("û (^ key)") << "Digit6" << Qt::KeyboardModifiers(Qt::ShiftModifier) << "KeyU"
<< "û" << Qt::Key_Ucircumflex << Qt::KeyboardModifiers() << "û";
QTest::newRow("Û (^ key)") << "Digit6" << Qt::KeyboardModifiers(Qt::ShiftModifier) << "KeyU"
<< "U" << Qt::Key_Ucircumflex
<< Qt::KeyboardModifiers(Qt::ShiftModifier) << "Û";
QTest::newRow("ý") << "KeyE" << Qt::KeyboardModifiers() << "KeyY"
<< "y" << Qt::Key_Yacute << Qt::KeyboardModifiers() << "ý";
QTest::newRow("Ý") << "KeyE" << Qt::KeyboardModifiers() << "KeyY"
<< "Y" << Qt::Key_Yacute << Qt::KeyboardModifiers(Qt::ShiftModifier) << "Ý";
QTest::newRow("ý (Quote)") << "Quote" << Qt::KeyboardModifiers() << "KeyY"
<< "y" << Qt::Key_Yacute << Qt::KeyboardModifiers() << "ý";
QTest::newRow("Ý (Quote)") << "Quote" << Qt::KeyboardModifiers() << "KeyY"
<< "Y" << Qt::Key_Yacute << Qt::KeyboardModifiers(Qt::ShiftModifier)
<< "Ý";
QTest::newRow("ÿ (Mac Umlaut)") << "KeyU" << Qt::KeyboardModifiers() << "KeyY"
<< "y" << Qt::Key_ydiaeresis << Qt::KeyboardModifiers() << "ÿ";
QTest::newRow("Ÿ (Mac Umlaut)")
<< "KeyU" << Qt::KeyboardModifiers() << "KeyY"
<< "Y" << Qt::Key_ydiaeresis << Qt::KeyboardModifiers(Qt::ShiftModifier) << "Ÿ";
QTest::newRow("ÿ (Shift+Quote)")
<< "Quote" << Qt::KeyboardModifiers(Qt::ShiftModifier) << "KeyY"
<< "y" << Qt::Key_ydiaeresis << Qt::KeyboardModifiers() << "ÿ";
QTest::newRow("Ÿ (Shift+Quote)")
<< "Quote" << Qt::KeyboardModifiers(Qt::ShiftModifier) << "KeyY"
<< "Y" << Qt::Key_ydiaeresis << Qt::KeyboardModifiers(Qt::ShiftModifier) << "Ÿ";
}
void tst_QWasmKeyTranslator::modifyByDeadKey()
{
QFETCH(QString, deadKeyCode);
QFETCH(Qt::KeyboardModifiers, deadKeyModifiers);
QFETCH(QString, targetKeyCode);
QFETCH(QString, targetKey);
QFETCH(Qt::Key, targetQtKey);
QFETCH(Qt::KeyboardModifiers, modifiers);
QFETCH(QString, expectedModifiedKey);
QWasmDeadKeySupport deadKeySupport;
KeyEvent event(EventType::KeyDown, makeDeadKeyJsEvent(deadKeyCode, deadKeyModifiers));
QCOMPARE(event.deadKey, true);
deadKeySupport.applyDeadKeyTranslations(&event);
KeyEvent eDown(EventType::KeyDown, makeKeyJsEvent(targetKeyCode, targetKey, modifiers));
QCOMPARE(eDown.deadKey, false);
deadKeySupport.applyDeadKeyTranslations(&eDown);
QCOMPARE(eDown.deadKey, false);
QCOMPARE(eDown.text, expectedModifiedKey);
QCOMPARE(eDown.key, targetQtKey);
KeyEvent eUp(EventType::KeyUp, makeKeyJsEvent(targetKeyCode, targetKey, modifiers));
QCOMPARE(eUp.deadKey, false);
deadKeySupport.applyDeadKeyTranslations(&eUp);
QCOMPARE(eUp.text, expectedModifiedKey);
QCOMPARE(eUp.key, targetQtKey);
}
void tst_QWasmKeyTranslator::deadKeyModifiesOnlyOneKeyPressAndUp()
{
QWasmDeadKeySupport deadKeySupport;
KeyEvent event(EventType::KeyDown, makeDeadKeyJsEvent("KeyU", Qt::KeyboardModifiers()));
deadKeySupport.applyDeadKeyTranslations(&event);
KeyEvent eDown(EventType::KeyDown, makeKeyJsEvent("KeyU", "u", Qt::KeyboardModifiers()));
deadKeySupport.applyDeadKeyTranslations(&eDown);
QCOMPARE(eDown.text, "ü");
QCOMPARE(eDown.key, Qt::Key_Udiaeresis);
KeyEvent eUp(EventType::KeyUp, makeKeyJsEvent("KeyU", "u", Qt::KeyboardModifiers()));
deadKeySupport.applyDeadKeyTranslations(&eUp);
QCOMPARE(eUp.text, "ü");
QCOMPARE(eUp.key, Qt::Key_Udiaeresis);
KeyEvent eDown2(EventType::KeyDown, makeKeyJsEvent("KeyU", "u", Qt::KeyboardModifiers()));
deadKeySupport.applyDeadKeyTranslations(&eDown2);
QCOMPARE(eDown2.text, "u");
QCOMPARE(eDown2.key, Qt::Key_U);
KeyEvent eUp2(EventType::KeyUp, makeKeyJsEvent("KeyU", "u", Qt::KeyboardModifiers()));
deadKeySupport.applyDeadKeyTranslations(&eUp2);
QCOMPARE(eUp2.text, "u");
QCOMPARE(eUp2.key, Qt::Key_U);
}
void tst_QWasmKeyTranslator::deadKeyIgnoresKeyUpPrecedingKeyDown()
{
QWasmDeadKeySupport deadKeySupport;
KeyEvent deadKeyDownEvent(EventType::KeyDown,
makeDeadKeyJsEvent("KeyU", Qt::KeyboardModifiers()));
deadKeySupport.applyDeadKeyTranslations(&deadKeyDownEvent);
KeyEvent deadKeyUpEvent(EventType::KeyUp, makeDeadKeyJsEvent("KeyU", Qt::KeyboardModifiers()));
deadKeySupport.applyDeadKeyTranslations(&deadKeyUpEvent);
KeyEvent otherKeyUpEvent(EventType::KeyUp,
makeKeyJsEvent("AltLeft", "Alt", Qt::KeyboardModifiers()));
deadKeySupport.applyDeadKeyTranslations(&otherKeyUpEvent);
KeyEvent eDown(EventType::KeyDown, makeKeyJsEvent("KeyU", "u", Qt::KeyboardModifiers()));
deadKeySupport.applyDeadKeyTranslations(&eDown);
QCOMPARE(eDown.text, "ü");
QCOMPARE(eDown.key, Qt::Key_Udiaeresis);
KeyEvent yetAnotherKeyUpEvent(
EventType::KeyUp, makeKeyJsEvent("ControlLeft", "Control", Qt::KeyboardModifiers()));
deadKeySupport.applyDeadKeyTranslations(&yetAnotherKeyUpEvent);
KeyEvent eUp(EventType::KeyUp, makeKeyJsEvent("KeyU", "u", Qt::KeyboardModifiers()));
deadKeySupport.applyDeadKeyTranslations(&eUp);
QCOMPARE(eUp.text, "ü");
QCOMPARE(eUp.key, Qt::Key_Udiaeresis);
}
void tst_QWasmKeyTranslator::onlyKeysProducingTextAreModifiedByDeadKeys()
{
QWasmDeadKeySupport deadKeySupport;
KeyEvent deadKeyDownEvent(EventType::KeyDown,
makeDeadKeyJsEvent("KeyU", Qt::KeyboardModifiers()));
deadKeySupport.applyDeadKeyTranslations(&deadKeyDownEvent);
KeyEvent noTextKeyDown(EventType::KeyDown,
makeKeyJsEvent("AltLeft", "Alt", Qt::KeyboardModifiers()));
deadKeySupport.applyDeadKeyTranslations(&noTextKeyDown);
QCOMPARE(noTextKeyDown.text, "");
QCOMPARE(noTextKeyDown.key, Qt::Key_Alt);
KeyEvent noTextKeyUp(EventType::KeyUp,
makeKeyJsEvent("AltLeft", "Alt", Qt::KeyboardModifiers()));
deadKeySupport.applyDeadKeyTranslations(&noTextKeyUp);
QCOMPARE(noTextKeyDown.text, "");
QCOMPARE(noTextKeyDown.key, Qt::Key_Alt);
KeyEvent eDown(EventType::KeyDown, makeKeyJsEvent("KeyU", "u", Qt::KeyboardModifiers()));
deadKeySupport.applyDeadKeyTranslations(&eDown);
QCOMPARE(eDown.text, "ü");
QCOMPARE(eDown.key, Qt::Key_Udiaeresis);
KeyEvent eUp(EventType::KeyUp, makeKeyJsEvent("KeyU", "u", Qt::KeyboardModifiers()));
deadKeySupport.applyDeadKeyTranslations(&eUp);
QCOMPARE(eUp.text, "ü");
QCOMPARE(eUp.key, Qt::Key_Udiaeresis);
}
QTEST_MAIN(tst_QWasmKeyTranslator)
#include "tst_qwasmkeytranslator.moc"