summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/platforms/wasm/CMakeLists.txt2
-rw-r--r--src/plugins/platforms/wasm/qwasmcompositor.cpp300
-rw-r--r--src/plugins/platforms/wasm/qwasmcompositor.h85
-rw-r--r--src/plugins/platforms/wasm/qwasmdrag.cpp3
-rw-r--r--src/plugins/platforms/wasm/qwasmevent.cpp53
-rw-r--r--src/plugins/platforms/wasm/qwasmevent.h145
-rw-r--r--src/plugins/platforms/wasm/qwasmeventtranslator.cpp48
-rw-r--r--src/plugins/platforms/wasm/qwasmeventtranslator.h20
-rw-r--r--src/plugins/platforms/wasm/qwasminputcontext.cpp15
-rw-r--r--src/plugins/platforms/wasm/qwasmintegration.cpp16
-rw-r--r--src/plugins/platforms/wasm/qwasmintegration.h10
-rw-r--r--src/plugins/platforms/wasm/qwasmplatform.cpp31
-rw-r--r--src/plugins/platforms/wasm/qwasmplatform.h29
13 files changed, 510 insertions, 247 deletions
diff --git a/src/plugins/platforms/wasm/CMakeLists.txt b/src/plugins/platforms/wasm/CMakeLists.txt
index 113dad18c6..b29c59c4e7 100644
--- a/src/plugins/platforms/wasm/CMakeLists.txt
+++ b/src/plugins/platforms/wasm/CMakeLists.txt
@@ -15,12 +15,14 @@ qt_internal_add_plugin(QWasmIntegrationPlugin
qwasmclipboard.cpp qwasmclipboard.h
qwasmcompositor.cpp qwasmcompositor.h
qwasmcursor.cpp qwasmcursor.h
+ qwasmevent.cpp qwasmevent.h
qwasmeventdispatcher.cpp qwasmeventdispatcher.h
qwasmeventtranslator.cpp qwasmeventtranslator.h
qwasmfontdatabase.cpp qwasmfontdatabase.h
qwasmintegration.cpp qwasmintegration.h
qwasmoffscreensurface.cpp qwasmoffscreensurface.h
qwasmopenglcontext.cpp qwasmopenglcontext.h
+ qwasmplatform.cpp qwasmplatform.h
qwasmscreen.cpp qwasmscreen.h
qwasmservices.cpp qwasmservices.h
qwasmstring.cpp qwasmstring.h
diff --git a/src/plugins/platforms/wasm/qwasmcompositor.cpp b/src/plugins/platforms/wasm/qwasmcompositor.cpp
index 45e9eeeedd..85c2783439 100644
--- a/src/plugins/platforms/wasm/qwasmcompositor.cpp
+++ b/src/plugins/platforms/wasm/qwasmcompositor.cpp
@@ -7,6 +7,7 @@
#include "qwasmeventtranslator.h"
#include "qwasmeventdispatcher.h"
#include "qwasmclipboard.h"
+#include "qwasmevent.h"
#include <QtOpenGL/qopengltexture.h>
@@ -58,6 +59,7 @@ EMSCRIPTEN_BINDINGS(qtMouseModule) {
QWasmCompositor::QWasmCompositor(QWasmScreen *screen)
: QObject(screen)
+ , m_windowManipulation(screen)
, m_blitter(new QOpenGLTextureBlitter)
, m_eventTranslator(std::make_unique<QWasmEventTranslator>())
{
@@ -87,12 +89,6 @@ void QWasmCompositor::deregisterEventHandlers()
emscripten_set_keydown_callback(canvasSelector.constData(), 0, 0, NULL);
emscripten_set_keyup_callback(canvasSelector.constData(), 0, 0, NULL);
- emscripten_set_mousedown_callback(canvasSelector.constData(), 0, 0, NULL);
- emscripten_set_mouseup_callback(canvasSelector.constData(), 0, 0, NULL);
- emscripten_set_mousemove_callback(canvasSelector.constData(), 0, 0, NULL);
- emscripten_set_mouseenter_callback(canvasSelector.constData(), 0, 0, NULL);
- emscripten_set_mouseleave_callback(canvasSelector.constData(), 0, 0, NULL);
-
emscripten_set_focus_callback(canvasSelector.constData(), 0, 0, NULL);
emscripten_set_wheel_callback(canvasSelector.constData(), 0, 0, NULL);
@@ -133,9 +129,7 @@ void QWasmCompositor::initEventHandlers()
{
QByteArray canvasSelector = screen()->canvasTargetId().toUtf8();
- m_eventTranslator->g_usePlatformMacSpecifics
- = (QWasmIntegration::get()->platform == QWasmIntegration::MacOSPlatform);
- if (QWasmIntegration::get()->platform == QWasmIntegration::MacOSPlatform) {
+ if (platform() == Platform::MacOS) {
if (!emscripten::val::global("window")["safari"].isUndefined()) {
val canvas = screen()->canvas();
canvas.call<void>("addEventListener",
@@ -149,11 +143,17 @@ void QWasmCompositor::initEventHandlers()
emscripten_set_keydown_callback(canvasSelector.constData(), (void *)this, UseCapture, &keyboard_cb);
emscripten_set_keyup_callback(canvasSelector.constData(), (void *)this, UseCapture, &keyboard_cb);
- emscripten_set_mousedown_callback(canvasSelector.constData(), (void *)this, UseCapture, &mouse_cb);
- emscripten_set_mouseup_callback(canvasSelector.constData(), (void *)this, UseCapture, &mouse_cb);
- emscripten_set_mousemove_callback(canvasSelector.constData(), (void *)this, UseCapture, &mouse_cb);
- emscripten_set_mouseenter_callback(canvasSelector.constData(), (void *)this, UseCapture, &mouse_cb);
- emscripten_set_mouseleave_callback(canvasSelector.constData(), (void *)this, UseCapture, &mouse_cb);
+ val canvas = screen()->canvas();
+ const auto callback = std::function([this](emscripten::val event) {
+ if (processPointer(*PointerEvent::fromWeb(event)))
+ event.call<void>("preventDefault");
+ });
+
+ m_pointerDownCallback = std::make_unique<qstdweb::EventCallback>(canvas, "pointerdown", callback);
+ m_pointerMoveCallback = std::make_unique<qstdweb::EventCallback>(canvas, "pointermove", callback);
+ m_pointerUpCallback = std::make_unique<qstdweb::EventCallback>(canvas, "pointerup", callback);
+ m_pointerEnterCallback = std::make_unique<qstdweb::EventCallback>(canvas, "pointerenter", callback);
+ m_pointerLeaveCallback = std::make_unique<qstdweb::EventCallback>(canvas, "pointerleave", callback);
emscripten_set_focus_callback(canvasSelector.constData(), (void *)this, UseCapture, &focus_cb);
@@ -164,7 +164,6 @@ void QWasmCompositor::initEventHandlers()
emscripten_set_touchmove_callback(canvasSelector.constData(), (void *)this, UseCapture, &touchCallback);
emscripten_set_touchcancel_callback(canvasSelector.constData(), (void *)this, UseCapture, &touchCallback);
- val canvas = screen()->canvas();
canvas.call<void>("addEventListener",
std::string("drop"),
val::module_property("qtDrop"), val(true));
@@ -859,60 +858,27 @@ void QWasmCompositor::frame()
m_context->swapBuffers(someWindow->window());
}
-void QWasmCompositor::resizeWindow(QWindow *window, QWasmCompositor::ResizeMode mode,
- QRect startRect, QPoint amount)
+void QWasmCompositor::WindowManipulation::resizeWindow(const QPoint& amount)
{
- if (mode == QWasmCompositor::ResizeNone)
- return;
-
- bool top = mode == QWasmCompositor::ResizeTopLeft ||
- mode == QWasmCompositor::ResizeTop ||
- mode == QWasmCompositor::ResizeTopRight;
-
- bool bottom = mode == QWasmCompositor::ResizeBottomLeft ||
- mode == QWasmCompositor::ResizeBottom ||
- mode == QWasmCompositor::ResizeBottomRight;
-
- bool left = mode == QWasmCompositor::ResizeLeft ||
- mode == QWasmCompositor::ResizeTopLeft ||
- mode == QWasmCompositor::ResizeBottomLeft;
-
- bool right = mode == QWasmCompositor::ResizeRight ||
- mode == QWasmCompositor::ResizeTopRight ||
- mode == QWasmCompositor::ResizeBottomRight;
-
- int x1 = startRect.left();
- int y1 = startRect.top();
- int x2 = startRect.right();
- int y2 = startRect.bottom();
-
- if (left)
- x1 += amount.x();
- if (top)
- y1 += amount.y();
- if (right)
- x2 += amount.x();
- if (bottom)
- y2 += amount.y();
-
- int w = x2-x1;
- int h = y2-y1;
-
- if (w < window->minimumWidth()) {
- if (left)
- x1 -= window->minimumWidth() - w;
-
- w = window->minimumWidth();
- }
-
- if (h < window->minimumHeight()) {
- if (top)
- y1 -= window->minimumHeight() - h;
-
- h = window->minimumHeight();
- }
-
- window->setGeometry(x1, y1, w, h);
+ const auto& minShrink = std::get<ResizeState>(m_state->operationSpecific).m_minShrink;
+ const auto& maxGrow = std::get<ResizeState>(m_state->operationSpecific).m_maxGrow;
+ const auto& resizeMode = std::get<ResizeState>(m_state->operationSpecific).m_resizeMode;
+
+ const QPoint cappedGrowVector(
+ std::min(maxGrow.x(), std::max(minShrink.x(),
+ (resizeMode & Left) ? -amount.x() : (resizeMode & Right) ? amount.x() : 0)),
+ std::min(maxGrow.y(), std::max(minShrink.y(),
+ (resizeMode & Top) ? -amount.y() : (resizeMode & Bottom) ? amount.y() : 0)));
+
+ const auto& initialBounds =
+ std::get<ResizeState>(m_state->operationSpecific).m_initialWindowBounds;
+ m_state->window->setGeometry(
+ initialBounds.adjusted(
+ (resizeMode & Left) ? -cappedGrowVector.x() : 0,
+ (resizeMode & Top) ? -cappedGrowVector.y() : 0,
+ (resizeMode & Right) ? cappedGrowVector.x() : 0,
+ (resizeMode & Bottom) ? cappedGrowVector.y() : 0
+ ));
}
void QWasmCompositor::notifyTopWindowChanged(QWasmWindow *window)
@@ -945,12 +911,6 @@ int QWasmCompositor::keyboard_cb(int eventType, const EmscriptenKeyboardEvent *k
return static_cast<int>(wasmCompositor->processKeyboard(eventType, keyEvent));
}
-int QWasmCompositor::mouse_cb(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
-{
- QWasmCompositor *compositor = (QWasmCompositor*)userData;
- return static_cast<int>(compositor->processMouse(eventType, mouseEvent));
-}
-
int QWasmCompositor::focus_cb(int eventType, const EmscriptenFocusEvent *focusEvent, void *userData)
{
Q_UNUSED(eventType)
@@ -972,19 +932,18 @@ int QWasmCompositor::touchCallback(int eventType, const EmscriptenTouchEvent *to
return static_cast<int>(compositor->handleTouch(eventType, touchEvent));
}
-bool QWasmCompositor::processMouse(int eventType, const EmscriptenMouseEvent *mouseEvent)
+bool QWasmCompositor::processPointer(const PointerEvent& event)
{
- const Qt::MouseButton button = QWasmEventTranslator::translateMouseButton(mouseEvent->button);
+ if (event.pointerType != PointerType::Mouse)
+ return false;
- const QPoint targetPointInCanvasCoords(mouseEvent->targetX, mouseEvent->targetY);
- const QPoint targetPointInScreenCoords = screen()->geometry().topLeft() + targetPointInCanvasCoords;
+ const QPoint targetPointInScreenCoords = screen()->geometry().topLeft() + event.point;
QEvent::Type buttonEventType = QEvent::None;
- Qt::KeyboardModifiers modifiers = m_eventTranslator->translateMouseEventModifier(mouseEvent);
QWindow *const targetWindow = ([this, &targetPointInScreenCoords]() -> QWindow * {
auto *targetWindow =
- m_resizeMode == QWasmCompositor::ResizeNone ?
+ m_windowManipulation.operation() == WindowManipulation::Operation::None ?
screen()->compositor()->windowAt(targetPointInScreenCoords, 5) : nullptr;
return targetWindow ? targetWindow : m_lastMouseTargetWindow.get();
@@ -1006,57 +965,41 @@ bool QWasmCompositor::processMouse(int eventType, const EmscriptenMouseEvent *mo
Qt::WindowStates windowState = targetWindow->windowState();
const bool isTargetWindowResizable = !windowState.testFlag(Qt::WindowMaximized) && !windowState.testFlag(Qt::WindowFullScreen);
- switch (eventType) {
- case EMSCRIPTEN_EVENT_MOUSEDOWN:
+ switch (event.type) {
+ case EventType::PointerDown:
{
buttonEventType = QEvent::MouseButtonPress;
- m_pressedButtons.setFlag(button);
-
if (targetWindow)
targetWindow->requestActivate();
m_pressedWindow = targetWindow;
- if (isTargetWindowResizable && button == Qt::MouseButton::LeftButton && !isTargetWindowBlocked) {
- if (wasmTargetWindow->isPointOnTitle(targetPointInScreenCoords)) {
- m_windowBeingManipulated = targetWindow;
- } else if (wasmTargetWindow->isPointOnResizeRegion(targetPointInScreenCoords)) {
- m_windowBeingManipulated = targetWindow;
- m_resizeMode = wasmTargetWindow->resizeModeAtPoint(targetPointInScreenCoords);
- m_resizePoint = targetPointInScreenCoords;
- m_resizeStartRect = targetWindow->geometry();
- }
- }
+ m_windowManipulation.onPointerDown(event, targetWindow);
- wasmTargetWindow->injectMousePressed(pointInTargetWindowCoords, targetPointInScreenCoords, button, modifiers);
+ wasmTargetWindow->injectMousePressed(pointInTargetWindowCoords, targetPointInScreenCoords, event.mouseButton, event.modifiers);
break;
}
- case EMSCRIPTEN_EVENT_MOUSEUP:
+ case EventType::PointerUp:
{
buttonEventType = QEvent::MouseButtonRelease;
- m_pressedButtons.setFlag(button, false);
-
- if (m_windowBeingManipulated && m_pressedButtons.testFlag(Qt::NoButton)) {
- m_windowBeingManipulated = nullptr;
- m_resizeMode = QWasmCompositor::ResizeNone;
- }
+ m_windowManipulation.onPointerUp(event);
if (m_pressedWindow) {
// Always deliver the released event to the same window that was pressed
- AsWasmWindow(m_pressedWindow)->injectMouseReleased(pointInTargetWindowCoords, targetPointInScreenCoords, button, modifiers);
- if (button == Qt::MouseButton::LeftButton)
+ AsWasmWindow(m_pressedWindow)->injectMouseReleased(pointInTargetWindowCoords, targetPointInScreenCoords, event.mouseButton, event.modifiers);
+ if (event.mouseButton == Qt::MouseButton::LeftButton)
m_pressedWindow = nullptr;
} else {
- wasmTargetWindow->injectMouseReleased(pointInTargetWindowCoords, targetPointInScreenCoords, button, modifiers);
+ wasmTargetWindow->injectMouseReleased(pointInTargetWindowCoords, targetPointInScreenCoords, event.mouseButton, event.modifiers);
}
break;
}
- case EMSCRIPTEN_EVENT_MOUSEMOVE:
+ case EventType::PointerMove:
{
buttonEventType = QEvent::MouseMove;
- if (wasmTargetWindow && m_pressedButtons.testFlag(Qt::NoButton)) {
+ if (wasmTargetWindow && event.mouseButtons.testFlag(Qt::NoButton)) {
const bool isOnResizeRegion = wasmTargetWindow->isPointOnResizeRegion(targetPointInScreenCoords);
if (isTargetWindowResizable && isOnResizeRegion && !isTargetWindowBlocked) {
@@ -1073,34 +1016,26 @@ bool QWasmCompositor::processMouse(int eventType, const EmscriptenMouseEvent *mo
}
}
- if (m_windowBeingManipulated) {
- if (m_resizeMode == QWasmCompositor::ResizeNone) {
- m_windowBeingManipulated->setPosition(
- m_windowBeingManipulated->position() + QPoint(mouseEvent->movementX, mouseEvent->movementY));
- } else {
- const QPoint delta = targetPointInCanvasCoords - m_resizePoint;
- resizeWindow(m_windowBeingManipulated, m_resizeMode, m_resizeStartRect, delta);
- }
- }
+ m_windowManipulation.onPointerMove(event);
break;
}
- case EMSCRIPTEN_EVENT_MOUSEENTER:
- processMouseEnter(mouseEvent);
+ case EventType::PointerEnter:
+ processMouseEnter(nullptr);
break;
- case EMSCRIPTEN_EVENT_MOUSELEAVE:
+ case EventType::PointerLeave:
processMouseLeave();
break;
default:
break;
};
- if (!pointerIsWithinTargetWindowBounds && m_pressedButtons.testFlag(Qt::NoButton)) {
+ if (!pointerIsWithinTargetWindowBounds && event.mouseButtons.testFlag(Qt::NoButton)) {
leaveWindow(m_lastMouseTargetWindow);
}
bool shouldDeliverEvent = pointerIsWithinTargetWindowBounds;
QWindow *eventTarget = targetWindow;
- if (!eventTarget && buttonEventType == QEvent::MouseButtonRelease) {
+ if (!eventTarget && event.type == EventType::PointerUp) {
eventTarget = m_lastMouseTargetWindow;
m_lastMouseTargetWindow = nullptr;
shouldDeliverEvent = true;
@@ -1109,13 +1044,122 @@ bool QWasmCompositor::processMouse(int eventType, const EmscriptenMouseEvent *mo
eventTarget != nullptr && shouldDeliverEvent &&
QWindowSystemInterface::handleMouseEvent<QWindowSystemInterface::SynchronousDelivery>(
eventTarget, QWasmIntegration::getTimestamp(), pointInTargetWindowCoords, targetPointInScreenCoords,
- m_pressedButtons, button, buttonEventType, modifiers);
+ event.mouseButtons, event.mouseButton, buttonEventType, event.modifiers);
- if (!eventAccepted && buttonEventType == QEvent::MouseButtonPress)
+ if (!eventAccepted && event.type == EventType::PointerDown)
QGuiApplicationPrivate::instance()->closeAllPopups();
return eventAccepted;
}
+QWasmCompositor::WindowManipulation::WindowManipulation(QWasmScreen *screen)
+ : m_screen(screen)
+{
+ Q_ASSERT(!!screen);
+}
+
+QWasmCompositor::WindowManipulation::Operation QWasmCompositor::WindowManipulation::operation() const
+{
+ if (!m_state)
+ return Operation::None;
+
+ return std::holds_alternative<MoveState>(m_state->operationSpecific)
+ ? Operation::Move : Operation::Resize;
+}
+
+void QWasmCompositor::WindowManipulation::onPointerDown(
+ const PointerEvent& event, QWindow* windowAtPoint)
+{
+ // Only one operation at a time.
+ if (operation() != Operation::None)
+ return;
+
+ if (event.mouseButton != Qt::MouseButton::LeftButton)
+ return;
+
+ const bool isTargetWindowResizable =
+ !windowAtPoint->windowStates().testFlag(Qt::WindowMaximized) &&
+ !windowAtPoint->windowStates().testFlag(Qt::WindowFullScreen);
+ if (!isTargetWindowResizable)
+ return;
+
+ const bool isTargetWindowBlocked =
+ QGuiApplicationPrivate::instance()->isWindowBlocked(windowAtPoint);
+ if (isTargetWindowBlocked)
+ return;
+
+ const auto pointInScreenCoords = m_screen->geometry().topLeft() + event.point;
+
+ std::unique_ptr<std::variant<ResizeState, MoveState>> operationSpecific;
+ if (AsWasmWindow(windowAtPoint)->isPointOnTitle(pointInScreenCoords)) {
+ operationSpecific = std::make_unique<std::variant<ResizeState, MoveState>>(MoveState {
+ .m_lastPointInScreenCoords = pointInScreenCoords
+ });
+ } else if (AsWasmWindow(windowAtPoint)->isPointOnResizeRegion(pointInScreenCoords)) {
+ operationSpecific = std::make_unique<std::variant<ResizeState, MoveState>>(ResizeState {
+ .m_resizeMode = AsWasmWindow(windowAtPoint)->resizeModeAtPoint(pointInScreenCoords),
+ .m_originInScreenCoords = pointInScreenCoords,
+ .m_initialWindowBounds = windowAtPoint->geometry(),
+ .m_minShrink = QPoint(windowAtPoint->minimumWidth() - windowAtPoint->geometry().width(),
+ windowAtPoint->minimumHeight() - windowAtPoint->geometry().height()),
+ .m_maxGrow = QPoint(
+ windowAtPoint->maximumWidth() - windowAtPoint->geometry().width(),
+ windowAtPoint->maximumHeight() - windowAtPoint->geometry().height()),
+ });
+ } else {
+ return;
+ }
+
+ m_state.reset(new OperationState{
+ .pointerId = event.pointerId,
+ .window = windowAtPoint,
+ .operationSpecific = std::move(*operationSpecific),
+ });
+
+ m_screen->canvas().call<void>("setPointerCapture", event.pointerId);
+}
+
+void QWasmCompositor::WindowManipulation::onPointerMove(
+ const PointerEvent& event)
+{
+ if (operation() == Operation::None || event.pointerId != m_state->pointerId)
+ return;
+
+ const auto pointInScreenCoords = m_screen->geometry().topLeft() + event.point;
+
+ switch (operation()) {
+ case Operation::Move: {
+ const QPoint targetPointClippedToScreen(
+ std::max(m_screen->geometry().left(), std::min(m_screen->geometry().right(), pointInScreenCoords.x())),
+ std::max(m_screen->geometry().top(), std::min(m_screen->geometry().bottom(), pointInScreenCoords.y())));
+
+ const QPoint difference = targetPointClippedToScreen -
+ std::get<MoveState>(m_state->operationSpecific).m_lastPointInScreenCoords;
+
+ std::get<MoveState>(m_state->operationSpecific).m_lastPointInScreenCoords = targetPointClippedToScreen;
+
+ m_state->window->setPosition(m_state->window->position() + difference);
+ break;
+ }
+ case Operation::Resize: {
+ resizeWindow(pointInScreenCoords -
+ std::get<ResizeState>(m_state->operationSpecific).m_originInScreenCoords);
+ break;
+ }
+ case Operation::None:
+ Q_ASSERT(0);
+ break;
+ }
+}
+
+void QWasmCompositor::WindowManipulation::onPointerUp(const PointerEvent& event)
+{
+ if (operation() == Operation::None || event.mouseButtons != 0 || event.pointerId != m_state->pointerId)
+ return;
+
+ m_state.reset();
+ m_screen->canvas().call<void>("releasePointerCapture", event.pointerId);
+}
+
bool QWasmCompositor::processKeyboard(int eventType, const EmscriptenKeyboardEvent *keyEvent)
{
Qt::Key qtKey;
@@ -1139,7 +1183,7 @@ bool QWasmCompositor::processKeyboard(int eventType, const EmscriptenKeyboardEve
if (keyType == QEvent::None)
return 0;
- QFlags<Qt::KeyboardModifier> modifiers = m_eventTranslator->translateKeyboardEventModifier(keyEvent);
+ QFlags<Qt::KeyboardModifier> modifiers = KeyboardModifier::getForEvent(*keyEvent);
// Clipboard fallback path: cut/copy/paste are handled by clipboard event
// handlers if direct clipboard access is not available.
@@ -1180,7 +1224,7 @@ bool QWasmCompositor::processWheel(int eventType, const EmscriptenWheelEvent *wh
{
Q_UNUSED(eventType);
- EmscriptenMouseEvent mouseEvent = wheelEvent->mouse;
+ const EmscriptenMouseEvent* mouseEvent = &wheelEvent->mouse;
int scrollFactor = 0;
switch (wheelEvent->deltaMode) {
@@ -1197,8 +1241,8 @@ bool QWasmCompositor::processWheel(int eventType, const EmscriptenWheelEvent *wh
scrollFactor = -scrollFactor; // Web scroll deltas are inverted from Qt deltas.
- Qt::KeyboardModifiers modifiers = m_eventTranslator->translateMouseEventModifier(&mouseEvent);
- QPoint targetPointInCanvasCoords(mouseEvent.targetX, mouseEvent.targetY);
+ Qt::KeyboardModifiers modifiers = KeyboardModifier::getForEvent(*mouseEvent);
+ QPoint targetPointInCanvasCoords(mouseEvent->targetX, mouseEvent->targetY);
QPoint targetPointInScreenCoords = screen()->geometry().topLeft() + targetPointInCanvasCoords;
QWindow *targetWindow = screen()->compositor()->windowAt(targetPointInScreenCoords, 5);
@@ -1287,7 +1331,7 @@ int QWasmCompositor::handleTouch(int eventType, const EmscriptenTouchEvent *touc
touchPointList.append(touchPoint);
}
- QFlags<Qt::KeyboardModifier> keyModifier = m_eventTranslator->translateTouchEventModifier(touchEvent);
+ QFlags<Qt::KeyboardModifier> keyModifier = KeyboardModifier::getForEvent(*touchEvent);
bool accepted = false;
diff --git a/src/plugins/platforms/wasm/qwasmcompositor.h b/src/plugins/platforms/wasm/qwasmcompositor.h
index 8524747a9d..b7a93d110b 100644
--- a/src/plugins/platforms/wasm/qwasmcompositor.h
+++ b/src/plugins/platforms/wasm/qwasmcompositor.h
@@ -11,6 +11,7 @@
#include <QtGui/qpalette.h>
#include <QtGui/qpainter.h>
#include <QtGui/qinputdevice.h>
+#include <QtCore/private/qstdweb_p.h>
#include <QPointer>
#include <QPointingDevice>
@@ -21,6 +22,7 @@
QT_BEGIN_NAMESPACE
+struct PointerEvent;
class QWasmWindow;
class QWasmScreen;
class QOpenGLContext;
@@ -69,16 +71,23 @@ public:
};
Q_DECLARE_FLAGS(StateFlags, QWasmStateFlag)
+ enum ResizeDimension {
+ Left = 1,
+ Right = 1 << 1,
+ Top = 1 << 2,
+ Bottom = 1 << 3
+ };
+
enum ResizeMode {
ResizeNone,
- ResizeTopLeft,
- ResizeTop,
- ResizeTopRight,
- ResizeRight,
- ResizeBottomRight,
- ResizeBottom,
- ResizeBottomLeft,
- ResizeLeft
+ ResizeTopLeft = Top | Left,
+ ResizeTop = Top,
+ ResizeTopRight = Top | Right,
+ ResizeRight = Right,
+ ResizeBottomRight = Bottom | Right,
+ ResizeBottom = Bottom,
+ ResizeBottomLeft = Bottom | Left,
+ ResizeLeft = Left
};
struct QWasmTitleBarOptions {
@@ -125,11 +134,9 @@ public:
void deliverUpdateRequests();
void deliverUpdateRequest(QWasmWindow *window, UpdateRequestDeliveryType updateType);
void handleBackingStoreFlush();
- bool processMouse(int eventType, const EmscriptenMouseEvent *mouseEvent);
bool processKeyboard(int eventType, const EmscriptenKeyboardEvent *keyEvent);
bool processWheel(int eventType, const EmscriptenWheelEvent *wheelEvent);
int handleTouch(int eventType, const EmscriptenTouchEvent *touchEvent);
- void resizeWindow(QWindow *window, QWasmCompositor::ResizeMode mode, QRect startRect, QPoint amount);
bool processMouseEnter(const EmscriptenMouseEvent *mouseEvent);
bool processMouseLeave();
@@ -140,6 +147,47 @@ private slots:
void frame();
private:
+ class WindowManipulation {
+ public:
+ enum class Operation {
+ None,
+ Move,
+ Resize,
+ };
+
+ WindowManipulation(QWasmScreen* screen);
+
+ void onPointerDown(const PointerEvent& event, QWindow* windowAtPoint);
+ void onPointerMove(const PointerEvent& event);
+ void onPointerUp(const PointerEvent& event);
+
+ Operation operation() const;
+
+ private:
+ struct ResizeState {
+ ResizeMode m_resizeMode;
+ QPoint m_originInScreenCoords;
+ QRect m_initialWindowBounds;
+ const QPoint m_minShrink;
+ const QPoint m_maxGrow;
+ };
+ struct MoveState {
+ QPoint m_lastPointInScreenCoords;
+ };
+ struct OperationState
+ {
+ int pointerId;
+ QPointer<QWindow> window;
+ std::variant<ResizeState, MoveState> operationSpecific;
+ };
+
+ void resizeWindow(const QPoint& amount);
+
+ QWasmScreen *m_screen;
+
+ std::unique_ptr<OperationState> m_state;
+ };
+
void notifyTopWindowChanged(QWasmWindow *window);
void drawWindow(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, QWasmWindow *window);
void drawWindowContent(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, QWasmWindow *window);
@@ -156,12 +204,15 @@ private:
int alignment, const QPixmap &pixmap) const;
static int keyboard_cb(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData);
- static int mouse_cb(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData);
static int focus_cb(int eventType, const EmscriptenFocusEvent *focusEvent, void *userData);
static int wheel_cb(int eventType, const EmscriptenWheelEvent *wheelEvent, void *userData);
+ bool processPointer(const PointerEvent& event);
+
static int touchCallback(int eventType, const EmscriptenTouchEvent *ev, void *userData);
+ WindowManipulation m_windowManipulation;
+
QScopedPointer<QOpenGLContext> m_context;
QScopedPointer<QOpenGLTextureBlitter> m_blitter;
@@ -170,7 +221,6 @@ private:
QRegion m_globalDamage; // damage caused by expose, window close, etc.
bool m_needComposit = false;
bool m_inFlush = false;
- bool m_inResize = false;
bool m_isEnabled = true;
QSize m_targetSize;
qreal m_targetDevicePixelRatio = 1;
@@ -179,14 +229,15 @@ private:
int m_requestAnimationFrameId = -1;
bool m_inDeliverUpdateRequest = false;
- QPointer<QWindow> m_windowBeingManipulated;
QPointer<QWindow> m_pressedWindow;
QPointer<QWindow> m_lastMouseTargetWindow;
- Qt::MouseButtons m_pressedButtons = Qt::NoButton;
- ResizeMode m_resizeMode = ResizeNone;
- QPoint m_resizePoint;
- QRect m_resizeStartRect;
+ std::unique_ptr<qstdweb::EventCallback> m_pointerDownCallback;
+ std::unique_ptr<qstdweb::EventCallback> m_pointerMoveCallback;
+ std::unique_ptr<qstdweb::EventCallback> m_pointerUpCallback;
+ std::unique_ptr<qstdweb::EventCallback> m_pointerLeaveCallback;
+ std::unique_ptr<qstdweb::EventCallback> m_pointerEnterCallback;
+
std::unique_ptr<QPointingDevice> m_touchDevice;
QMap <int, QPointF> m_pressedTouchIds;
diff --git a/src/plugins/platforms/wasm/qwasmdrag.cpp b/src/plugins/platforms/wasm/qwasmdrag.cpp
index c87e4ce7c2..c2b50e4356 100644
--- a/src/plugins/platforms/wasm/qwasmdrag.cpp
+++ b/src/plugins/platforms/wasm/qwasmdrag.cpp
@@ -64,8 +64,7 @@ static void dropEvent(val event)
if (wasmDrag->m_mimeData)
delete wasmDrag->m_mimeData;
wasmDrag->m_mimeData = new QMimeData;
- int button = event["button"].as<int>();
- wasmDrag->m_qButton = QWasmEventTranslator::translateMouseButton(button);
+ wasmDrag->m_qButton = MouseEvent::buttonFromWeb(event["button"].as<int>());
wasmDrag->m_keyModifiers = Qt::NoModifier;
if (event["altKey"].as<bool>())
diff --git a/src/plugins/platforms/wasm/qwasmevent.cpp b/src/plugins/platforms/wasm/qwasmevent.cpp
new file mode 100644
index 0000000000..b094dbfe14
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmevent.cpp
@@ -0,0 +1,53 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "qwasmevent.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace KeyboardModifier
+{
+template <>
+QFlags<Qt::KeyboardModifier> getForEvent<EmscriptenKeyboardEvent>(
+ const EmscriptenKeyboardEvent& event)
+{
+ return internal::Helper<EmscriptenKeyboardEvent>::getModifierForEvent(event) |
+ (event.location == DOM_KEY_LOCATION_NUMPAD ? Qt::KeypadModifier : Qt::NoModifier);
+}
+} // namespace KeyboardModifier
+
+std::optional<PointerEvent> PointerEvent::fromWeb(emscripten::val event)
+{
+ PointerEvent ret;
+
+ const auto eventType = ([&event]() -> std::optional<EventType> {
+ const auto eventTypeString = event["type"].as<std::string>();
+
+ if (eventTypeString == "pointermove")
+ return EventType::PointerMove;
+ else if (eventTypeString == "pointerup")
+ return EventType::PointerUp;
+ else if (eventTypeString == "pointerdown")
+ return EventType::PointerDown;
+ else if (eventTypeString == "pointerenter")
+ return EventType::PointerEnter;
+ else if (eventTypeString == "pointerleave")
+ return EventType::PointerLeave;
+ return std::nullopt;
+ })();
+ if (!eventType)
+ return std::nullopt;
+
+ ret.type = *eventType;
+ ret.pointerType = event["pointerType"].as<std::string>() == "mouse" ?
+ PointerType::Mouse : PointerType::Other;
+ ret.mouseButton = MouseEvent::buttonFromWeb(event["button"].as<int>());
+ ret.mouseButtons = MouseEvent::buttonsFromWeb(event["buttons"].as<unsigned short>());
+ ret.point = QPoint(event["x"].as<int>(), event["y"].as<int>());
+ ret.pointerId = event["pointerId"].as<int>();
+ ret.modifiers = KeyboardModifier::getForEvent(event);
+
+ return ret;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmevent.h b/src/plugins/platforms/wasm/qwasmevent.h
new file mode 100644
index 0000000000..784591fb95
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmevent.h
@@ -0,0 +1,145 @@
+// 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 <QtCore/qglobal.h>
+#include <QtCore/qnamespace.h>
+
+#include <QPoint>
+
+#include <emscripten/html5.h>
+#include <emscripten/val.h>
+
+QT_BEGIN_NAMESPACE
+
+enum class EventType {
+ PointerDown,
+ PointerMove,
+ PointerUp,
+ PointerEnter,
+ PointerLeave,
+};
+
+enum class PointerType {
+ Mouse,
+ Other,
+};
+
+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<typename T>
+ struct IsEmscriptenEvent
+ {
+ template<typename U, EM_BOOL U::*, EM_BOOL U::*, EM_BOOL U::*, EM_BOOL U::*>
+ struct SFINAE {};
+ template<typename U> static char Test(
+ SFINAE<U, &U::shiftKey, &U::ctrlKey, &U::altKey, &U::metaKey>*);
+ template<typename U> static int Test(...);
+ static const bool value = sizeof(Test<T>(0)) == sizeof(char);
+ };
+
+ template<class T, typename Enable = void>
+ struct Helper;
+
+ template<class T>
+ struct Helper<T, std::enable_if_t<IsEmscriptenEvent<T>::value>>
+ {
+ static QFlags<Qt::KeyboardModifier> getModifierForEvent(const T& event) {
+ QFlags<Qt::KeyboardModifier> 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<emscripten::val>
+ {
+ static QFlags<Qt::KeyboardModifier> getModifierForEvent(const emscripten::val& event) {
+ QFlags<Qt::KeyboardModifier> keyModifier = Qt::NoModifier;
+ if (event["shiftKey"].as<bool>())
+ keyModifier |= Qt::ShiftModifier;
+ if (event["ctrlKey"].as<bool>())
+ keyModifier |= platform() == Platform::MacOS ? Qt::MetaModifier : Qt::ControlModifier;
+ if (event["altKey"].as<bool>())
+ keyModifier |= Qt::AltModifier;
+ if (event["metaKey"].as<bool>())
+ keyModifier |= platform() == Platform::MacOS ? Qt::ControlModifier : Qt::MetaModifier;
+ if (event["constructor"]["name"].as<std::string>() == "KeyboardEvent" &&
+ event["location"].as<unsigned int>() == DOM_KEY_LOCATION_NUMPAD) {
+ keyModifier |= Qt::KeypadModifier;
+ }
+
+ return keyModifier;
+ }
+ };
+} // namespace internal
+
+template <typename Event>
+QFlags<Qt::KeyboardModifier> getForEvent(const Event& event)
+{
+ return internal::Helper<Event>::getModifierForEvent(event);
+}
+
+template <>
+QFlags<Qt::KeyboardModifier> getForEvent<EmscriptenKeyboardEvent>(
+ const EmscriptenKeyboardEvent& event);
+
+} // namespace KeyboardModifier
+
+struct Q_CORE_EXPORT Event
+{
+ EventType type;
+};
+
+struct Q_CORE_EXPORT MouseEvent : public Event
+{
+ QPoint point;
+ Qt::MouseButton mouseButton;
+ Qt::MouseButtons mouseButtons;
+ QFlags<Qt::KeyboardModifier> modifiers;
+
+ 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);
+}
+};
+
+struct Q_CORE_EXPORT PointerEvent : public MouseEvent
+{
+ static std::optional<PointerEvent> fromWeb(emscripten::val webEvent);
+
+ PointerType pointerType;
+ int pointerId;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWASMEVENT_H
diff --git a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp
index 6f13009aef..edd323294c 100644
--- a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp
+++ b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp
@@ -160,54 +160,6 @@ QWasmEventTranslator::~QWasmEventTranslator()
{
}
-template <typename Event>
-QFlags<Qt::KeyboardModifier> QWasmEventTranslator::translatKeyModifier(const Event *event)
-{
- // macOS CTRL <-> META switching. We most likely want to enable
- // the existing switching code in QtGui, but for now do it here.
-
- QFlags<Qt::KeyboardModifier> keyModifier = Qt::NoModifier;
- if (event->shiftKey)
- keyModifier |= Qt::ShiftModifier;
- if (event->ctrlKey) {
- if (g_usePlatformMacSpecifics)
- keyModifier |= Qt::MetaModifier;
- else
- keyModifier |= Qt::ControlModifier;
- }
- if (event->altKey)
- keyModifier |= Qt::AltModifier;
- if (event->metaKey) {
- if (g_usePlatformMacSpecifics)
- keyModifier |= Qt::ControlModifier;
- else
- keyModifier |= Qt::MetaModifier;
- }
-
- return keyModifier;
-}
-
-QFlags<Qt::KeyboardModifier> QWasmEventTranslator::translateKeyboardEventModifier(const EmscriptenKeyboardEvent *event)
-{
- QFlags<Qt::KeyboardModifier> keyModifier = translatKeyModifier(event);
-
- if (event->location == DOM_KEY_LOCATION_NUMPAD) {
- keyModifier |= Qt::KeypadModifier;
- }
-
- return keyModifier;
-}
-
-QFlags<Qt::KeyboardModifier> QWasmEventTranslator::translateMouseEventModifier(const EmscriptenMouseEvent *mouseEvent)
-{
- return translatKeyModifier(mouseEvent);
-}
-
-QFlags<Qt::KeyboardModifier> QWasmEventTranslator::translateTouchEventModifier(const EmscriptenTouchEvent *touchEvent)
-{
- return translatKeyModifier(touchEvent);
-}
-
Qt::Key QWasmEventTranslator::translateEmscriptKey(const EmscriptenKeyboardEvent *emscriptKey)
{
Qt::Key qtKey = Qt::Key_unknown;
diff --git a/src/plugins/platforms/wasm/qwasmeventtranslator.h b/src/plugins/platforms/wasm/qwasmeventtranslator.h
index d86ddf7625..76da1ebbe5 100644
--- a/src/plugins/platforms/wasm/qwasmeventtranslator.h
+++ b/src/plugins/platforms/wasm/qwasmeventtranslator.h
@@ -12,6 +12,8 @@
#include <QtGui/qinputdevice.h>
#include <QHash>
#include <QCursor>
+#include "qwasmevent.h"
+#include "qwasmplatform.h"
QT_BEGIN_NAMESPACE
@@ -26,25 +28,7 @@ public:
explicit QWasmEventTranslator();
~QWasmEventTranslator();
- template <typename Event>
- QFlags<Qt::KeyboardModifier> translatKeyModifier(const Event *event);
-
static Qt::Key translateEmscriptKey(const EmscriptenKeyboardEvent *emscriptKey);
- QFlags<Qt::KeyboardModifier> translateKeyboardEventModifier(const EmscriptenKeyboardEvent *keyEvent);
- QFlags<Qt::KeyboardModifier> translateMouseEventModifier(const EmscriptenMouseEvent *mouseEvent);
- QFlags<Qt::KeyboardModifier> translateTouchEventModifier(const EmscriptenTouchEvent *touchEvent);
- static constexpr Qt::MouseButton translateMouseButton(unsigned short button) {
- switch (button) {
- case 0:
- return Qt::LeftButton;
- case 1:
- return Qt::MiddleButton;
- case 2:
- return Qt::RightButton;
- default:
- return Qt::NoButton;
- }
- }
static QCursor cursorForMode(QWasmCompositor::ResizeMode mode);
QString getKeyText(const EmscriptenKeyboardEvent *keyEvent, Qt::Key key);
diff --git a/src/plugins/platforms/wasm/qwasminputcontext.cpp b/src/plugins/platforms/wasm/qwasminputcontext.cpp
index f27ea013c6..9da0a9dc34 100644
--- a/src/plugins/platforms/wasm/qwasminputcontext.cpp
+++ b/src/plugins/platforms/wasm/qwasminputcontext.cpp
@@ -50,7 +50,7 @@ QWasmInputContext::QWasmInputContext()
m_inputElement.set("style", "position:absolute;left:-1000px;top:-1000px"); // offscreen
m_inputElement.set("contentaediable","true");
- if (QWasmIntegration::get()->platform == QWasmIntegration::AndroidPlatform) {
+ if (platform() == Platform::Android) {
emscripten::val body = document["body"];
body.call<void>("appendChild", m_inputElement);
@@ -65,8 +65,7 @@ QWasmInputContext::QWasmInputContext()
&androidKeyboardCallback);
}
- if (QWasmIntegration::get()->platform == QWasmIntegration::MacOSPlatform ||
- QWasmIntegration::get()->platform == QWasmIntegration::iPhonePlatform)
+ if (platform() == Platform::MacOS || platform() == Platform::iPhone)
{
auto callback = [=](emscripten::val) {
m_inputElement["parentElement"].call<void>("removeChild", m_inputElement);
@@ -81,7 +80,7 @@ QWasmInputContext::QWasmInputContext()
QWasmInputContext::~QWasmInputContext()
{
- if (QWasmIntegration::get()->platform == QWasmIntegration::AndroidPlatform)
+ if (platform() == Platform::Android)
emscripten_set_keydown_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, 0, NULL);
}
@@ -107,7 +106,7 @@ void QWasmInputContext::update(Qt::InputMethodQueries queries)
void QWasmInputContext::showInputPanel()
{
- if (QWasmIntegration::get()->platform == QWasmIntegration::WindowsPlatform
+ if (platform() == Platform::Windows
&& inputPanelIsOpen) // call this only once for win32
return;
// this is called each time the keyboard is touched
@@ -119,9 +118,9 @@ void QWasmInputContext::showInputPanel()
// captured by the keyboard event handler installed on the
// canvas.
- if (QWasmIntegration::get()->platform == QWasmIntegration::MacOSPlatform // keep for compatibility
- || QWasmIntegration::get()->platform == QWasmIntegration::iPhonePlatform
- || QWasmIntegration::get()->platform == QWasmIntegration::WindowsPlatform) {
+ if (platform() == Platform::MacOS // keep for compatibility
+ || platform() == Platform::iPhone
+ || platform() == Platform::Windows) {
emscripten::val canvas = focusCanvas();
if (canvas == emscripten::val::undefined())
return;
diff --git a/src/plugins/platforms/wasm/qwasmintegration.cpp b/src/plugins/platforms/wasm/qwasmintegration.cpp
index f19ede9246..a29e18e98a 100644
--- a/src/plugins/platforms/wasm/qwasmintegration.cpp
+++ b/src/plugins/platforms/wasm/qwasmintegration.cpp
@@ -86,22 +86,6 @@ QWasmIntegration::QWasmIntegration()
s_instance = this;
touchPoints = emscripten::val::global("navigator")["maxTouchPoints"].as<int>();
- // The Platform Detect: expand coverage as needed
- platform = GenericPlatform;
- emscripten::val rawPlatform = emscripten::val::global("navigator")["platform"];
-
- if (rawPlatform.call<bool>("includes", emscripten::val("Mac")))
- platform = MacOSPlatform;
- if (rawPlatform.call<bool>("includes", emscripten::val("iPhone")))
- platform = iPhonePlatform;
- if (rawPlatform.call<bool>("includes", emscripten::val("Win32")))
- platform = WindowsPlatform;
- if (rawPlatform.call<bool>("includes", emscripten::val("Linux"))) {
- platform = LinuxPlatform;
- emscripten::val uAgent = emscripten::val::global("navigator")["userAgent"];
- if (uAgent.call<bool>("includes", emscripten::val("Android")))
- platform = AndroidPlatform;
- }
// Create screens for container elements. Each container element can be a div element (preferred),
// or a canvas element (legacy). Qt versions prior to 6.x read the "qtCanvasElements" module property,
diff --git a/src/plugins/platforms/wasm/qwasmintegration.h b/src/plugins/platforms/wasm/qwasmintegration.h
index db1f928f76..76296ff1a7 100644
--- a/src/plugins/platforms/wasm/qwasmintegration.h
+++ b/src/plugins/platforms/wasm/qwasmintegration.h
@@ -40,15 +40,6 @@ class QWasmIntegration : public QObject, public QPlatformIntegration
{
Q_OBJECT
public:
- enum Platform {
- GenericPlatform,
- MacOSPlatform,
- WindowsPlatform,
- LinuxPlatform,
- AndroidPlatform,
- iPhonePlatform
- };
-
QWasmIntegration();
~QWasmIntegration();
@@ -89,7 +80,6 @@ public:
void removeBackingStore(QWindow* window);
static quint64 getTimestamp();
- Platform platform;
int touchPoints;
private:
diff --git a/src/plugins/platforms/wasm/qwasmplatform.cpp b/src/plugins/platforms/wasm/qwasmplatform.cpp
new file mode 100644
index 0000000000..c641e345e4
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmplatform.cpp
@@ -0,0 +1,31 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "qwasmplatform.h"
+
+QT_BEGIN_NAMESPACE
+
+Platform platform()
+{
+ static const Platform qtDetectedPlatform = ([]() {
+ // The Platform Detect: expand coverage as needed
+ emscripten::val rawPlatform = emscripten::val::global("navigator")["platform"];
+
+ if (rawPlatform.call<bool>("includes", emscripten::val("Mac")))
+ return Platform::MacOS;
+ if (rawPlatform.call<bool>("includes", emscripten::val("iPhone")))
+ return Platform::iPhone;
+ if (rawPlatform.call<bool>("includes", emscripten::val("Win32")))
+ return Platform::Windows;
+ if (rawPlatform.call<bool>("includes", emscripten::val("Linux"))) {
+ emscripten::val uAgent = emscripten::val::global("navigator")["userAgent"];
+ if (uAgent.call<bool>("includes", emscripten::val("Android")))
+ return Platform::Android;
+ return Platform::Linux;
+ }
+ return Platform::Generic;
+ })();
+ return qtDetectedPlatform;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmplatform.h b/src/plugins/platforms/wasm/qwasmplatform.h
new file mode 100644
index 0000000000..239efdeae9
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmplatform.h
@@ -0,0 +1,29 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QWASMPLATFORM_H
+#define QWASMPLATFORM_H
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qnamespace.h>
+
+#include <QPoint>
+
+#include <emscripten/val.h>
+
+QT_BEGIN_NAMESPACE
+
+enum class Platform {
+ Generic,
+ MacOS,
+ Windows,
+ Linux,
+ Android,
+ iPhone,
+};
+
+Platform platform();
+
+QT_END_NAMESPACE
+
+#endif // QWASMPLATFORM_H