diff options
Diffstat (limited to 'src/plugins/platforms/wasm')
-rw-r--r-- | src/plugins/platforms/wasm/qwasmcompositor.cpp | 504 | ||||
-rw-r--r-- | src/plugins/platforms/wasm/qwasmcompositor.h | 52 | ||||
-rw-r--r-- | src/plugins/platforms/wasm/qwasmeventtranslator.cpp | 602 | ||||
-rw-r--r-- | src/plugins/platforms/wasm/qwasmeventtranslator.h | 54 | ||||
-rw-r--r-- | src/plugins/platforms/wasm/qwasmintegration.cpp | 5 | ||||
-rw-r--r-- | src/plugins/platforms/wasm/qwasmintegration.h | 1 | ||||
-rw-r--r-- | src/plugins/platforms/wasm/qwasmscreen.cpp | 2 | ||||
-rw-r--r-- | src/plugins/platforms/wasm/qwasmwindow.cpp | 20 | ||||
-rw-r--r-- | src/plugins/platforms/wasm/qwasmwindow.h | 16 |
9 files changed, 658 insertions, 598 deletions
diff --git a/src/plugins/platforms/wasm/qwasmcompositor.cpp b/src/plugins/platforms/wasm/qwasmcompositor.cpp index aa498c8238..048dcfa2fc 100644 --- a/src/plugins/platforms/wasm/qwasmcompositor.cpp +++ b/src/plugins/platforms/wasm/qwasmcompositor.cpp @@ -28,9 +28,11 @@ ****************************************************************************/ #include "qwasmcompositor.h" -#include "qwasmeventdispatcher.h" -#include "qwasmwindow.h" #include "qwasmstylepixmaps_p.h" +#include "qwasmwindow.h" +#include "qwasmeventtranslator.h" +#include "qwasmeventdispatcher.h" +#include "qwasmclipboard.h" #include <QtOpenGL/qopengltexture.h> @@ -47,6 +49,10 @@ #include <QtCore/qcoreapplication.h> #include <QtGui/qguiapplication.h> +#include <emscripten/bind.h> + +using namespace emscripten; + Q_GUI_EXPORT int qt_defaultDpiX(); QWasmCompositedWindow::QWasmCompositedWindow() @@ -57,6 +63,25 @@ QWasmCompositedWindow::QWasmCompositedWindow() { } +// macOS CTRL <-> META switching. We most likely want to enable +// the existing switching code in QtGui, but for now do it here. + + +bool g_useNaturalScrolling = true; // natural scrolling is default on linux/windows + +static void mouseWheelEvent(emscripten::val event) { + + emscripten::val wheelInterted = event["webkitDirectionInvertedFromDevice"]; + + if (wheelInterted.as<bool>()) { + g_useNaturalScrolling = true; + } +} + +EMSCRIPTEN_BINDINGS(qtMouseModule) { + function("qtMouseWheelEvent", &mouseWheelEvent); +} + QWasmCompositor::QWasmCompositor(QWasmScreen *screen) :QObject(screen) , m_blitter(new QOpenGLTextureBlitter) @@ -65,16 +90,51 @@ QWasmCompositor::QWasmCompositor(QWasmScreen *screen) , m_inResize(false) , m_isEnabled(true) , m_targetDevicePixelRatio(1) + , draggedWindow(nullptr) + , lastWindow(nullptr) + , pressedButtons(Qt::NoButton) + , resizeMode(QWasmCompositor::ResizeNone) + , eventTranslator(new QWasmEventTranslator()) { + touchDevice = new QPointingDevice( + "touchscreen", 1, QInputDevice::DeviceType::TouchScreen, + QPointingDevice::PointerType::Finger, + QPointingDevice::Capability::Position | QPointingDevice::Capability::Area | QPointingDevice::Capability::NormalizedPosition, + 10, 0); + QWindowSystemInterface::registerInputDevice(touchDevice); + + initEventHandlers(); } QWasmCompositor::~QWasmCompositor() { if (m_requestAnimationFrameId != -1) emscripten_cancel_animation_frame(m_requestAnimationFrameId); + + deregisterEventHandlers(); destroy(); } +void QWasmCompositor::deregisterEventHandlers() +{ + QByteArray canvasSelector = "#" + screen()->canvasId().toUtf8(); + 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_focus_callback(canvasSelector.constData(), 0, 0, NULL); + + emscripten_set_wheel_callback(canvasSelector.constData(), 0, 0, NULL); + + emscripten_set_touchstart_callback(canvasSelector.constData(), 0, 0, NULL); + emscripten_set_touchend_callback(canvasSelector.constData(), 0, 0, NULL); + emscripten_set_touchmove_callback(canvasSelector.constData(), 0, 0, NULL); + emscripten_set_touchcancel_callback(canvasSelector.constData(), 0, 0, NULL); +} + void QWasmCompositor::destroy() { // Destroy OpenGL resources. This is done here in a separate function @@ -96,6 +156,48 @@ void QWasmCompositor::destroy() m_isEnabled = false; // prevent frame() from creating a new m_context } +void QWasmCompositor::initEventHandlers() +{ + QByteArray canvasSelector = "#" + screen()->canvasId().toUtf8(); + + // The Platform Detect: expand coverage and move as needed + enum Platform { + GenericPlatform, + MacOSPlatform + }; + Platform platform = Platform(emscripten::val::global("navigator")["platform"] + .call<bool>("includes", emscripten::val("Mac"))); + + eventTranslator->setIsMac(platform == MacOSPlatform); + + if (platform == MacOSPlatform) { + g_useNaturalScrolling = false; // make this !default on macOS + + if (!emscripten::val::global("window")["safari"].isUndefined()) { + val canvas = screen()->canvas(); + canvas.call<void>("addEventListener", + val("wheel"), + val::module_property("qtMouseWheelEvent")); + } + } + + emscripten_set_keydown_callback(canvasSelector.constData(), (void *)this, 1, &keyboard_cb); + emscripten_set_keyup_callback(canvasSelector.constData(), (void *)this, 1, &keyboard_cb); + + emscripten_set_mousedown_callback(canvasSelector.constData(), (void *)this, 1, &mouse_cb); + emscripten_set_mouseup_callback(canvasSelector.constData(), (void *)this, 1, &mouse_cb); + emscripten_set_mousemove_callback(canvasSelector.constData(), (void *)this, 1, &mouse_cb); + + emscripten_set_focus_callback(canvasSelector.constData(), (void *)this, 1, &focus_cb); + + emscripten_set_wheel_callback(canvasSelector.constData(), (void *)this, 1, &wheel_cb); + + emscripten_set_touchstart_callback(canvasSelector.constData(), (void *)this, 1, &touchCallback); + emscripten_set_touchend_callback(canvasSelector.constData(), (void *)this, 1, &touchCallback); + emscripten_set_touchmove_callback(canvasSelector.constData(), (void *)this, 1, &touchCallback); + emscripten_set_touchcancel_callback(canvasSelector.constData(), (void *)this, 1, &touchCallback); +} + void QWasmCompositor::setEnabled(bool enabled) { m_isEnabled = enabled; @@ -784,6 +886,62 @@ void QWasmCompositor::frame() m_context->swapBuffers(someWindow->window()); } +void QWasmCompositor::resizeWindow(QWindow *window, QWasmCompositor::ResizeMode mode, + QRect startRect, 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); +} + void QWasmCompositor::notifyTopWindowChanged(QWasmWindow *window) { QWindow *modalWindow; @@ -807,3 +965,345 @@ QOpenGLContext *QWasmCompositor::context() { return m_context.data(); } + +int QWasmCompositor::keyboard_cb(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData) +{ + QWasmCompositor *wasmCompositor = reinterpret_cast<QWasmCompositor *>(userData); + bool accepted = wasmCompositor->processKeyboard(eventType, keyEvent); + + return accepted ? 1 : 0; +} + +int QWasmCompositor::mouse_cb(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData) +{ + QWasmCompositor *compositor = (QWasmCompositor*)userData; + bool accepted = compositor->processMouse(eventType, mouseEvent); + return accepted; +} + +int QWasmCompositor::focus_cb(int /*eventType*/, const EmscriptenFocusEvent */*focusEvent*/, void */*userData*/) +{ + return 0; +} + +int QWasmCompositor::wheel_cb(int eventType, const EmscriptenWheelEvent *wheelEvent, void *userData) +{ + QWasmCompositor *compositor = (QWasmCompositor *) userData; + bool accepted = compositor->processWheel(eventType, wheelEvent); + return accepted ? 1 : 0; +} + +int QWasmCompositor::touchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData) +{ + auto compositor = reinterpret_cast<QWasmCompositor*>(userData); + return compositor->handleTouch(eventType, touchEvent); +} + +bool QWasmCompositor::processMouse(int eventType, const EmscriptenMouseEvent *mouseEvent) +{ + QPoint targetPoint(mouseEvent->targetX, mouseEvent->targetY); + QPoint globalPoint = screen()->geometry().topLeft() + targetPoint; + + QEvent::Type buttonEventType = QEvent::None; + Qt::MouseButton button = Qt::NoButton; + Qt::KeyboardModifiers modifiers = eventTranslator->translateMouseEventModifier(mouseEvent); + + QWindow *window2 = nullptr; + if (resizeMode == QWasmCompositor::ResizeNone) + window2 = screen()->compositor()->windowAt(globalPoint, 5); + + if (window2 == nullptr) { + window2 = lastWindow; + } else { + lastWindow = window2; + } + + QPoint localPoint = window2->mapFromGlobal(globalPoint); + bool interior = window2->geometry().contains(globalPoint); + + QWasmWindow *htmlWindow = static_cast<QWasmWindow*>(window2->handle()); + switch (eventType) { + case EMSCRIPTEN_EVENT_MOUSEDOWN: + { + button = QWasmEventTranslator::translateMouseButton(mouseEvent->button); + + if (window2) + window2->requestActivate(); + + pressedButtons.setFlag(button); + + pressedWindow = window2; + buttonEventType = QEvent::MouseButtonPress; + + // button overview: + // 0 = primary mouse button, usually left click + // 1 = middle mouse button, usually mouse wheel + // 2 = right mouse button, usually right click + // from: https://w3c.github.io/uievents/#dom-mouseevent-button + if (mouseEvent->button == 0) { + if (!(htmlWindow->m_windowState & Qt::WindowFullScreen) && !(htmlWindow->m_windowState & Qt::WindowMaximized)) { + if (htmlWindow && window2->flags().testFlag(Qt::WindowTitleHint) && htmlWindow->isPointOnTitle(globalPoint)) + draggedWindow = window2; + else if (htmlWindow && htmlWindow->isPointOnResizeRegion(globalPoint)) { + draggedWindow = window2; + resizeMode = htmlWindow->resizeModeAtPoint(globalPoint); + resizePoint = globalPoint; + resizeStartRect = window2->geometry(); + } + } + } + + htmlWindow->injectMousePressed(localPoint, globalPoint, button, modifiers); + break; + } + case EMSCRIPTEN_EVENT_MOUSEUP: + { + button = QWasmEventTranslator::translateMouseButton(mouseEvent->button); + pressedButtons.setFlag(button, false); + buttonEventType = QEvent::MouseButtonRelease; + QWasmWindow *oldWindow = nullptr; + + if (mouseEvent->button == 0 && pressedWindow) { + oldWindow = static_cast<QWasmWindow*>(pressedWindow->handle()); + pressedWindow = nullptr; + } + + if (draggedWindow && pressedButtons.testFlag(Qt::NoButton)) { + draggedWindow = nullptr; + resizeMode = QWasmCompositor::ResizeNone; + } + + if (oldWindow) + oldWindow->injectMouseReleased(localPoint, globalPoint, button, modifiers); + else + htmlWindow->injectMouseReleased(localPoint, globalPoint, button, modifiers); + break; + } + case EMSCRIPTEN_EVENT_MOUSEMOVE: // drag event + { + buttonEventType = QEvent::MouseMove; + + if (htmlWindow && pressedButtons.testFlag(Qt::NoButton)) { + + if (htmlWindow->isPointOnResizeRegion(globalPoint)) { + QCursor resizingCursor = eventTranslator->cursorForMode(htmlWindow->resizeModeAtPoint(globalPoint)); + + if (resizingCursor != window2->cursor()) { + isCursorOverridden = true; + QWasmCursor::setOverrideWasmCursor(&resizingCursor, window2->screen()); + } + } else { // off resizing area + if (isCursorOverridden) { + isCursorOverridden = false; + QWasmCursor::clearOverrideWasmCursor(window2->screen()); + } + } + } + + if (!(htmlWindow->m_windowState & Qt::WindowFullScreen) && !(htmlWindow->m_windowState & Qt::WindowMaximized)) { + if (resizeMode == QWasmCompositor::ResizeNone && draggedWindow) { + draggedWindow->setX(draggedWindow->x() + mouseEvent->movementX); + draggedWindow->setY(draggedWindow->y() + mouseEvent->movementY); + } + + if (resizeMode != QWasmCompositor::ResizeNone && !(htmlWindow->m_windowState & Qt::WindowFullScreen)) { + QPoint delta = QPoint(mouseEvent->targetX, mouseEvent->targetY) - resizePoint; + resizeWindow(draggedWindow, resizeMode, resizeStartRect, delta); + } + } + break; + } + default: // MOUSELEAVE MOUSEENTER + break; + }; + if (!window2 && buttonEventType == QEvent::MouseButtonRelease) { + window2 = lastWindow; + lastWindow = nullptr; + interior = true; + } + bool accepted = true; + if (window2 && interior) { + accepted = QWindowSystemInterface::handleMouseEvent<QWindowSystemInterface::SynchronousDelivery>( + window2, QWasmIntegration::getTimestamp(), localPoint, globalPoint, pressedButtons, button, buttonEventType, modifiers); + } + return accepted; +} + +bool QWasmCompositor::processKeyboard(int eventType, const EmscriptenKeyboardEvent *keyEvent) +{ + Qt::Key qtKey; + QString keyText; + QEvent::Type keyType = QEvent::None; + switch (eventType) { + case EMSCRIPTEN_EVENT_KEYPRESS: + case EMSCRIPTEN_EVENT_KEYDOWN: // down + keyType = QEvent::KeyPress; + keyText = this->eventTranslator->getKeyText(keyEvent); + qtKey = this->eventTranslator->getKey(keyEvent); + break; + case EMSCRIPTEN_EVENT_KEYUP: // up + keyType = QEvent::KeyRelease; + this->eventTranslator->setStickyDeadKey(keyEvent); + break; + default: + break; + }; + + if (keyType == QEvent::None) + return 0; + + QFlags<Qt::KeyboardModifier> modifiers = eventTranslator->translateKeyboardEventModifier(keyEvent); + + // Clipboard fallback path: cut/copy/paste are handled by clipboard event + // handlers if direct clipboard access is not available. + if (!QWasmIntegration::get()->getWasmClipboard()->hasClipboardApi && modifiers & Qt::ControlModifier && + (qtKey == Qt::Key_X || qtKey == Qt::Key_C || qtKey == Qt::Key_V)) { + if (qtKey == Qt::Key_V) { + QWasmIntegration::get()->getWasmClipboard()->isPaste = true; + } + return false; + } + + bool accepted = false; + + if (keyType == QEvent::KeyPress && + modifiers.testFlag(Qt::ControlModifier) + && qtKey == Qt::Key_V) { + QWasmIntegration::get()->getWasmClipboard()->isPaste = true; + accepted = false; // continue on to event + } else { + if (keyText.isEmpty()) + keyText = QString(keyEvent->key); + if (keyText.size() > 1) + keyText.clear(); + accepted = QWindowSystemInterface::handleKeyEvent<QWindowSystemInterface::SynchronousDelivery>( + 0, keyType, qtKey, modifiers, keyText); + } + if (keyType == QEvent::KeyPress && + modifiers.testFlag(Qt::ControlModifier) + && qtKey == Qt::Key_C) { + QWasmIntegration::get()->getWasmClipboard()->isPaste = false; + accepted = false; // continue on to event + } + + return accepted; +} + +bool QWasmCompositor::processWheel(int eventType, const EmscriptenWheelEvent *wheelEvent) +{ + Q_UNUSED(eventType); + + EmscriptenMouseEvent mouseEvent = wheelEvent->mouse; + + int scrollFactor = 0; + switch (wheelEvent->deltaMode) { + case DOM_DELTA_PIXEL://chrome safari + scrollFactor = 1; + break; + case DOM_DELTA_LINE: //firefox + scrollFactor = 12; + break; + case DOM_DELTA_PAGE: + scrollFactor = 20; + break; + }; + + if (g_useNaturalScrolling) //macOS platform has document oriented scrolling + scrollFactor = -scrollFactor; + + Qt::KeyboardModifiers modifiers = eventTranslator->translateMouseEventModifier(&mouseEvent); + QPoint targetPoint(mouseEvent.targetX, mouseEvent.targetY); + QPoint globalPoint = screen()->geometry().topLeft() + targetPoint; + + QWindow *window2 = screen()->compositor()->windowAt(globalPoint, 5); + if (!window2) + return 0; + QPoint localPoint = window2->mapFromGlobal(globalPoint); + + QPoint pixelDelta; + + if (wheelEvent->deltaY != 0) pixelDelta.setY(wheelEvent->deltaY * scrollFactor); + if (wheelEvent->deltaX != 0) pixelDelta.setX(wheelEvent->deltaX * scrollFactor); + + bool accepted = QWindowSystemInterface::handleWheelEvent( + window2, QWasmIntegration::getTimestamp(), localPoint, + globalPoint, QPoint(), pixelDelta, modifiers); + return accepted; +} + +int QWasmCompositor::handleTouch(int eventType, const EmscriptenTouchEvent *touchEvent) +{ + QList<QWindowSystemInterface::TouchPoint> touchPointList; + touchPointList.reserve(touchEvent->numTouches); + QWindow *window2; + + for (int i = 0; i < touchEvent->numTouches; i++) { + + const EmscriptenTouchPoint *touches = &touchEvent->touches[i]; + + QPoint targetPoint(touches->targetX, touches->targetY); + QPoint globalPoint = screen()->geometry().topLeft() + targetPoint; + + window2 = this->screen()->compositor()->windowAt(globalPoint, 5); + if (window2 == nullptr) + continue; + + QWindowSystemInterface::TouchPoint touchPoint; + + touchPoint.area = QRect(0, 0, 8, 8); + touchPoint.id = touches->identifier; + touchPoint.pressure = 1.0; + + touchPoint.area.moveCenter(globalPoint); + + const auto tp = pressedTouchIds.constFind(touchPoint.id); + if (tp != pressedTouchIds.constEnd()) + touchPoint.normalPosition = tp.value(); + + QPointF localPoint = QPointF(window2->mapFromGlobal(globalPoint)); + QPointF normalPosition(localPoint.x() / window2->width(), + localPoint.y() / window2->height()); + + const bool stationaryTouchPoint = (normalPosition == touchPoint.normalPosition); + touchPoint.normalPosition = normalPosition; + + switch (eventType) { + case EMSCRIPTEN_EVENT_TOUCHSTART: + if (tp != pressedTouchIds.constEnd()) { + touchPoint.state = (stationaryTouchPoint + ? QEventPoint::State::Stationary + : QEventPoint::State::Updated); + } else { + touchPoint.state = QEventPoint::State::Pressed; + } + pressedTouchIds.insert(touchPoint.id, touchPoint.normalPosition); + + break; + case EMSCRIPTEN_EVENT_TOUCHEND: + touchPoint.state = QEventPoint::State::Released; + pressedTouchIds.remove(touchPoint.id); + break; + case EMSCRIPTEN_EVENT_TOUCHMOVE: + touchPoint.state = (stationaryTouchPoint + ? QEventPoint::State::Stationary + : QEventPoint::State::Updated); + + pressedTouchIds.insert(touchPoint.id, touchPoint.normalPosition); + break; + default: + break; + } + + touchPointList.append(touchPoint); + } + + QFlags<Qt::KeyboardModifier> keyModifier = eventTranslator->translateTouchEventModifier(touchEvent); + + bool accepted = QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::SynchronousDelivery>( + window2, QWasmIntegration::getTimestamp(), touchDevice, touchPointList, keyModifier); + + if (eventType == EMSCRIPTEN_EVENT_TOUCHCANCEL) + accepted = QWindowSystemInterface::handleTouchCancelEvent(window2, QWasmIntegration::getTimestamp(), touchDevice, keyModifier); + + return static_cast<int>(accepted); +} diff --git a/src/plugins/platforms/wasm/qwasmcompositor.h b/src/plugins/platforms/wasm/qwasmcompositor.h index 1a51016c03..1feda04870 100644 --- a/src/plugins/platforms/wasm/qwasmcompositor.h +++ b/src/plugins/platforms/wasm/qwasmcompositor.h @@ -36,6 +36,12 @@ #include <QtOpenGL/qopengltextureblitter.h> #include <QtGui/qpalette.h> #include <QtGui/qpainter.h> +#include <QtGui/qinputdevice.h> + +#include <QPointer> +#include <QPointingDevice> + +#include <emscripten/html5.h> QT_BEGIN_NAMESPACE @@ -43,6 +49,7 @@ class QWasmWindow; class QWasmScreen; class QOpenGLContext; class QOpenGLTexture; +class QWasmEventTranslator; class QWasmCompositedWindow { @@ -63,6 +70,7 @@ class QWasmCompositor : public QObject public: QWasmCompositor(QWasmScreen *screen); ~QWasmCompositor(); + void deregisterEventHandlers(); void destroy(); enum QWasmSubControl { @@ -84,6 +92,18 @@ public: }; Q_DECLARE_FLAGS(StateFlags, QWasmStateFlag) + enum ResizeMode { + ResizeNone, + ResizeTopLeft, + ResizeTop, + ResizeTopRight, + ResizeRight, + ResizeBottomRight, + ResizeBottom, + ResizeBottomLeft, + ResizeLeft + }; + struct QWasmTitleBarOptions { QRect rect; Qt::WindowFlags flags; @@ -128,9 +148,17 @@ 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); + +private slots: void frame(); private: + void initEventHandlers(); void notifyTopWindowChanged(QWasmWindow *window); void drawWindow(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, QWasmWindow *window); void drawWindowContent(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, QWasmWindow *window); @@ -156,6 +184,21 @@ private: int m_requestAnimationFrameId = -1; bool m_inDeliverUpdateRequest = false; + QPointer<QWindow> draggedWindow; + QPointer<QWindow> pressedWindow; + QPointer<QWindow> lastWindow; + Qt::MouseButtons pressedButtons; + + QWasmCompositor::ResizeMode resizeMode; + QPoint resizePoint; + QRect resizeStartRect; + QPointingDevice *touchDevice; + + QMap <int, QPointF> pressedTouchIds; + + QCursor overriddenCursor; + bool isCursorOverridden = false; + static QPalette makeWindowPalette(); void drawFrameWindow(QWasmFrameOptions options, QPainter *painter); @@ -163,6 +206,15 @@ private: void drawShadePanel(QWasmTitleBarOptions options, QPainter *painter); void drawItemPixmap(QPainter *painter, const QRect &rect, 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); + + static int touchCallback(int eventType, const EmscriptenTouchEvent *ev, void *userData); + + QWasmEventTranslator *eventTranslator; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QWasmCompositor::SubControls) diff --git a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp index 34b1a7358a..0285ace1e6 100644 --- a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp +++ b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp @@ -177,101 +177,12 @@ static constexpr const auto DeadKeyShiftTbl = qMakeArray( >::Data{} ); -// macOS CTRL <-> META switching. We most likely want to enable -// the existing switching code in QtGui, but for now do it here. -static bool g_usePlatformMacSpecifics = false; - -bool g_useNaturalScrolling = true; // natural scrolling is default on linux/windows - -static void mouseWheelEvent(emscripten::val event) { - - emscripten::val wheelInterted = event["webkitDirectionInvertedFromDevice"]; - - if (wheelInterted.as<bool>()) { - g_useNaturalScrolling = true; - } -} - -EMSCRIPTEN_BINDINGS(qtMouseModule) { - function("qtMouseWheelEvent", &mouseWheelEvent); -} - -QWasmEventTranslator::QWasmEventTranslator(QWasmScreen *screen) - : QObject(screen) - , draggedWindow(nullptr) - , lastWindow(nullptr) - , pressedButtons(Qt::NoButton) - , resizeMode(QWasmWindow::ResizeNone) +QWasmEventTranslator::QWasmEventTranslator() : QObject() { - touchDevice = new QPointingDevice("touchscreen", 1, QInputDevice::DeviceType::TouchScreen, - QPointingDevice::PointerType::Finger, - QPointingDevice::Capability::Position | QPointingDevice::Capability::Area | QPointingDevice::Capability::NormalizedPosition, - 10, 0); - QWindowSystemInterface::registerInputDevice(touchDevice); - - initEventHandlers(); } QWasmEventTranslator::~QWasmEventTranslator() { - // deregister event handlers - QByteArray canvasSelector = "#" + screen()->canvasId().toUtf8(); - 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_focus_callback(canvasSelector.constData(), 0, 0, NULL); - - emscripten_set_wheel_callback(canvasSelector.constData(), 0, 0, NULL); - - emscripten_set_touchstart_callback(canvasSelector.constData(), 0, 0, NULL); - emscripten_set_touchend_callback(canvasSelector.constData(), 0, 0, NULL); - emscripten_set_touchmove_callback(canvasSelector.constData(), 0, 0, NULL); - emscripten_set_touchcancel_callback(canvasSelector.constData(), 0, 0, NULL); -} - -void QWasmEventTranslator::initEventHandlers() -{ - QByteArray canvasSelector = "#" + screen()->canvasId().toUtf8(); - - // The Platform Detect: expand coverage and move as needed - enum Platform { - GenericPlatform, - MacOSPlatform - }; - Platform platform = Platform(emscripten::val::global("navigator")["platform"] - .call<bool>("includes", emscripten::val("Mac"))); - g_usePlatformMacSpecifics = (platform == MacOSPlatform); - - if (platform == MacOSPlatform) { - g_useNaturalScrolling = false; // make this !default on macOS - - if (!emscripten::val::global("window")["safari"].isUndefined()) { - val canvas = screen()->canvas(); - canvas.call<void>("addEventListener", - val("wheel"), - val::module_property("qtMouseWheelEvent")); - } - } - - emscripten_set_keydown_callback(canvasSelector.constData(), (void *)this, 1, &keyboard_cb); - emscripten_set_keyup_callback(canvasSelector.constData(), (void *)this, 1, &keyboard_cb); - - emscripten_set_mousedown_callback(canvasSelector.constData(), (void *)this, 1, &mouse_cb); - emscripten_set_mouseup_callback(canvasSelector.constData(), (void *)this, 1, &mouse_cb); - emscripten_set_mousemove_callback(canvasSelector.constData(), (void *)this, 1, &mouse_cb); - - emscripten_set_focus_callback(canvasSelector.constData(), (void *)this, 1, &focus_cb); - - emscripten_set_wheel_callback(canvasSelector.constData(), (void *)this, 1, &wheel_cb); - - emscripten_set_touchstart_callback(canvasSelector.constData(), (void *)this, 1, &touchCallback); - emscripten_set_touchend_callback(canvasSelector.constData(), (void *)this, 1, &touchCallback); - emscripten_set_touchmove_callback(canvasSelector.constData(), (void *)this, 1, &touchCallback); - emscripten_set_touchcancel_callback(canvasSelector.constData(), (void *)this, 1, &touchCallback); } template <typename Event> @@ -294,13 +205,15 @@ QFlags<Qt::KeyboardModifier> QWasmEventTranslator::translatKeyModifier(const Eve else keyModifier |= Qt::MetaModifier; } + return keyModifier; } -QFlags<Qt::KeyboardModifier> QWasmEventTranslator::translateKeyboardEventModifier(const EmscriptenKeyboardEvent *keyEvent) +QFlags<Qt::KeyboardModifier> QWasmEventTranslator::translateKeyboardEventModifier(const EmscriptenKeyboardEvent *event) { - QFlags<Qt::KeyboardModifier> keyModifier = translatKeyModifier(keyEvent); - if (keyEvent->location == DOM_KEY_LOCATION_NUMPAD) { + QFlags<Qt::KeyboardModifier> keyModifier = translatKeyModifier(event); + + if (event->location == DOM_KEY_LOCATION_NUMPAD) { keyModifier |= Qt::KeypadModifier; } @@ -312,17 +225,9 @@ QFlags<Qt::KeyboardModifier> QWasmEventTranslator::translateMouseEventModifier(c return translatKeyModifier(mouseEvent); } -int QWasmEventTranslator::keyboard_cb(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData) +QFlags<Qt::KeyboardModifier> QWasmEventTranslator::translateTouchEventModifier(const EmscriptenTouchEvent *touchEvent) { - QWasmEventTranslator *wasmTranslator = reinterpret_cast<QWasmEventTranslator *>(userData); - bool accepted = wasmTranslator->processKeyboard(eventType, keyEvent); - - return accepted ? 1 : 0; -} - -QWasmScreen *QWasmEventTranslator::screen() -{ - return static_cast<QWasmScreen *>(parent()); + return translatKeyModifier(touchEvent); } Qt::Key QWasmEventTranslator::translateEmscriptKey(const EmscriptenKeyboardEvent *emscriptKey) @@ -367,335 +272,6 @@ Qt::MouseButton QWasmEventTranslator::translateMouseButton(unsigned short button return Qt::NoButton; } -int QWasmEventTranslator::mouse_cb(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData) -{ - QWasmEventTranslator *translator = (QWasmEventTranslator*)userData; - bool accepted = translator->processMouse(eventType,mouseEvent); - return accepted; -} - -void resizeWindow(QWindow *window, QWasmWindow::ResizeMode mode, - QRect startRect, QPoint amount) -{ - if (mode == QWasmWindow::ResizeNone) - return; - - bool top = mode == QWasmWindow::ResizeTopLeft || - mode == QWasmWindow::ResizeTop || - mode == QWasmWindow::ResizeTopRight; - - bool bottom = mode == QWasmWindow::ResizeBottomLeft || - mode == QWasmWindow::ResizeBottom || - mode == QWasmWindow::ResizeBottomRight; - - bool left = mode == QWasmWindow::ResizeLeft || - mode == QWasmWindow::ResizeTopLeft || - mode == QWasmWindow::ResizeBottomLeft; - - bool right = mode == QWasmWindow::ResizeRight || - mode == QWasmWindow::ResizeTopRight || - mode == QWasmWindow::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); -} - -bool QWasmEventTranslator::processMouse(int eventType, const EmscriptenMouseEvent *mouseEvent) -{ - QPoint targetPoint(mouseEvent->targetX, mouseEvent->targetY); - QPoint globalPoint = screen()->geometry().topLeft() + targetPoint; - - QEvent::Type buttonEventType = QEvent::None; - Qt::MouseButton button = Qt::NoButton; - Qt::KeyboardModifiers modifiers = translateMouseEventModifier(mouseEvent); - - QWindow *window2 = nullptr; - if (resizeMode == QWasmWindow::ResizeNone) - window2 = screen()->compositor()->windowAt(globalPoint, 5); - - if (window2 == nullptr) { - window2 = lastWindow; - } else { - lastWindow = window2; - } - - QPoint localPoint = window2->mapFromGlobal(globalPoint); - bool interior = window2->geometry().contains(globalPoint); - - QWasmWindow *htmlWindow = static_cast<QWasmWindow*>(window2->handle()); - switch (eventType) { - case EMSCRIPTEN_EVENT_MOUSEDOWN: - { - button = translateMouseButton(mouseEvent->button); - - if (window2) - window2->requestActivate(); - - pressedButtons.setFlag(button); - - pressedWindow = window2; - buttonEventType = QEvent::MouseButtonPress; - - // button overview: - // 0 = primary mouse button, usually left click - // 1 = middle mouse button, usually mouse wheel - // 2 = right mouse button, usually right click - // from: https://w3c.github.io/uievents/#dom-mouseevent-button - if (mouseEvent->button == 0) { - if (!(htmlWindow->m_windowState & Qt::WindowFullScreen) && !(htmlWindow->m_windowState & Qt::WindowMaximized)) { - if (htmlWindow && window2->flags().testFlag(Qt::WindowTitleHint) && htmlWindow->isPointOnTitle(globalPoint)) - draggedWindow = window2; - else if (htmlWindow && htmlWindow->isPointOnResizeRegion(globalPoint)) { - draggedWindow = window2; - resizeMode = htmlWindow->resizeModeAtPoint(globalPoint); - resizePoint = globalPoint; - resizeStartRect = window2->geometry(); - } - } - } - - htmlWindow->injectMousePressed(localPoint, globalPoint, button, modifiers); - break; - } - case EMSCRIPTEN_EVENT_MOUSEUP: - { - button = translateMouseButton(mouseEvent->button); - pressedButtons.setFlag(button, false); - buttonEventType = QEvent::MouseButtonRelease; - QWasmWindow *oldWindow = nullptr; - - if (mouseEvent->button == 0 && pressedWindow) { - oldWindow = static_cast<QWasmWindow*>(pressedWindow->handle()); - pressedWindow = nullptr; - } - - if (draggedWindow && pressedButtons.testFlag(Qt::NoButton)) { - draggedWindow = nullptr; - resizeMode = QWasmWindow::ResizeNone; - } - - if (oldWindow) - oldWindow->injectMouseReleased(localPoint, globalPoint, button, modifiers); - else - htmlWindow->injectMouseReleased(localPoint, globalPoint, button, modifiers); - break; - } - case EMSCRIPTEN_EVENT_MOUSEMOVE: // drag event - { - buttonEventType = QEvent::MouseMove; - - if (htmlWindow && pressedButtons.testFlag(Qt::NoButton)) { - - if (htmlWindow->isPointOnResizeRegion(globalPoint)) { - QCursor resizingCursor = cursorForMode(htmlWindow->resizeModeAtPoint(globalPoint)); - - if (resizingCursor != window2->cursor()) { - isCursorOverridden = true; - QWasmCursor::setOverrideWasmCursor(&resizingCursor, window2->screen()); - } - } else { // off resizing area - if (isCursorOverridden) { - isCursorOverridden = false; - QWasmCursor::clearOverrideWasmCursor(window2->screen()); - } - } - } - - if (!(htmlWindow->m_windowState & Qt::WindowFullScreen) && !(htmlWindow->m_windowState & Qt::WindowMaximized)) { - if (resizeMode == QWasmWindow::ResizeNone && draggedWindow) { - draggedWindow->setX(draggedWindow->x() + mouseEvent->movementX); - draggedWindow->setY(draggedWindow->y() + mouseEvent->movementY); - } - - if (resizeMode != QWasmWindow::ResizeNone && !(htmlWindow->m_windowState & Qt::WindowFullScreen)) { - QPoint delta = QPoint(mouseEvent->targetX, mouseEvent->targetY) - resizePoint; - resizeWindow(draggedWindow, resizeMode, resizeStartRect, delta); - } - } - break; - } - default: // MOUSELEAVE MOUSEENTER - break; - }; - if (!window2 && buttonEventType == QEvent::MouseButtonRelease) { - window2 = lastWindow; - lastWindow = nullptr; - interior = true; - } - bool accepted = true; - if (window2 && interior) { - accepted = QWindowSystemInterface::handleMouseEvent<QWindowSystemInterface::SynchronousDelivery>( - window2, getTimestamp(), localPoint, globalPoint, pressedButtons, button, buttonEventType, modifiers); - } - return accepted; -} - -int QWasmEventTranslator::focus_cb(int /*eventType*/, const EmscriptenFocusEvent */*focusEvent*/, void */*userData*/) -{ - return 0; -} - -int QWasmEventTranslator::wheel_cb(int eventType, const EmscriptenWheelEvent *wheelEvent, void *userData) -{ - Q_UNUSED(eventType); - - QWasmEventTranslator *eventTranslator = static_cast<QWasmEventTranslator *>(userData); - EmscriptenMouseEvent mouseEvent = wheelEvent->mouse; - - int scrollFactor = 0; - switch (wheelEvent->deltaMode) { - case DOM_DELTA_PIXEL://chrome safari - scrollFactor = 1; - break; - case DOM_DELTA_LINE: //firefox - scrollFactor = 12; - break; - case DOM_DELTA_PAGE: - scrollFactor = 20; - break; - }; - - if (g_useNaturalScrolling) //macOS platform has document oriented scrolling - scrollFactor = -scrollFactor; - - QWasmEventTranslator *translator = (QWasmEventTranslator*)userData; - Qt::KeyboardModifiers modifiers = translator->translateMouseEventModifier(&mouseEvent); - QPoint targetPoint(mouseEvent.targetX, mouseEvent.targetY); - QPoint globalPoint = eventTranslator->screen()->geometry().topLeft() + targetPoint; - - QWindow *window2 = eventTranslator->screen()->compositor()->windowAt(globalPoint, 5); - if (!window2) - return 0; - QPoint localPoint = window2->mapFromGlobal(globalPoint); - - QPoint pixelDelta; - - if (wheelEvent->deltaY != 0) pixelDelta.setY(wheelEvent->deltaY * scrollFactor); - if (wheelEvent->deltaX != 0) pixelDelta.setX(wheelEvent->deltaX * scrollFactor); - - bool accepted = QWindowSystemInterface::handleWheelEvent(window2, getTimestamp(), localPoint, - globalPoint, QPoint(), pixelDelta, modifiers); - return static_cast<int>(accepted); -} - -int QWasmEventTranslator::touchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData) -{ - auto translator = reinterpret_cast<QWasmEventTranslator*>(userData); - return translator->handleTouch(eventType, touchEvent); -} - -int QWasmEventTranslator::handleTouch(int eventType, const EmscriptenTouchEvent *touchEvent) -{ - QList<QWindowSystemInterface::TouchPoint> touchPointList; - touchPointList.reserve(touchEvent->numTouches); - QWindow *window2; - - for (int i = 0; i < touchEvent->numTouches; i++) { - - const EmscriptenTouchPoint *touches = &touchEvent->touches[i]; - - QPoint targetPoint(touches->targetX, touches->targetY); - QPoint globalPoint = screen()->geometry().topLeft() + targetPoint; - - window2 = this->screen()->compositor()->windowAt(globalPoint, 5); - if (window2 == nullptr) - continue; - - QWindowSystemInterface::TouchPoint touchPoint; - - touchPoint.area = QRect(0, 0, 8, 8); - touchPoint.id = touches->identifier; - touchPoint.pressure = 1.0; - - touchPoint.area.moveCenter(globalPoint); - - const auto tp = pressedTouchIds.constFind(touchPoint.id); - if (tp != pressedTouchIds.constEnd()) - touchPoint.normalPosition = tp.value(); - - QPointF localPoint = QPointF(window2->mapFromGlobal(globalPoint)); - QPointF normalPosition(localPoint.x() / window2->width(), - localPoint.y() / window2->height()); - - const bool stationaryTouchPoint = (normalPosition == touchPoint.normalPosition); - touchPoint.normalPosition = normalPosition; - - switch (eventType) { - case EMSCRIPTEN_EVENT_TOUCHSTART: - if (tp != pressedTouchIds.constEnd()) { - touchPoint.state = (stationaryTouchPoint - ? QEventPoint::State::Stationary - : QEventPoint::State::Updated); - } else { - touchPoint.state = QEventPoint::State::Pressed; - } - pressedTouchIds.insert(touchPoint.id, touchPoint.normalPosition); - - break; - case EMSCRIPTEN_EVENT_TOUCHEND: - touchPoint.state = QEventPoint::State::Released; - pressedTouchIds.remove(touchPoint.id); - break; - case EMSCRIPTEN_EVENT_TOUCHMOVE: - touchPoint.state = (stationaryTouchPoint - ? QEventPoint::State::Stationary - : QEventPoint::State::Updated); - - pressedTouchIds.insert(touchPoint.id, touchPoint.normalPosition); - break; - default: - break; - } - - touchPointList.append(touchPoint); - } - - QFlags<Qt::KeyboardModifier> keyModifier = translatKeyModifier(touchEvent); - - bool accepted = QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::SynchronousDelivery>( - window2, getTimestamp(), touchDevice, touchPointList, keyModifier); - - if (eventType == EMSCRIPTEN_EVENT_TOUCHCANCEL) - accepted = QWindowSystemInterface::handleTouchCancelEvent(window2, getTimestamp(), touchDevice, keyModifier); - - return static_cast<int>(accepted); -} - -quint64 QWasmEventTranslator::getTimestamp() -{ - return emscripten_performance_now(); -} - struct KeyMapping { Qt::Key from, to; }; constexpr KeyMapping tildeKeyTable[] = { // ~ @@ -750,12 +326,12 @@ static Qt::Key find(const KeyMapping (&map)[N], Qt::Key key) noexcept return find_impl(map, map + N, key); } -Qt::Key QWasmEventTranslator::translateDeadKey(Qt::Key deadKey, Qt::Key accentBaseKey) +Qt::Key QWasmEventTranslator::translateDeadKey(Qt::Key deadKey, Qt::Key accentBaseKey, bool is_mac) { Qt::Key wasmKey = Qt::Key_unknown; if (deadKey == Qt::Key_QuoteLeft ) { - if (g_usePlatformMacSpecifics) { // ` macOS: Key_Dead_Grave + if (is_mac) { // ` macOS: Key_Dead_Grave wasmKey = find(graveKeyTable, accentBaseKey); } else { wasmKey = find(diaeresisKeyTable, accentBaseKey); @@ -790,121 +366,83 @@ Qt::Key QWasmEventTranslator::translateDeadKey(Qt::Key deadKey, Qt::Key accentBa return wasmKey; } -bool QWasmEventTranslator::processKeyboard(int eventType, const EmscriptenKeyboardEvent *keyEvent) +QCursor QWasmEventTranslator::cursorForMode(QWasmCompositor::ResizeMode m) +{ + switch (m) { + case QWasmCompositor::ResizeTopLeft: + case QWasmCompositor::ResizeBottomRight: + return Qt::SizeFDiagCursor; + case QWasmCompositor::ResizeBottomLeft: + case QWasmCompositor::ResizeTopRight: + return Qt::SizeBDiagCursor; + case QWasmCompositor::ResizeTop: + case QWasmCompositor::ResizeBottom: + return Qt::SizeVerCursor; + case QWasmCompositor::ResizeLeft: + case QWasmCompositor::ResizeRight: + return Qt::SizeHorCursor; + case QWasmCompositor::ResizeNone: + return Qt::ArrowCursor; + } + return Qt::ArrowCursor; +} + +QString QWasmEventTranslator::getKeyText(const EmscriptenKeyboardEvent *keyEvent) { + QString keyText; Qt::Key qtKey = translateEmscriptKey(keyEvent); + //Qt::KeyboardModifiers modifiers = translateKeyboardEventModifier(keyEvent); - Qt::KeyboardModifiers modifiers = translateKeyboardEventModifier(keyEvent); + if (m_emDeadKey != Qt::Key_unknown) { + Qt::Key transformedKey = translateDeadKey(m_emDeadKey, qtKey); - QString keyText; - QEvent::Type keyType = QEvent::None; - switch (eventType) { - case EMSCRIPTEN_EVENT_KEYPRESS: - case EMSCRIPTEN_EVENT_KEYDOWN: // down - keyType = QEvent::KeyPress; - - if (m_emDeadKey != Qt::Key_unknown) { - - Qt::Key transformedKey = translateDeadKey(m_emDeadKey, qtKey); - - if (transformedKey != Qt::Key_unknown) - qtKey = transformedKey; - - if (keyEvent->shiftKey == 0) { - for (auto it = KeyTbl.cbegin(); it != KeyTbl.end(); ++it) { - if (it != KeyTbl.end() && (qtKey == static_cast<Qt::Key>(it->qt))) { - keyText = it->em; - m_emDeadKey = Qt::Key_unknown; - break; - } + if (transformedKey != Qt::Key_unknown) + qtKey = transformedKey; + + if (keyEvent->shiftKey == 0) { + for (auto it = KeyTbl.cbegin(); it != KeyTbl.end(); ++it) { + if (it != KeyTbl.end() && (qtKey == static_cast<Qt::Key>(it->qt))) { + keyText = it->em; + m_emDeadKey = Qt::Key_unknown; + break; } - } else { - for (auto it = DeadKeyShiftTbl.cbegin(); it != DeadKeyShiftTbl.end(); ++it) { - if (it != DeadKeyShiftTbl.end() && (qtKey == static_cast<Qt::Key>(it->qt))) { - keyText = it->em; - m_emDeadKey = Qt::Key_unknown; - break; - } + } + } else { + for (auto it = DeadKeyShiftTbl.cbegin(); it != DeadKeyShiftTbl.end(); ++it) { + if (it != DeadKeyShiftTbl.end() && (qtKey == static_cast<Qt::Key>(it->qt))) { + keyText = it->em; + m_emDeadKey = Qt::Key_unknown; + break; } } } - if (qstrncmp(keyEvent->key, "Dead", 4) == 0 || qtKey == Qt::Key_AltGr) { - qtKey = translateEmscriptKey(keyEvent); - m_emStickyDeadKey = true; - if (keyEvent->shiftKey == 1 && qtKey == Qt::Key_QuoteLeft) - qtKey = Qt::Key_AsciiTilde; - m_emDeadKey = qtKey; - } - break; - case EMSCRIPTEN_EVENT_KEYUP: // up - keyType = QEvent::KeyRelease; - if (m_emStickyDeadKey && qtKey != Qt::Key_Alt) { - m_emStickyDeadKey = false; - } - break; - default: - break; - }; - - if (keyType == QEvent::None) - return 0; + } - QFlags<Qt::KeyboardModifier> mods = translateKeyboardEventModifier(keyEvent); + return keyText; +} - // Clipboard fallback path: cut/copy/paste are handled by clipboard event - // handlers if direct clipboard access is not available. - if (!QWasmIntegration::get()->getWasmClipboard()->hasClipboardApi && modifiers & Qt::ControlModifier && - (qtKey == Qt::Key_X || qtKey == Qt::Key_C || qtKey == Qt::Key_V)) { - if (qtKey == Qt::Key_V) { - QWasmIntegration::get()->getWasmClipboard()->isPaste = true; - } - return false; - } +Qt::Key QWasmEventTranslator::getKey(const EmscriptenKeyboardEvent *keyEvent) +{ + Qt::Key qtKey = translateEmscriptKey(keyEvent); - bool accepted = false; - - if (keyType == QEvent::KeyPress && - mods.testFlag(Qt::ControlModifier) - && qtKey == Qt::Key_V) { - QWasmIntegration::get()->getWasmClipboard()->isPaste = true; - accepted = false; // continue on to event - } else { - if (keyText.isEmpty()) - keyText = QString(keyEvent->key); - if (keyText.size() > 1) - keyText.clear(); - accepted = QWindowSystemInterface::handleKeyEvent<QWindowSystemInterface::SynchronousDelivery>( - 0, keyType, qtKey, modifiers, keyText); - } - if (keyType == QEvent::KeyPress && - mods.testFlag(Qt::ControlModifier) - && qtKey == Qt::Key_C) { - QWasmIntegration::get()->getWasmClipboard()->isPaste = false; - accepted = false; // continue on to event + if (qstrncmp(keyEvent->key, "Dead", 4) == 0 || qtKey == Qt::Key_AltGr) { + qtKey = translateEmscriptKey(keyEvent); + m_emStickyDeadKey = true; + if (keyEvent->shiftKey == 1 && qtKey == Qt::Key_QuoteLeft) + qtKey = Qt::Key_AsciiTilde; + m_emDeadKey = qtKey; } - return accepted; + return qtKey; } -QCursor QWasmEventTranslator::cursorForMode(QWasmWindow::ResizeMode m) +void QWasmEventTranslator::setStickyDeadKey(const EmscriptenKeyboardEvent *keyEvent) { - switch (m) { - case QWasmWindow::ResizeTopLeft: - case QWasmWindow::ResizeBottomRight: - return Qt::SizeFDiagCursor; - case QWasmWindow::ResizeBottomLeft: - case QWasmWindow::ResizeTopRight: - return Qt::SizeBDiagCursor; - case QWasmWindow::ResizeTop: - case QWasmWindow::ResizeBottom: - return Qt::SizeVerCursor; - case QWasmWindow::ResizeLeft: - case QWasmWindow::ResizeRight: - return Qt::SizeHorCursor; - case QWasmWindow::ResizeNone: - return Qt::ArrowCursor; + Qt::Key qtKey = translateEmscriptKey(keyEvent); + + if (m_emStickyDeadKey && qtKey != Qt::Key_Alt) { + m_emStickyDeadKey = false; } - return Qt::ArrowCursor; } QT_END_NAMESPACE diff --git a/src/plugins/platforms/wasm/qwasmeventtranslator.h b/src/plugins/platforms/wasm/qwasmeventtranslator.h index 0b579691c5..341971d79f 100644 --- a/src/plugins/platforms/wasm/qwasmeventtranslator.h +++ b/src/plugins/platforms/wasm/qwasmeventtranslator.h @@ -49,59 +49,37 @@ class QWasmEventTranslator : public QObject public: - explicit QWasmEventTranslator(QWasmScreen *screen); + explicit QWasmEventTranslator(); ~QWasmEventTranslator(); - 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); - - static int touchCallback(int eventType, const EmscriptenTouchEvent *ev, void *userData); - - void processEvents(); - void initEventHandlers(); - int handleTouch(int eventType, const EmscriptenTouchEvent *touchEvent); - -Q_SIGNALS: - void getWindowAt(const QPoint &point, QWindow **window); -private: - QWasmScreen *screen(); - Qt::Key translateEmscriptKey(const EmscriptenKeyboardEvent *emscriptKey); 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); - Qt::MouseButton translateMouseButton(unsigned short button); + QFlags<Qt::KeyboardModifier> translateTouchEventModifier(const EmscriptenTouchEvent *touchEvent); + static Qt::MouseButton translateMouseButton(unsigned short button); + static QCursor cursorForMode(QWasmCompositor::ResizeMode mode); - bool processMouse(int eventType, const EmscriptenMouseEvent *mouseEvent); - bool processKeyboard(int eventType, const EmscriptenKeyboardEvent *keyEvent); + QString getKeyText(const EmscriptenKeyboardEvent *keyEvent); + Qt::Key getKey(const EmscriptenKeyboardEvent *keyEvent); + void setStickyDeadKey(const EmscriptenKeyboardEvent *keyEvent); - Qt::Key translateDeadKey(Qt::Key deadKey, Qt::Key accentBaseKey); + void setIsMac(bool is_mac) {g_usePlatformMacSpecifics = is_mac;}; - QMap <int, QPointF> pressedTouchIds; +Q_SIGNALS: + void getWindowAt(const QPoint &point, QWindow **window); +private: + bool g_usePlatformMacSpecifics = false; + static Qt::Key translateDeadKey(Qt::Key deadKey, Qt::Key accentBaseKey, bool is_mac = false); private: - QPointer<QWindow> draggedWindow; - QPointer<QWindow> pressedWindow; - QPointer<QWindow> lastWindow; - Qt::MouseButtons pressedButtons; - - QWasmWindow::ResizeMode resizeMode; - QPoint resizePoint; - QRect resizeStartRect; -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - QPointingDevice *touchDevice; -#else - QTouchDevice *touchDevice; -#endif static quint64 getTimestamp(); Qt::Key m_emDeadKey = Qt::Key_unknown; bool m_emStickyDeadKey = false; - QCursor cursorForMode(QWasmWindow::ResizeMode mode); - QCursor overriddenCursor; - bool isCursorOverridden = false; + }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/wasm/qwasmintegration.cpp b/src/plugins/platforms/wasm/qwasmintegration.cpp index 3dfd8cfe12..031128563e 100644 --- a/src/plugins/platforms/wasm/qwasmintegration.cpp +++ b/src/plugins/platforms/wasm/qwasmintegration.cpp @@ -328,4 +328,9 @@ void QWasmIntegration::resizeAllScreens() canvasAndScreen.second->updateQScreenAndCanvasRenderSize(); } +quint64 QWasmIntegration::getTimestamp() +{ + return emscripten_performance_now(); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/wasm/qwasmintegration.h b/src/plugins/platforms/wasm/qwasmintegration.h index 16c48e1ea1..46fab8e818 100644 --- a/src/plugins/platforms/wasm/qwasmintegration.h +++ b/src/plugins/platforms/wasm/qwasmintegration.h @@ -89,6 +89,7 @@ public: void resizeAllScreens(); void updateDpi(); void removeBackingStore(QWindow* window); + static quint64 getTimestamp(); private: mutable QWasmFontDatabase *m_fontDb; diff --git a/src/plugins/platforms/wasm/qwasmscreen.cpp b/src/plugins/platforms/wasm/qwasmscreen.cpp index 3cc067bbe7..eb77dc65b9 100644 --- a/src/plugins/platforms/wasm/qwasmscreen.cpp +++ b/src/plugins/platforms/wasm/qwasmscreen.cpp @@ -55,7 +55,7 @@ const char * QWasmScreen::m_canvasResizeObserverCallbackContextPropertyName = "d QWasmScreen::QWasmScreen(const emscripten::val &canvas) : m_canvas(canvas) , m_compositor(new QWasmCompositor(this)) - , m_eventTranslator(new QWasmEventTranslator(this)) + , m_eventTranslator(new QWasmEventTranslator()) { updateQScreenAndCanvasRenderSize(); m_canvas.call<void>("focus"); diff --git a/src/plugins/platforms/wasm/qwasmwindow.cpp b/src/plugins/platforms/wasm/qwasmwindow.cpp index 3819e8daa6..a25b5a262c 100644 --- a/src/plugins/platforms/wasm/qwasmwindow.cpp +++ b/src/plugins/platforms/wasm/qwasmwindow.cpp @@ -274,7 +274,7 @@ bool QWasmWindow::isPointOnResizeRegion(QPoint point) const return resizeRegion().contains(point); } -QWasmWindow::ResizeMode QWasmWindow::resizeModeAtPoint(QPoint point) const +QWasmCompositor::ResizeMode QWasmWindow::resizeModeAtPoint(QPoint point) const { QPoint p1 = window()->frameGeometry().topLeft() - QPoint(5, 5); QPoint p2 = window()->frameGeometry().bottomRight() + QPoint(5, 5); @@ -291,28 +291,28 @@ QWasmWindow::ResizeMode QWasmWindow::resizeModeAtPoint(QPoint point) const if (top.contains(point)) { // Top if (left.contains(point)) - return ResizeTopLeft; + return QWasmCompositor::ResizeTopLeft; if (center.contains(point)) - return ResizeTop; + return QWasmCompositor::ResizeTop; if (right.contains(point)) - return ResizeTopRight; + return QWasmCompositor::ResizeTopRight; } else if (middle.contains(point)) { // Middle if (left.contains(point)) - return ResizeLeft; + return QWasmCompositor::ResizeLeft; if (right.contains(point)) - return ResizeRight; + return QWasmCompositor::ResizeRight; } else if (bottom.contains(point)) { // Bottom if (left.contains(point)) - return ResizeBottomLeft; + return QWasmCompositor::ResizeBottomLeft; if (center.contains(point)) - return ResizeBottom; + return QWasmCompositor::ResizeBottom; if (right.contains(point)) - return ResizeBottomRight; + return QWasmCompositor::ResizeBottomRight; } - return ResizeNone; + return QWasmCompositor::ResizeNone; } QRect getSubControlRect(const QWasmWindow *window, QWasmCompositor::SubControls subControl) diff --git a/src/plugins/platforms/wasm/qwasmwindow.h b/src/plugins/platforms/wasm/qwasmwindow.h index 5df6d9dc66..686a26430e 100644 --- a/src/plugins/platforms/wasm/qwasmwindow.h +++ b/src/plugins/platforms/wasm/qwasmwindow.h @@ -39,23 +39,9 @@ QT_BEGIN_NAMESPACE -class QWasmCompositor; - class QWasmWindow : public QPlatformWindow { public: - enum ResizeMode { - ResizeNone, - ResizeTopLeft, - ResizeTop, - ResizeTopRight, - ResizeRight, - ResizeBottomRight, - ResizeBottom, - ResizeBottomLeft, - ResizeLeft - }; - QWasmWindow(QWindow *w, QWasmCompositor *compositor, QWasmBackingStore *backingStore); ~QWasmWindow(); void destroy(); @@ -92,7 +78,7 @@ public: QRegion resizeRegion() const; bool isPointOnTitle(QPoint point) const; bool isPointOnResizeRegion(QPoint point) const; - ResizeMode resizeModeAtPoint(QPoint point) const; + QWasmCompositor::ResizeMode resizeModeAtPoint(QPoint point) const; QRect maxButtonRect() const; QRect minButtonRect() const; QRect closeButtonRect() const; |