diff options
Diffstat (limited to 'src/plugins/platforms/wasm/qwasmevent.cpp')
-rw-r--r-- | src/plugins/platforms/wasm/qwasmevent.cpp | 184 |
1 files changed, 172 insertions, 12 deletions
diff --git a/src/plugins/platforms/wasm/qwasmevent.cpp b/src/plugins/platforms/wasm/qwasmevent.cpp index eb2c8c145a..e418263655 100644 --- a/src/plugins/platforms/wasm/qwasmevent.cpp +++ b/src/plugins/platforms/wasm/qwasmevent.cpp @@ -3,8 +3,78 @@ #include "qwasmevent.h" +#include "qwasmkeytranslator.h" + +#include <QtCore/private/qmakearray_p.h> +#include <QtCore/private/qstringiterator_p.h> +#include <QtCore/qregularexpression.h> + QT_BEGIN_NAMESPACE +namespace { +constexpr std::string_view WebDeadKeyValue = "Dead"; + +bool isDeadKeyEvent(const char *key) +{ + return qstrncmp(key, WebDeadKeyValue.data(), WebDeadKeyValue.size()) == 0; +} + +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) { + 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; + } + + // 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)); +} +} // namespace + namespace KeyboardModifier { template <> @@ -16,7 +86,10 @@ QFlags<Qt::KeyboardModifier> getForEvent<EmscriptenKeyboardEvent>( } } // namespace KeyboardModifier -Event::Event(EventType type, emscripten::val target) : type(type), target(target) { } +Event::Event(EventType type, emscripten::val webEvent) + : webEvent(webEvent), type(type) +{ +} Event::~Event() = default; @@ -28,7 +101,55 @@ Event &Event::operator=(const Event &other) = default; Event &Event::operator=(Event &&other) = default; -MouseEvent::MouseEvent(EventType type, emscripten::val event) : Event(type, event["target"]) +KeyEvent::KeyEvent(EventType type, emscripten::val event) : Event(type, event) +{ + const auto code = event["code"].as<std::string>(); + const auto webKey = event["key"].as<std::string>(); + deadKey = isDeadKeyEvent(webKey.c_str()); + autoRepeat = event["repeat"].as<bool>(); + modifiers = KeyboardModifier::getForEvent(event); + key = webKeyToQtKey(code, webKey, deadKey, modifiers); + + text = QString::fromUtf8(webKey); + if (text.size() > 1) + text.clear(); + + if (key == Qt::Key_Tab) + text = "\t"; +} + +KeyEvent::~KeyEvent() = default; + +KeyEvent::KeyEvent(const KeyEvent &other) = default; + +KeyEvent::KeyEvent(KeyEvent &&other) = default; + +KeyEvent &KeyEvent::operator=(const KeyEvent &other) = default; + +KeyEvent &KeyEvent::operator=(KeyEvent &&other) = default; + +std::optional<KeyEvent> KeyEvent::fromWebWithDeadKeyTranslation(emscripten::val event, + QWasmDeadKeySupport *deadKeySupport) +{ + const auto eventType = ([&event]() -> std::optional<EventType> { + const auto eventTypeString = event["type"].as<std::string>(); + + if (eventTypeString == "keydown") + return EventType::KeyDown; + else if (eventTypeString == "keyup") + return EventType::KeyUp; + return std::nullopt; + })(); + if (!eventType) + return std::nullopt; + + auto result = KeyEvent(*eventType, event); + deadKeySupport->applyDeadKeyTranslations(&result); + + return result; +} + +MouseEvent::MouseEvent(EventType type, emscripten::val event) : Event(type, event) { mouseButton = MouseEvent::buttonFromWeb(event["button"].as<int>()); mouseButtons = MouseEvent::buttonsFromWeb(event["buttons"].as<unsigned short>()); @@ -38,9 +159,9 @@ MouseEvent::MouseEvent(EventType type, emscripten::val event) : Event(type, even // it up here. if (type == EventType::PointerDown) mouseButtons |= mouseButton; - localPoint = QPoint(event["offsetX"].as<int>(), event["offsetY"].as<int>()); - pointInPage = QPoint(event["pageX"].as<int>(), event["pageY"].as<int>()); - pointInViewport = QPoint(event["clientX"].as<int>(), event["clientY"].as<int>()); + localPoint = QPointF(event["offsetX"].as<qreal>(), event["offsetY"].as<qreal>()); + pointInPage = QPointF(event["pageX"].as<qreal>(), event["pageY"].as<qreal>()); + pointInViewport = QPointF(event["clientX"].as<qreal>(), event["clientY"].as<qreal>()); modifiers = KeyboardModifier::getForEvent(event); } @@ -57,8 +178,23 @@ MouseEvent &MouseEvent::operator=(MouseEvent &&other) = default; PointerEvent::PointerEvent(EventType type, emscripten::val event) : MouseEvent(type, event) { pointerId = event["pointerId"].as<int>(); - pointerType = event["pointerType"].as<std::string>() == "mouse" ? PointerType::Mouse - : PointerType::Other; + pointerType = ([type = event["pointerType"].as<std::string>()]() { + if (type == "mouse") + return PointerType::Mouse; + if (type == "touch") + return PointerType::Touch; + if (type == "pen") + return PointerType::Pen; + return PointerType::Other; + })(); + width = event["width"].as<qreal>(); + height = event["height"].as<qreal>(); + pressure = event["pressure"].as<qreal>(); + tiltX = event["tiltX"].as<qreal>(); + tiltY = event["tiltY"].as<qreal>(); + tangentialPressure = event["tangentialPressure"].as<qreal>(); + twist = event["twist"].as<qreal>(); + isPrimary = event["isPrimary"].as<bool>(); } PointerEvent::~PointerEvent() = default; @@ -94,8 +230,8 @@ std::optional<PointerEvent> PointerEvent::fromWeb(emscripten::val event) return PointerEvent(*eventType, event); } -DragEvent::DragEvent(EventType type, emscripten::val event) - : MouseEvent(type, event), dataTransfer(event["dataTransfer"]) +DragEvent::DragEvent(EventType type, emscripten::val event, QWindow *window) + : MouseEvent(type, event), dataTransfer(event["dataTransfer"]), targetWindow(window) { dropAction = ([event]() { const std::string effect = event["dataTransfer"]["dropEffect"].as<std::string>(); @@ -120,18 +256,42 @@ DragEvent &DragEvent::operator=(const DragEvent &other) = default; DragEvent &DragEvent::operator=(DragEvent &&other) = default; -std::optional<DragEvent> DragEvent::fromWeb(emscripten::val event) +std::optional<DragEvent> DragEvent::fromWeb(emscripten::val event, QWindow *targetWindow) { const auto eventType = ([&event]() -> std::optional<EventType> { const auto eventTypeString = event["type"].as<std::string>(); + if (eventTypeString == "dragend") + return EventType::DragEnd; + if (eventTypeString == "dragover") + return EventType::DragOver; + if (eventTypeString == "dragstart") + return EventType::DragStart; if (eventTypeString == "drop") return EventType::Drop; return std::nullopt; })(); if (!eventType) return std::nullopt; - return DragEvent(*eventType, event); + return DragEvent(*eventType, event, targetWindow); +} + +void DragEvent::cancelDragStart() +{ + Q_ASSERT_X(type == EventType::DragStart, Q_FUNC_INFO, "Only supported for DragStart"); + webEvent.call<void>("preventDefault"); +} + +void DragEvent::acceptDragOver() +{ + Q_ASSERT_X(type == EventType::DragOver, Q_FUNC_INFO, "Only supported for DragOver"); + webEvent.call<void>("preventDefault"); +} + +void DragEvent::acceptDrop() +{ + Q_ASSERT_X(type == EventType::Drop, Q_FUNC_INFO, "Only supported for Drop"); + webEvent.call<void>("preventDefault"); } WheelEvent::WheelEvent(EventType type, emscripten::val event) : MouseEvent(type, event) @@ -146,7 +306,7 @@ WheelEvent::WheelEvent(EventType type, emscripten::val event) : MouseEvent(type, return DeltaMode::Page; })(); - delta = QPoint(event["deltaX"].as<int>(), event["deltaY"].as<int>()); + delta = QPointF(event["deltaX"].as<qreal>(), event["deltaY"].as<qreal>()); webkitDirectionInvertedFromDevice = event["webkitDirectionInvertedFromDevice"].as<bool>(); } |