// Copyright (C) 2022 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #ifndef QWASMEVENT_H #define QWASMEVENT_H #include "qwasmplatform.h" #include "qwasmdom.h" #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE class QWasmDeadKeySupport; class QWindow; enum class EventType { DragEnd, DragOver, DragStart, Drop, KeyDown, KeyUp, PointerDown, PointerMove, PointerUp, PointerEnter, PointerLeave, PointerCancel, Wheel, }; enum class PointerType { Mouse, Touch, Pen, Other, }; enum class WindowArea { NonClient, Client, }; enum class DeltaMode { Pixel, Line, Page }; namespace KeyboardModifier { namespace internal { // Check for the existence of shiftKey, ctrlKey, altKey and metaKey in a type. // Based on that, we can safely assume we are dealing with an emscripten event type. template struct IsEmscriptenEvent { template struct SFINAE {}; template static char Test( SFINAE*); template static int Test(...); static const bool value = sizeof(Test(0)) == sizeof(char); }; template struct Helper; template struct Helper::value>> { static QFlags getModifierForEvent(const T& event) { QFlags keyModifier = Qt::NoModifier; if (event.shiftKey) keyModifier |= Qt::ShiftModifier; if (event.ctrlKey) keyModifier |= platform() == Platform::MacOS ? Qt::MetaModifier : Qt::ControlModifier; if (event.altKey) keyModifier |= Qt::AltModifier; if (event.metaKey) keyModifier |= platform() == Platform::MacOS ? Qt::ControlModifier : Qt::MetaModifier; return keyModifier; } }; template<> struct Helper { static QFlags getModifierForEvent(const emscripten::val& event) { QFlags keyModifier = Qt::NoModifier; if (event["shiftKey"].as()) keyModifier |= Qt::ShiftModifier; if (event["ctrlKey"].as()) keyModifier |= platform() == Platform::MacOS ? Qt::MetaModifier : Qt::ControlModifier; if (event["altKey"].as()) keyModifier |= Qt::AltModifier; if (event["metaKey"].as()) keyModifier |= platform() == Platform::MacOS ? Qt::ControlModifier : Qt::MetaModifier; if (event["constructor"]["name"].as() == "KeyboardEvent" && event["location"].as() == DOM_KEY_LOCATION_NUMPAD) { keyModifier |= Qt::KeypadModifier; } return keyModifier; } }; } // namespace internal template QFlags getForEvent(const Event& event) { return internal::Helper::getModifierForEvent(event); } template <> QFlags getForEvent( const EmscriptenKeyboardEvent& event); } // namespace KeyboardModifier struct Event { Event(EventType type, emscripten::val webEvent); ~Event(); Event(const Event &other); Event(Event &&other); Event &operator=(const Event &other); Event &operator=(Event &&other); emscripten::val webEvent; EventType type; emscripten::val target() const { return webEvent["target"]; } }; struct KeyEvent : public Event { static std::optional fromWebWithDeadKeyTranslation(emscripten::val webEvent, QWasmDeadKeySupport *deadKeySupport); KeyEvent(EventType type, emscripten::val webEvent); ~KeyEvent(); KeyEvent(const KeyEvent &other); KeyEvent(KeyEvent &&other); KeyEvent &operator=(const KeyEvent &other); KeyEvent &operator=(KeyEvent &&other); Qt::Key key; QFlags modifiers; bool deadKey; QString text; }; struct MouseEvent : public Event { MouseEvent(EventType type, emscripten::val webEvent); ~MouseEvent(); MouseEvent(const MouseEvent &other); MouseEvent(MouseEvent &&other); MouseEvent &operator=(const MouseEvent &other); MouseEvent &operator=(MouseEvent &&other); static constexpr Qt::MouseButton buttonFromWeb(int webButton) { switch (webButton) { case 0: return Qt::LeftButton; case 1: return Qt::MiddleButton; case 2: return Qt::RightButton; default: return Qt::NoButton; } } static constexpr Qt::MouseButtons buttonsFromWeb(unsigned short webButtons) { // Coincidentally, Qt and web bitfields match. return Qt::MouseButtons::fromInt(webButtons); } static constexpr QEvent::Type mouseEventTypeFromEventType( EventType eventType, WindowArea windowArea) { switch (eventType) { case EventType::PointerDown : return windowArea == WindowArea::Client ? QEvent::MouseButtonPress : QEvent::NonClientAreaMouseButtonPress; case EventType::PointerUp : return windowArea == WindowArea::Client ? QEvent::MouseButtonRelease : QEvent::NonClientAreaMouseButtonRelease; case EventType::PointerMove : return windowArea == WindowArea::Client ? QEvent::MouseMove : QEvent::NonClientAreaMouseMove; default: return QEvent::None; } } QPointF localPoint; QPointF pointInPage; QPointF pointInViewport; Qt::MouseButton mouseButton; Qt::MouseButtons mouseButtons; QFlags modifiers; }; struct PointerEvent : public MouseEvent { static std::optional fromWeb(emscripten::val webEvent); PointerEvent(EventType type, emscripten::val webEvent); ~PointerEvent(); PointerEvent(const PointerEvent &other); PointerEvent(PointerEvent &&other); PointerEvent &operator=(const PointerEvent &other); PointerEvent &operator=(PointerEvent &&other); PointerType pointerType; int pointerId; qreal pressure; qreal tiltX; qreal tiltY; qreal tangentialPressure; qreal twist; qreal width; qreal height; bool isPrimary; }; struct DragEvent : public MouseEvent { static std::optional fromWeb(emscripten::val webEvent, QWindow *targetQWindow); DragEvent(EventType type, emscripten::val webEvent, QWindow *targetQWindow); ~DragEvent(); DragEvent(const DragEvent &other); DragEvent(DragEvent &&other); DragEvent &operator=(const DragEvent &other); DragEvent &operator=(DragEvent &&other); void cancelDragStart(); void acceptDragOver(); void acceptDrop(); Qt::DropAction dropAction; dom::DataTransfer dataTransfer; QWindow *targetWindow; }; struct WheelEvent : public MouseEvent { static std::optional fromWeb(emscripten::val webEvent); WheelEvent(EventType type, emscripten::val webEvent); ~WheelEvent(); WheelEvent(const WheelEvent &other); WheelEvent(WheelEvent &&other); WheelEvent &operator=(const WheelEvent &other); WheelEvent &operator=(WheelEvent &&other); DeltaMode deltaMode; bool webkitDirectionInvertedFromDevice; QPointF delta; }; QT_END_NAMESPACE #endif // QWASMEVENT_H