Description: Add tablet support for WebAssembly. Browsers like Chromium support
stylus input, which will arrive as "pen" events. These must be interpreted as
tablet events and mouse events must be synthesized by Qt.

--- a/src/plugins/platforms/wasm/qwasmevent.cpp
+++ b/src/plugins/platforms/wasm/qwasmevent.cpp
@@ -177,11 +177,17 @@
             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>();
 }

--- a/src/plugins/platforms/wasm/qwasmevent.h
+++ b/src/plugins/platforms/wasm/qwasmevent.h
@@ -35,6 +35,7 @@
 enum class PointerType {
     Mouse,
     Touch,
+    Pen,
     Other,
 };

@@ -214,6 +215,10 @@
     PointerType pointerType;
     int pointerId;
     qreal pressure;
+    qreal tiltX;
+    qreal tiltY;
+    qreal tangentialPressure;
+    qreal twist;
     qreal width;
     qreal height;
     bool isPrimary;
--- a/src/plugins/platforms/wasm/qwasmintegration.cpp
+++ b/src/plugins/platforms/wasm/qwasmintegration.cpp
@@ -22,6 +22,7 @@
 #include <qpa/qwindowsysteminterface.h>
 #include <QtCore/qcoreapplication.h>
 #include <qpa/qplatforminputcontextfactory_p.h>
+#include <qpa/qwindowsysteminterface_p.h>

 #include <emscripten/bind.h>
 #include <emscripten/val.h>
@@ -95,6 +96,7 @@
         qt_set_sequence_auto_mnemonic(false);

     touchPoints = emscripten::val::global("navigator")["maxTouchPoints"].as<int>();
+    QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false);

     // Create screens for container elements. Each container element will ultimately become a
     // div element. Qt historically supported supplying canvas for screen elements - these elements
--- a/src/plugins/platforms/wasm/qwasmscreen.cpp
+++ b/src/plugins/platforms/wasm/qwasmscreen.cpp
@@ -92,6 +92,16 @@
             QPointingDevice::Capability::Position | QPointingDevice::Capability::Area
                     | QPointingDevice::Capability::NormalizedPosition,
             10, 0);
+    m_tabletDevice = std::make_unique<QPointingDevice>(
+            "stylus", 2, QInputDevice::DeviceType::Stylus,
+            QPointingDevice::PointerType::Pen,
+            QPointingDevice::Capability::Position | QPointingDevice::Capability::Pressure
+                | QPointingDevice::Capability::NormalizedPosition
+                | QInputDevice::Capability::MouseEmulation
+                | QInputDevice::Capability::Hover | QInputDevice::Capability::Rotation
+                | QInputDevice::Capability::XTilt | QInputDevice::Capability::YTilt
+                | QInputDevice::Capability::TangentialPressure,
+            0, 0);

     QWindowSystemInterface::registerInputDevice(m_touchDevice.get());
 }
--- a/src/plugins/platforms/wasm/qwasmscreen.h
+++ b/src/plugins/platforms/wasm/qwasmscreen.h
@@ -37,6 +37,7 @@
     QString eventTargetId() const;
     QString outerScreenId() const;
     QPointingDevice *touchDevice() { return m_touchDevice.get(); }
+    QPointingDevice *tabletDevice() { return m_tabletDevice.get(); }

     QWasmCompositor *compositor();
     QWasmDeadKeySupport *deadKeySupport() { return m_deadKeySupport.get(); }
@@ -70,6 +71,7 @@
     emscripten::val m_shadowContainer;
     std::unique_ptr<QWasmCompositor> m_compositor;
     std::unique_ptr<QPointingDevice> m_touchDevice;
+    std::unique_ptr<QPointingDevice> m_tabletDevice;
     std::unique_ptr<QWasmDeadKeySupport> m_deadKeySupport;
     QRect m_geometry = QRect(0, 0, 100, 100);
     int m_depth = 32;
--- a/src/plugins/platforms/wasm/qwasmwindowclientarea.cpp
+++ b/src/plugins/platforms/wasm/qwasmwindowclientarea.cpp
@@ -91,6 +91,31 @@
                         eventType, event.modifiers);
     }

+    if (event.pointerType == PointerType::Pen) {
+        qreal pressure;
+        switch (event.type) {
+            case EventType::PointerDown :
+            case EventType::PointerMove :
+                pressure = event.pressure;
+                break;
+            case EventType::PointerUp :
+                pressure = 0.0;
+                break;
+            default:
+                return false;
+        }
+        // Tilt in the browser is in the range +-90, but QTabletEvent only goes to +-60.
+        qreal xTilt = qBound(-60.0, event.tiltX, 60.0);
+        qreal yTilt = qBound(-60.0, event.tiltY, 60.0);
+        // Barrel rotation is reported as 0 to 359, but QTabletEvent wants a signed value.
+        qreal rotation = event.twist > 180.0 ? 360.0 - event.twist : event.twist;
+        return QWindowSystemInterface::handleTabletEvent(
+            m_window->window(), QWasmIntegration::getTimestamp(), m_screen->tabletDevice(),
+            m_window->window()->mapFromGlobal(targetPointClippedToScreen),
+            targetPointClippedToScreen, event.mouseButtons, pressure, xTilt, yTilt,
+            event.tangentialPressure, rotation, event.modifiers);
+    }
+
     QWindowSystemInterface::TouchPoint *touchPoint;

     QPointF pointInTargetWindowCoords =
--- a/src/plugins/platforms/wasm/qwasmwindow.cpp
+++ b/src/plugins/platforms/wasm/qwasmwindow.cpp
@@ -492,7 +492,7 @@

 bool QWasmWindow::processPointer(const PointerEvent &event)
 {
-    if (event.pointerType != PointerType::Mouse)
+    if (event.pointerType != PointerType::Mouse && event.pointerType != PointerType::Pen)
         return false;

     switch (event.type) {
