Handle the wheel event in the wasm window
Align the wheel event handling with other events - move the handler to wasm window and create a C++ wrapper class for the js wheel event. Fixes: QTBUG-109622 Change-Id: I915e502de7c0784ec9a6745a90ddcda062e91b2b Reviewed-by: Mikołaj Boc <Mikolaj.Boc@qt.io> Reviewed-by: Lorn Potter <lorn.potter@gmail.com> Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
This commit is contained in:
parent
5d356ae2bd
commit
c54416a06c
@ -29,19 +29,6 @@ using namespace emscripten;
|
|||||||
|
|
||||||
Q_GUI_EXPORT int qt_defaultDpiX();
|
Q_GUI_EXPORT int qt_defaultDpiX();
|
||||||
|
|
||||||
bool g_scrollingInvertedFromDevice = false;
|
|
||||||
|
|
||||||
static void mouseWheelEvent(emscripten::val event)
|
|
||||||
{
|
|
||||||
emscripten::val wheelInverted = event["webkitDirectionInvertedFromDevice"];
|
|
||||||
if (wheelInverted.as<bool>())
|
|
||||||
g_scrollingInvertedFromDevice = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_BINDINGS(qtMouseModule) {
|
|
||||||
function("qtMouseWheelEvent", &mouseWheelEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
QWasmCompositor::QWasmCompositor(QWasmScreen *screen)
|
QWasmCompositor::QWasmCompositor(QWasmScreen *screen)
|
||||||
: QObject(screen),
|
: QObject(screen),
|
||||||
m_windowStack(std::bind(&QWasmCompositor::onTopWindowChanged, this)),
|
m_windowStack(std::bind(&QWasmCompositor::onTopWindowChanged, this)),
|
||||||
@ -77,8 +64,6 @@ void QWasmCompositor::deregisterEventHandlers()
|
|||||||
emscripten_set_keydown_callback(screenElementSelector.constData(), 0, 0, NULL);
|
emscripten_set_keydown_callback(screenElementSelector.constData(), 0, 0, NULL);
|
||||||
emscripten_set_keyup_callback(screenElementSelector.constData(), 0, 0, NULL);
|
emscripten_set_keyup_callback(screenElementSelector.constData(), 0, 0, NULL);
|
||||||
|
|
||||||
emscripten_set_wheel_callback(screenElementSelector.constData(), 0, 0, NULL);
|
|
||||||
|
|
||||||
emscripten_set_touchstart_callback(screenElementSelector.constData(), 0, 0, NULL);
|
emscripten_set_touchstart_callback(screenElementSelector.constData(), 0, 0, NULL);
|
||||||
emscripten_set_touchend_callback(screenElementSelector.constData(), 0, 0, NULL);
|
emscripten_set_touchend_callback(screenElementSelector.constData(), 0, 0, NULL);
|
||||||
emscripten_set_touchmove_callback(screenElementSelector.constData(), 0, 0, NULL);
|
emscripten_set_touchmove_callback(screenElementSelector.constData(), 0, 0, NULL);
|
||||||
@ -94,13 +79,6 @@ void QWasmCompositor::destroy()
|
|||||||
|
|
||||||
void QWasmCompositor::initEventHandlers()
|
void QWasmCompositor::initEventHandlers()
|
||||||
{
|
{
|
||||||
if (platform() == Platform::MacOS) {
|
|
||||||
if (!emscripten::val::global("window")["safari"].isUndefined()) {
|
|
||||||
screen()->element().call<void>("addEventListener", val("wheel"),
|
|
||||||
val::module_property("qtMouseWheelEvent"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr EM_BOOL UseCapture = 1;
|
constexpr EM_BOOL UseCapture = 1;
|
||||||
|
|
||||||
const QByteArray screenElementSelector = screen()->eventTargetId().toUtf8();
|
const QByteArray screenElementSelector = screen()->eventTargetId().toUtf8();
|
||||||
@ -109,9 +87,6 @@ void QWasmCompositor::initEventHandlers()
|
|||||||
emscripten_set_keyup_callback(screenElementSelector.constData(), (void *)this, UseCapture,
|
emscripten_set_keyup_callback(screenElementSelector.constData(), (void *)this, UseCapture,
|
||||||
&keyboard_cb);
|
&keyboard_cb);
|
||||||
|
|
||||||
emscripten_set_wheel_callback(screenElementSelector.constData(), (void *)this, UseCapture,
|
|
||||||
&wheel_cb);
|
|
||||||
|
|
||||||
emscripten_set_touchstart_callback(screenElementSelector.constData(), (void *)this, UseCapture,
|
emscripten_set_touchstart_callback(screenElementSelector.constData(), (void *)this, UseCapture,
|
||||||
&touchCallback);
|
&touchCallback);
|
||||||
emscripten_set_touchend_callback(screenElementSelector.constData(), (void *)this, UseCapture,
|
emscripten_set_touchend_callback(screenElementSelector.constData(), (void *)this, UseCapture,
|
||||||
@ -314,12 +289,6 @@ int QWasmCompositor::keyboard_cb(int eventType, const EmscriptenKeyboardEvent *k
|
|||||||
return static_cast<int>(wasmCompositor->processKeyboard(eventType, keyEvent));
|
return static_cast<int>(wasmCompositor->processKeyboard(eventType, keyEvent));
|
||||||
}
|
}
|
||||||
|
|
||||||
int QWasmCompositor::wheel_cb(int eventType, const EmscriptenWheelEvent *wheelEvent, void *userData)
|
|
||||||
{
|
|
||||||
QWasmCompositor *compositor = (QWasmCompositor *) userData;
|
|
||||||
return static_cast<int>(compositor->processWheel(eventType, wheelEvent));
|
|
||||||
}
|
|
||||||
|
|
||||||
int QWasmCompositor::touchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)
|
int QWasmCompositor::touchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)
|
||||||
{
|
{
|
||||||
auto compositor = reinterpret_cast<QWasmCompositor*>(userData);
|
auto compositor = reinterpret_cast<QWasmCompositor*>(userData);
|
||||||
@ -354,51 +323,6 @@ bool QWasmCompositor::processKeyboard(int eventType, const EmscriptenKeyboardEve
|
|||||||
: result;
|
: result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QWasmCompositor::processWheel(int eventType, const EmscriptenWheelEvent *wheelEvent)
|
|
||||||
{
|
|
||||||
Q_UNUSED(eventType);
|
|
||||||
|
|
||||||
const EmscriptenMouseEvent* mouseEvent = &wheelEvent->mouse;
|
|
||||||
|
|
||||||
int scrollFactor = 0;
|
|
||||||
switch (wheelEvent->deltaMode) {
|
|
||||||
case DOM_DELTA_PIXEL:
|
|
||||||
scrollFactor = 1;
|
|
||||||
break;
|
|
||||||
case DOM_DELTA_LINE:
|
|
||||||
scrollFactor = 12;
|
|
||||||
break;
|
|
||||||
case DOM_DELTA_PAGE:
|
|
||||||
scrollFactor = 20;
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
|
|
||||||
scrollFactor = -scrollFactor; // Web scroll deltas are inverted from Qt deltas.
|
|
||||||
|
|
||||||
Qt::KeyboardModifiers modifiers = KeyboardModifier::getForEvent(*mouseEvent);
|
|
||||||
QPoint targetPointInScreenCoords =
|
|
||||||
screen()->mapFromLocal(QPoint(mouseEvent->targetX, mouseEvent->targetY));
|
|
||||||
|
|
||||||
QWindow *targetWindow = screen()->compositor()->windowAt(targetPointInScreenCoords, 5);
|
|
||||||
if (!targetWindow)
|
|
||||||
return 0;
|
|
||||||
QPoint pointInTargetWindowCoords = targetWindow->mapFromGlobal(targetPointInScreenCoords);
|
|
||||||
|
|
||||||
QPoint pixelDelta;
|
|
||||||
|
|
||||||
if (wheelEvent->deltaY != 0) pixelDelta.setY(wheelEvent->deltaY * scrollFactor);
|
|
||||||
if (wheelEvent->deltaX != 0) pixelDelta.setX(wheelEvent->deltaX * scrollFactor);
|
|
||||||
|
|
||||||
QPoint angleDelta = pixelDelta; // FIXME: convert from pixels?
|
|
||||||
|
|
||||||
bool accepted = QWindowSystemInterface::handleWheelEvent(
|
|
||||||
targetWindow, QWasmIntegration::getTimestamp(), pointInTargetWindowCoords,
|
|
||||||
targetPointInScreenCoords, pixelDelta, angleDelta, modifiers,
|
|
||||||
Qt::NoScrollPhase, Qt::MouseEventNotSynthesized,
|
|
||||||
g_scrollingInvertedFromDevice);
|
|
||||||
return accepted;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QWasmCompositor::processTouch(int eventType, const EmscriptenTouchEvent *touchEvent)
|
bool QWasmCompositor::processTouch(int eventType, const EmscriptenTouchEvent *touchEvent)
|
||||||
{
|
{
|
||||||
QList<QWindowSystemInterface::TouchPoint> touchPointList;
|
QList<QWindowSystemInterface::TouchPoint> touchPointList;
|
||||||
|
@ -79,13 +79,10 @@ private:
|
|||||||
void deliverUpdateRequest(QWasmWindow *window, UpdateRequestDeliveryType updateType);
|
void deliverUpdateRequest(QWasmWindow *window, UpdateRequestDeliveryType updateType);
|
||||||
|
|
||||||
static int keyboard_cb(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData);
|
static int keyboard_cb(int eventType, const EmscriptenKeyboardEvent *keyEvent, 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);
|
static int touchCallback(int eventType, const EmscriptenTouchEvent *ev, void *userData);
|
||||||
|
|
||||||
bool processKeyboard(int eventType, const EmscriptenKeyboardEvent *keyEvent);
|
bool processKeyboard(int eventType, const EmscriptenKeyboardEvent *keyEvent);
|
||||||
bool processWheel(int eventType, const EmscriptenWheelEvent *wheelEvent);
|
|
||||||
bool processTouch(int eventType, const EmscriptenTouchEvent *touchEvent);
|
bool processTouch(int eventType, const EmscriptenTouchEvent *touchEvent);
|
||||||
|
|
||||||
void enterWindow(QWindow *window, const QPoint &localPoint, const QPoint &globalPoint);
|
void enterWindow(QWindow *window, const QPoint &localPoint, const QPoint &globalPoint);
|
||||||
|
@ -134,4 +134,45 @@ std::optional<DragEvent> DragEvent::fromWeb(emscripten::val event)
|
|||||||
return DragEvent(*eventType, event);
|
return DragEvent(*eventType, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WheelEvent::WheelEvent(EventType type, emscripten::val event) : MouseEvent(type, event)
|
||||||
|
{
|
||||||
|
deltaMode = ([event]() {
|
||||||
|
const int deltaMode = event["deltaMode"].as<int>();
|
||||||
|
const auto jsWheelEventType = emscripten::val::global("WheelEvent");
|
||||||
|
if (deltaMode == jsWheelEventType["DOM_DELTA_PIXEL"].as<int>())
|
||||||
|
return DeltaMode::Pixel;
|
||||||
|
else if (deltaMode == jsWheelEventType["DOM_DELTA_LINE"].as<int>())
|
||||||
|
return DeltaMode::Line;
|
||||||
|
return DeltaMode::Page;
|
||||||
|
})();
|
||||||
|
|
||||||
|
delta = QPoint(event["deltaX"].as<int>(), event["deltaY"].as<int>());
|
||||||
|
|
||||||
|
webkitDirectionInvertedFromDevice = event["webkitDirectionInvertedFromDevice"].as<bool>();
|
||||||
|
}
|
||||||
|
|
||||||
|
WheelEvent::~WheelEvent() = default;
|
||||||
|
|
||||||
|
WheelEvent::WheelEvent(const WheelEvent &other) = default;
|
||||||
|
|
||||||
|
WheelEvent::WheelEvent(WheelEvent &&other) = default;
|
||||||
|
|
||||||
|
WheelEvent &WheelEvent::operator=(const WheelEvent &other) = default;
|
||||||
|
|
||||||
|
WheelEvent &WheelEvent::operator=(WheelEvent &&other) = default;
|
||||||
|
|
||||||
|
std::optional<WheelEvent> WheelEvent::fromWeb(emscripten::val event)
|
||||||
|
{
|
||||||
|
const auto eventType = ([&event]() -> std::optional<EventType> {
|
||||||
|
const auto eventTypeString = event["type"].as<std::string>();
|
||||||
|
|
||||||
|
if (eventTypeString == "wheel")
|
||||||
|
return EventType::Wheel;
|
||||||
|
return std::nullopt;
|
||||||
|
})();
|
||||||
|
if (!eventType)
|
||||||
|
return std::nullopt;
|
||||||
|
return WheelEvent(*eventType, event);
|
||||||
|
}
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
@ -24,6 +24,7 @@ enum class EventType {
|
|||||||
PointerUp,
|
PointerUp,
|
||||||
PointerEnter,
|
PointerEnter,
|
||||||
PointerLeave,
|
PointerLeave,
|
||||||
|
Wheel,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class PointerType {
|
enum class PointerType {
|
||||||
@ -36,6 +37,8 @@ enum class WindowArea {
|
|||||||
Client,
|
Client,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class DeltaMode { Pixel, Line, Page };
|
||||||
|
|
||||||
namespace KeyboardModifier {
|
namespace KeyboardModifier {
|
||||||
namespace internal
|
namespace internal
|
||||||
{
|
{
|
||||||
@ -203,6 +206,22 @@ struct DragEvent : public MouseEvent
|
|||||||
emscripten::val dataTransfer;
|
emscripten::val dataTransfer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct WheelEvent : public MouseEvent
|
||||||
|
{
|
||||||
|
static std::optional<WheelEvent> fromWeb(emscripten::val webEvent);
|
||||||
|
|
||||||
|
WheelEvent(EventType type, emscripten::val webEvent);
|
||||||
|
~WheelEvent();
|
||||||
|
WheelEvent(const WheelEvent &other);
|
||||||
|
WheelEvent(WheelEvent &&other);
|
||||||
|
WheelEvent &operator=(const WheelEvent &other);
|
||||||
|
WheelEvent &operator=(WheelEvent &&other);
|
||||||
|
|
||||||
|
DeltaMode deltaMode;
|
||||||
|
bool webkitDirectionInvertedFromDevice;
|
||||||
|
QPoint delta;
|
||||||
|
};
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
#endif // QWASMEVENT_H
|
#endif // QWASMEVENT_H
|
||||||
|
@ -89,6 +89,12 @@ QWasmWindow::QWasmWindow(QWindow *w, QWasmCompositor *compositor, QWasmBackingSt
|
|||||||
if (processDrop(*DragEvent::fromWeb(event)))
|
if (processDrop(*DragEvent::fromWeb(event)))
|
||||||
event.call<void>("preventDefault");
|
event.call<void>("preventDefault");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
m_wheelEventCallback = std::make_unique<qstdweb::EventCallback>(
|
||||||
|
m_qtWindow, "wheel", [this](emscripten::val event) {
|
||||||
|
if (processWheel(*WheelEvent::fromWeb(event)))
|
||||||
|
event.call<void>("preventDefault");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QWasmWindow::~QWasmWindow()
|
QWasmWindow::~QWasmWindow()
|
||||||
@ -447,6 +453,30 @@ bool QWasmWindow::processDrop(const DragEvent &event)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool QWasmWindow::processWheel(const WheelEvent &event)
|
||||||
|
{
|
||||||
|
// Web scroll deltas are inverted from Qt deltas - negate.
|
||||||
|
const int scrollFactor = -([&event]() {
|
||||||
|
switch (event.deltaMode) {
|
||||||
|
case DeltaMode::Pixel:
|
||||||
|
return 1;
|
||||||
|
case DeltaMode::Line:
|
||||||
|
return 12;
|
||||||
|
case DeltaMode::Page:
|
||||||
|
return 20;
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
const auto pointInScreen = platformScreen()->mapFromLocal(
|
||||||
|
dom::mapPoint(event.target, platformScreen()->element(), event.localPoint));
|
||||||
|
|
||||||
|
return QWindowSystemInterface::handleWheelEvent(
|
||||||
|
window(), QWasmIntegration::getTimestamp(), mapFromGlobal(pointInScreen), pointInScreen,
|
||||||
|
event.delta * scrollFactor, event.delta * scrollFactor, event.modifiers,
|
||||||
|
Qt::NoScrollPhase, Qt::MouseEventNotSynthesized,
|
||||||
|
event.webkitDirectionInvertedFromDevice);
|
||||||
|
}
|
||||||
|
|
||||||
QRect QWasmWindow::normalGeometry() const
|
QRect QWasmWindow::normalGeometry() const
|
||||||
{
|
{
|
||||||
return m_normalGeometry;
|
return m_normalGeometry;
|
||||||
|
@ -33,6 +33,7 @@ class EventCallback;
|
|||||||
class ClientArea;
|
class ClientArea;
|
||||||
struct DragEvent;
|
struct DragEvent;
|
||||||
struct PointerEvent;
|
struct PointerEvent;
|
||||||
|
struct WheelEvent;
|
||||||
|
|
||||||
class QWasmWindow final : public QPlatformWindow
|
class QWasmWindow final : public QPlatformWindow
|
||||||
{
|
{
|
||||||
@ -93,6 +94,7 @@ private:
|
|||||||
|
|
||||||
bool processPointer(const PointerEvent &event);
|
bool processPointer(const PointerEvent &event);
|
||||||
bool processDrop(const DragEvent &event);
|
bool processDrop(const DragEvent &event);
|
||||||
|
bool processWheel(const WheelEvent &event);
|
||||||
|
|
||||||
QWindow *m_window = nullptr;
|
QWindow *m_window = nullptr;
|
||||||
QWasmCompositor *m_compositor = nullptr;
|
QWasmCompositor *m_compositor = nullptr;
|
||||||
@ -116,6 +118,8 @@ private:
|
|||||||
|
|
||||||
std::unique_ptr<qstdweb::EventCallback> m_dropCallback;
|
std::unique_ptr<qstdweb::EventCallback> m_dropCallback;
|
||||||
|
|
||||||
|
std::unique_ptr<qstdweb::EventCallback> m_wheelEventCallback;
|
||||||
|
|
||||||
Qt::WindowStates m_state = Qt::WindowNoState;
|
Qt::WindowStates m_state = Qt::WindowNoState;
|
||||||
Qt::WindowStates m_previousWindowState = Qt::WindowNoState;
|
Qt::WindowStates m_previousWindowState = Qt::WindowNoState;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user