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();
|
||||
|
||||
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)
|
||||
: QObject(screen),
|
||||
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_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_touchend_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()
|
||||
{
|
||||
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;
|
||||
|
||||
const QByteArray screenElementSelector = screen()->eventTargetId().toUtf8();
|
||||
@ -109,9 +87,6 @@ void QWasmCompositor::initEventHandlers()
|
||||
emscripten_set_keyup_callback(screenElementSelector.constData(), (void *)this, UseCapture,
|
||||
&keyboard_cb);
|
||||
|
||||
emscripten_set_wheel_callback(screenElementSelector.constData(), (void *)this, UseCapture,
|
||||
&wheel_cb);
|
||||
|
||||
emscripten_set_touchstart_callback(screenElementSelector.constData(), (void *)this, UseCapture,
|
||||
&touchCallback);
|
||||
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));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
auto compositor = reinterpret_cast<QWasmCompositor*>(userData);
|
||||
@ -354,51 +323,6 @@ bool QWasmCompositor::processKeyboard(int eventType, const EmscriptenKeyboardEve
|
||||
: 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)
|
||||
{
|
||||
QList<QWindowSystemInterface::TouchPoint> touchPointList;
|
||||
|
@ -79,13 +79,10 @@ private:
|
||||
void deliverUpdateRequest(QWasmWindow *window, UpdateRequestDeliveryType updateType);
|
||||
|
||||
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);
|
||||
|
||||
bool processKeyboard(int eventType, const EmscriptenKeyboardEvent *keyEvent);
|
||||
bool processWheel(int eventType, const EmscriptenWheelEvent *wheelEvent);
|
||||
bool processTouch(int eventType, const EmscriptenTouchEvent *touchEvent);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -24,6 +24,7 @@ enum class EventType {
|
||||
PointerUp,
|
||||
PointerEnter,
|
||||
PointerLeave,
|
||||
Wheel,
|
||||
};
|
||||
|
||||
enum class PointerType {
|
||||
@ -36,6 +37,8 @@ enum class WindowArea {
|
||||
Client,
|
||||
};
|
||||
|
||||
enum class DeltaMode { Pixel, Line, Page };
|
||||
|
||||
namespace KeyboardModifier {
|
||||
namespace internal
|
||||
{
|
||||
@ -203,6 +206,22 @@ struct DragEvent : public MouseEvent
|
||||
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
|
||||
|
||||
#endif // QWASMEVENT_H
|
||||
|
@ -89,6 +89,12 @@ QWasmWindow::QWasmWindow(QWindow *w, QWasmCompositor *compositor, QWasmBackingSt
|
||||
if (processDrop(*DragEvent::fromWeb(event)))
|
||||
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()
|
||||
@ -447,6 +453,30 @@ bool QWasmWindow::processDrop(const DragEvent &event)
|
||||
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
|
||||
{
|
||||
return m_normalGeometry;
|
||||
|
@ -33,6 +33,7 @@ class EventCallback;
|
||||
class ClientArea;
|
||||
struct DragEvent;
|
||||
struct PointerEvent;
|
||||
struct WheelEvent;
|
||||
|
||||
class QWasmWindow final : public QPlatformWindow
|
||||
{
|
||||
@ -93,6 +94,7 @@ private:
|
||||
|
||||
bool processPointer(const PointerEvent &event);
|
||||
bool processDrop(const DragEvent &event);
|
||||
bool processWheel(const WheelEvent &event);
|
||||
|
||||
QWindow *m_window = nullptr;
|
||||
QWasmCompositor *m_compositor = nullptr;
|
||||
@ -116,6 +118,8 @@ private:
|
||||
|
||||
std::unique_ptr<qstdweb::EventCallback> m_dropCallback;
|
||||
|
||||
std::unique_ptr<qstdweb::EventCallback> m_wheelEventCallback;
|
||||
|
||||
Qt::WindowStates m_state = Qt::WindowNoState;
|
||||
Qt::WindowStates m_previousWindowState = Qt::WindowNoState;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user