Browse Source

Platform: replace mouse events with pointer events in EmscriptenApp.

Nothing special here, except for the extremely stupid difference where
the middle mouse button is 1 in one event and 1 << 2 in another.
pull/651/head
Vladimír Vondruš 2 years ago
parent
commit
e86c011e05
  1. 4
      doc/changelog.dox
  2. 174
      src/Magnum/Platform/EmscriptenApplication.cpp
  3. 281
      src/Magnum/Platform/EmscriptenApplication.h
  4. 53
      src/Magnum/Platform/Test/EmscriptenApplicationTest.cpp

4
doc/changelog.dox

@ -1396,8 +1396,8 @@ See also:
@relativeref{Platform::Sdl2Application,PointerEvent} and @relativeref{Platform::Sdl2Application,PointerEvent} and
@relativeref{Platform::Sdl2Application,PointerMoveEvent} APIs that provide @relativeref{Platform::Sdl2Application,PointerMoveEvent} APIs that provide
a better abstraction over general pointer input, not just a mouse alone. a better abstraction over general pointer input, not just a mouse alone.
The same change is done in @ref Platform::AbstractXApplication and The same change is done in @ref Platform::AbstractXApplication,
@ref Platform::GlfwApplication. @ref Platform::EmscriptenApplication and @ref Platform::GlfwApplication.
- @cpp Platform::AbstractXApplication::MouseEvent::Button::WheelUp @ce and - @cpp Platform::AbstractXApplication::MouseEvent::Button::WheelUp @ce and
`WheelDown` members are deprecated in favor of a dedicated `WheelDown` members are deprecated in favor of a dedicated
@ref Platform::AbstractXApplication::mouseScrollEvent(). Similar change was @ref Platform::AbstractXApplication::mouseScrollEvent(). Similar change was

174
src/Magnum/Platform/EmscriptenApplication.cpp

@ -501,6 +501,42 @@ void EmscriptenApplication::handleCanvasResize(const EmscriptenUiEvent* event) {
} }
} }
namespace {
EmscriptenApplication::Pointer buttonToPointer(const std::int32_t button) {
/* https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button */
switch(button) {
case 0:
return EmscriptenApplication::Pointer::MouseLeft;
case 1:
return EmscriptenApplication::Pointer::MouseMiddle;
case 2:
return EmscriptenApplication::Pointer::MouseRight;
}
/* W3C spec allows other, platform-specific buttons:
https://www.w3.org/TR/uievents/#dom-mouseevent-button
Return an invalid value in that case, don't treat this as an unreachable
scenario. */
return {};
}
EmscriptenApplication::Pointers buttonsToPointers(const std::uint32_t buttons) {
/* https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/buttons,
note that Middle and Right has order swapped compared to button, for
some unexplainable reason */
EmscriptenApplication::Pointers pointers;
if(buttons & (1 << 0))
pointers |= EmscriptenApplication::Pointer::MouseLeft;
if(buttons & (1 << 2))
pointers |= EmscriptenApplication::Pointer::MouseMiddle;
if(buttons & (1 << 1))
pointers |= EmscriptenApplication::Pointer::MouseRight;
return pointers;
}
}
void EmscriptenApplication::setupCallbacks(bool resizable) { void EmscriptenApplication::setupCallbacks(bool resizable) {
/* Since 1.38.17 all emscripten_set_*_callback() are macros. Play it safe /* Since 1.38.17 all emscripten_set_*_callback() are macros. Play it safe
and wrap all lambdas in () to avoid the preprocessor getting upset when and wrap all lambdas in () to avoid the preprocessor getting upset when
@ -524,32 +560,55 @@ void EmscriptenApplication::setupCallbacks(bool resizable) {
emscripten_set_mousedown_callback(_canvasTarget.data(), this, false, emscripten_set_mousedown_callback(_canvasTarget.data(), this, false,
([](int, const EmscriptenMouseEvent* event, void* userData) -> EM_BOOL { ([](int, const EmscriptenMouseEvent* event, void* userData) -> EM_BOOL {
MouseEvent e{*event}; auto& app = *static_cast<EmscriptenApplication*>(userData);
static_cast<EmscriptenApplication*>(userData)->mousePressEvent(e); const Pointer pointer = buttonToPointer(event->button);
return e.isAccepted(); const Pointers pointers = buttonsToPointers(event->buttons);
/* If an additional mouse button was pressed, call a move event
instead */
if(pointers & ~pointer) {
PointerMoveEvent e{*event, pointer, pointers, {}};
app.pointerMoveEvent(e);
return e.isAccepted();
} else {
PointerEvent e{*event, pointer};
app.pointerPressEvent(e);
return e.isAccepted();
}
})); }));
emscripten_set_mouseup_callback(_canvasTarget.data(), this, false, emscripten_set_mouseup_callback(_canvasTarget.data(), this, false,
([](int, const EmscriptenMouseEvent* event, void* userData) -> EM_BOOL { ([](int, const EmscriptenMouseEvent* event, void* userData) -> EM_BOOL {
MouseEvent e{*event}; auto& app = *static_cast<EmscriptenApplication*>(userData);
static_cast<EmscriptenApplication*>(userData)->mouseReleaseEvent(e); const Pointer pointer = buttonToPointer(event->button);
return e.isAccepted(); const Pointers pointers = buttonsToPointers(event->buttons);
/* If some buttons are still left pressed after a release, call a
move event instead */
if(pointers) {
PointerMoveEvent e{*event, pointer, pointers, {}};
app.pointerMoveEvent(e);
return e.isAccepted();
} else {
PointerEvent e{*event, pointer};
app.pointerReleaseEvent(e);
return e.isAccepted();
}
})); }));
emscripten_set_mousemove_callback(_canvasTarget.data(), this, false, emscripten_set_mousemove_callback(_canvasTarget.data(), this, false,
([](int, const EmscriptenMouseEvent* event, void* userData) -> EM_BOOL { ([](int, const EmscriptenMouseEvent* event, void* userData) -> EM_BOOL {
auto& app = *static_cast<EmscriptenApplication*>(userData); auto& app = *static_cast<EmscriptenApplication*>(userData);
/* Relies on the target being the canvas, which should be always /* Relies on the target being the canvas, which should be always
true for mouse events. The targetX and targetY variables used true for mouse events */
to be a `long` before 3.1.47, which is why the cast. */ Vector2 position{Float(event->targetX), Float(event->targetY)};
Vector2i position{Int(event->targetX), Int(event->targetY)}; PointerMoveEvent e{*event, {}, buttonsToPointers(event->buttons),
MouseMoveEvent e{*event,
/* Avoid bogus offset at first -- report 0 when the event is /* Avoid bogus offset at first -- report 0 when the event is
called for the first time. */ called for the first time. */
app._previousMouseMovePosition == Vector2i{-1} ? Vector2i{} : Math::isNan(app._previousMouseMovePosition).all() ? Vector2{} :
position - app._previousMouseMovePosition}; position - app._previousMouseMovePosition};
app._previousMouseMovePosition = position; app._previousMouseMovePosition = position;
static_cast<EmscriptenApplication*>(userData)->mouseMoveEvent(e); app.pointerMoveEvent(e);
return e.isAccepted(); return e.isAccepted();
})); }));
@ -729,9 +788,72 @@ void EmscriptenApplication::setTextInputRect(const Range2Di&) {
void EmscriptenApplication::viewportEvent(ViewportEvent&) {} void EmscriptenApplication::viewportEvent(ViewportEvent&) {}
void EmscriptenApplication::keyPressEvent(KeyEvent&) {} void EmscriptenApplication::keyPressEvent(KeyEvent&) {}
void EmscriptenApplication::keyReleaseEvent(KeyEvent&) {} void EmscriptenApplication::keyReleaseEvent(KeyEvent&) {}
void EmscriptenApplication::pointerPressEvent(PointerEvent& event) {
#ifdef MAGNUM_BUILD_DEPRECATED
CORRADE_IGNORE_DEPRECATED_PUSH
MouseEvent mouseEvent{event.event()};
mousePressEvent(mouseEvent);
CORRADE_IGNORE_DEPRECATED_POP
#else
static_cast<void>(event);
#endif
}
#ifdef MAGNUM_BUILD_DEPRECATED
CORRADE_IGNORE_DEPRECATED_PUSH
void EmscriptenApplication::mousePressEvent(MouseEvent&) {} void EmscriptenApplication::mousePressEvent(MouseEvent&) {}
CORRADE_IGNORE_DEPRECATED_POP
#endif
void EmscriptenApplication::pointerReleaseEvent(PointerEvent& event) {
#ifdef MAGNUM_BUILD_DEPRECATED
CORRADE_IGNORE_DEPRECATED_PUSH
MouseEvent mouseEvent{event.event()};
mouseReleaseEvent(mouseEvent);
CORRADE_IGNORE_DEPRECATED_POP
#else
static_cast<void>(event);
#endif
}
#ifdef MAGNUM_BUILD_DEPRECATED
CORRADE_IGNORE_DEPRECATED_PUSH
void EmscriptenApplication::mouseReleaseEvent(MouseEvent&) {} void EmscriptenApplication::mouseReleaseEvent(MouseEvent&) {}
CORRADE_IGNORE_DEPRECATED_POP
#endif
void EmscriptenApplication::pointerMoveEvent(PointerMoveEvent& event) {
#ifdef MAGNUM_BUILD_DEPRECATED
CORRADE_IGNORE_DEPRECATED_PUSH
/* If the event is due to some button being additionally pressed or one
button from a larger set being released, delegate to a press/release
event instead */
if(event.pointer()) {
/* Emscripten reports either a move or a press/release, so there
shouldn't be any move in this case */
CORRADE_INTERNAL_ASSERT(event.relativePosition() == Vector2{});
MouseEvent mouseEvent{event.event()};
event.pointers() >= *event.pointer() ?
mousePressEvent(mouseEvent) : mouseReleaseEvent(mouseEvent);
} else {
/* The positions are reported in integers in the first place, no need
to round anything */
MouseMoveEvent mouseEvent{event.event(), Vector2i{event.relativePosition()}};
mouseMoveEvent(mouseEvent);
}
CORRADE_IGNORE_DEPRECATED_POP
#else
static_cast<void>(event);
#endif
}
#ifdef MAGNUM_BUILD_DEPRECATED
CORRADE_IGNORE_DEPRECATED_PUSH
void EmscriptenApplication::mouseMoveEvent(MouseMoveEvent&) {} void EmscriptenApplication::mouseMoveEvent(MouseMoveEvent&) {}
CORRADE_IGNORE_DEPRECATED_POP
#endif
void EmscriptenApplication::mouseScrollEvent(MouseScrollEvent&) {} void EmscriptenApplication::mouseScrollEvent(MouseScrollEvent&) {}
void EmscriptenApplication::textInputEvent(TextInputEvent&) {} void EmscriptenApplication::textInputEvent(TextInputEvent&) {}
@ -787,6 +909,18 @@ template<class T> EmscriptenApplication::InputEvent::Modifiers eventModifiers(co
} }
Vector2 EmscriptenApplication::PointerEvent::position() const {
/* Relies on the target being the canvas, which should be always true for
mouse events */
return {Float(_event.targetX), Float(_event.targetY)};
}
EmscriptenApplication::PointerEvent::Modifiers EmscriptenApplication::PointerEvent::modifiers() const {
return eventModifiers(_event);
}
#ifdef MAGNUM_BUILD_DEPRECATED
CORRADE_IGNORE_DEPRECATED_PUSH
EmscriptenApplication::MouseEvent::Button EmscriptenApplication::MouseEvent::button() const { EmscriptenApplication::MouseEvent::Button EmscriptenApplication::MouseEvent::button() const {
return Button(_event.button); return Button(_event.button);
} }
@ -801,10 +935,25 @@ Vector2i EmscriptenApplication::MouseEvent::position() const {
EmscriptenApplication::MouseEvent::Modifiers EmscriptenApplication::MouseEvent::modifiers() const { EmscriptenApplication::MouseEvent::Modifiers EmscriptenApplication::MouseEvent::modifiers() const {
return eventModifiers(_event); return eventModifiers(_event);
} }
CORRADE_IGNORE_DEPRECATED_POP
#endif
Vector2 EmscriptenApplication::PointerMoveEvent::position() const {
/* Relies on the target being the canvas, which should be always true for
mouse events */
return {Float(_event.targetX), Float(_event.targetY)};
}
EmscriptenApplication::PointerMoveEvent::Modifiers EmscriptenApplication::PointerMoveEvent::modifiers() const {
return eventModifiers(_event);
}
#ifdef MAGNUM_BUILD_DEPRECATED
CORRADE_IGNORE_DEPRECATED_PUSH
EmscriptenApplication::MouseMoveEvent::Buttons EmscriptenApplication::MouseMoveEvent::buttons() const { EmscriptenApplication::MouseMoveEvent::Buttons EmscriptenApplication::MouseMoveEvent::buttons() const {
return EmscriptenApplication::MouseMoveEvent::Button(_event.buttons); return EmscriptenApplication::MouseMoveEvent::Button(_event.buttons);
} }
CORRADE_IGNORE_DEPRECATED_POP
Vector2i EmscriptenApplication::MouseMoveEvent::position() const { Vector2i EmscriptenApplication::MouseMoveEvent::position() const {
/* Relies on the target being the canvas, which should be always true for /* Relies on the target being the canvas, which should be always true for
@ -816,6 +965,7 @@ Vector2i EmscriptenApplication::MouseMoveEvent::position() const {
EmscriptenApplication::MouseMoveEvent::Modifiers EmscriptenApplication::MouseMoveEvent::modifiers() const { EmscriptenApplication::MouseMoveEvent::Modifiers EmscriptenApplication::MouseMoveEvent::modifiers() const {
return eventModifiers(_event); return eventModifiers(_event);
} }
#endif
Vector2 EmscriptenApplication::MouseScrollEvent::offset() const { Vector2 EmscriptenApplication::MouseScrollEvent::offset() const {
/* From emscripten's Browser.getMouseWheelDelta() function in /* From emscripten's Browser.getMouseWheelDelta() function in

281
src/Magnum/Platform/EmscriptenApplication.h

@ -296,12 +296,29 @@ class EmscriptenApplication {
class GLConfiguration; class GLConfiguration;
class ViewportEvent; class ViewportEvent;
class InputEvent; class InputEvent;
class PointerEvent;
class PointerMoveEvent;
#ifdef MAGNUM_BUILD_DEPRECATED
class MouseEvent; class MouseEvent;
class MouseMoveEvent; class MouseMoveEvent;
#endif
class MouseScrollEvent; class MouseScrollEvent;
class KeyEvent; class KeyEvent;
class TextInputEvent; class TextInputEvent;
/* The damn thing cannot handle forward enum declarations */
#ifndef DOXYGEN_GENERATING_OUTPUT
enum class Pointer: UnsignedByte;
#endif
/**
* @brief Set of pointer types
* @m_since_latest
*
* @see @ref PointerMoveEvent::pointers()
*/
typedef Containers::EnumSet<Pointer> Pointers;
#ifdef MAGNUM_TARGET_GL #ifdef MAGNUM_TARGET_GL
/** /**
* @brief Construct with a WebGL context * @brief Construct with a WebGL context
@ -600,7 +617,7 @@ class EmscriptenApplication {
* @} * @}
*/ */
/** @{ @name Mouse handling */ /** @{ @name Pointer handling */
public: public:
/** /**
@ -807,28 +824,90 @@ class EmscriptenApplication {
Cursor cursor(); Cursor cursor();
private: private:
/**
* @brief Pointer press event
* @m_since_latest
*
* Called when a mouse is pressed. Note that if at least one mouse
* button is already pressed and another button gets pressed in
* addition, @ref pointerMoveEvent() with the new combination is
* called, not this function.
*
* On builds with @ref MAGNUM_BUILD_DEPRECATED enabled, default
* implementation delegates to @ref mousePressEvent(). On builds with
* deprecated functionality disabled, default implementation does
* nothing.
*/
virtual void pointerPressEvent(PointerEvent& event);
#ifdef MAGNUM_BUILD_DEPRECATED
/** /**
* @brief Mouse press event * @brief Mouse press event
* @m_deprecated_since_latest Use @ref pointerPressEvent() instead,
* which is a better abstraction for covering both mouse and touch
* / pen input.
*
* Default implementation does nothing.
*/
virtual CORRADE_DEPRECATED("use pointerPressEvent() instead") void mousePressEvent(MouseEvent& event);
#endif
/**
* @brief Pointer release event
* @m_since_latest
*
* Called when a mouse is released. Note that if multiple mouse buttons
* are pressed and one of these is released, @ref pointerMoveEvent()
* with the new combination is called, not this function.
* *
* Called when mouse button is pressed. Default implementation does * On builds with @ref MAGNUM_BUILD_DEPRECATED enabled, default
* implementation delegates to @ref mouseReleaseEvent(). On builds with
* deprecated functionality disabled, default implementation does
* nothing. * nothing.
*/ */
virtual void mousePressEvent(MouseEvent& event); virtual void pointerReleaseEvent(PointerEvent& event);
#ifdef MAGNUM_BUILD_DEPRECATED
/** /**
* @brief Mouse release event * @brief Mouse release event
* @m_deprecated_since_latest Use @ref pointerReleaseEvent() instead,
* which is a better abstraction for covering both mouse and touch
* / pen input.
*
* Default implementation does nothing.
*/
virtual CORRADE_DEPRECATED("use pointerReleaseEvent() instead") void mouseReleaseEvent(MouseEvent& event);
#endif
/**
* @brief Pointer move event
* @m_since_latest
*
* Called when any of the currently pressed pointers is moved or
* changes its properties. Gets called also if the set of pressed mouse
* buttons changes.
* *
* Called when mouse button is released. Default implementation does * On builds with @ref MAGNUM_BUILD_DEPRECATED enabled, default
* implementation delegates to @ref mouseMoveEvent(), or if
* @ref PointerMoveEvent::pointer() is not
* @relativeref{Corrade,Containers::NullOpt}, to either
* @ref mousePressEvent() or @ref mouseReleaseEvent(). On builds with
* deprecated functionality disabled, default implementation does
* nothing. * nothing.
*/ */
virtual void mouseReleaseEvent(MouseEvent& event); virtual void pointerMoveEvent(PointerMoveEvent& event);
#ifdef MAGNUM_BUILD_DEPRECATED
/** /**
* @brief Mouse move event * @brief Mouse move event
* @m_deprecated_since_latest Use @ref pointerMoveEvent() instead,
* which is a better abstraction for covering both mouse and touch
* / pen input.
* *
* Called when mouse is moved. Default implementation does nothing. * Default implementation does nothing.
*/ */
virtual void mouseMoveEvent(MouseMoveEvent& event); virtual CORRADE_DEPRECATED("use pointerMoveEvent() instead") void mouseMoveEvent(MouseMoveEvent& event);
#endif
/** /**
* @brief Mouse scroll event * @brief Mouse scroll event
@ -912,7 +991,8 @@ class EmscriptenApplication {
void setupCallbacks(bool resizable); void setupCallbacks(bool resizable);
void setupAnimationFrame(bool ForceAnimationFrame); void setupAnimationFrame(bool ForceAnimationFrame);
Vector2i _lastKnownCanvasSize, _previousMouseMovePosition{-1}; Vector2i _lastKnownCanvasSize;
Vector2 _previousMouseMovePosition{Constants::nan()};
Vector2 _lastKnownDevicePixelRatio; Vector2 _lastKnownDevicePixelRatio;
Flags _flags; Flags _flags;
@ -937,6 +1017,26 @@ class EmscriptenApplication {
int (*_callback)(void*); int (*_callback)(void*);
}; };
/**
@brief Pointer type
@m_since_latest
@see @ref Pointers, @ref PointerEvent::pointer(),
@ref PointerMoveEvent::pointer(), @ref PointerMoveEvent::pointers()
*/
enum class EmscriptenApplication::Pointer: UnsignedByte {
/** Left mouse button */
MouseLeft = 1 << 0,
/** Middle mouse button */
MouseMiddle = 1 << 1,
/** Right mouse button */
MouseRight = 1 << 2
};
CORRADE_ENUMSET_OPERATORS(EmscriptenApplication::Pointers)
#ifdef MAGNUM_TARGET_GL #ifdef MAGNUM_TARGET_GL
/** /**
@brief WebGL context configuration @brief WebGL context configuration
@ -1466,8 +1566,10 @@ class EmscriptenApplication::ViewportEvent {
/** /**
@brief Base for input events @brief Base for input events
@see @ref KeyEvent, @ref MouseEvent, @ref MouseMoveEvent, @ref keyPressEvent(), @see @ref KeyEvent, @ref PointerEvent, @ref PointerMoveEvent,
@ref mousePressEvent(), @ref mouseReleaseEvent(), @ref mouseMoveEvent() @ref MouseScrollEvent, @ref keyPressEvent(), @ref keyReleaseEvent(),
@ref pointerPressEvent(), @ref pointerReleaseEvent(),
@ref pointerMoveEvent(), @ref mouseScrollEvent()
*/ */
class EmscriptenApplication::InputEvent { class EmscriptenApplication::InputEvent {
public: public:
@ -1475,7 +1577,9 @@ class EmscriptenApplication::InputEvent {
* @brief Modifier * @brief Modifier
* *
* @see @ref Modifiers, @ref KeyEvent::modifiers(), * @see @ref Modifiers, @ref KeyEvent::modifiers(),
* @ref MouseEvent::modifiers() * @ref PointerEvent::modifiers(),
* @ref PointerMoveEvent::modifiers(),
* @ref MouseScrollEvent::modifiers()
*/ */
enum class Modifier: Int { enum class Modifier: Int {
/** /**
@ -1510,8 +1614,9 @@ class EmscriptenApplication::InputEvent {
/** /**
* @brief Set of modifiers * @brief Set of modifiers
* *
* @see @ref KeyEvent::modifiers(), @ref MouseEvent::modifiers(), * @see @ref KeyEvent::modifiers(), @ref PointerEvent::modifiers(),
* @ref MouseMoveEvent::modifiers() * @ref PointerMoveEvent::modifiers(),
* @ref MouseScrollEvent::modifiers()
*/ */
typedef Containers::EnumSet<Modifier> Modifiers; typedef Containers::EnumSet<Modifier> Modifiers;
@ -1550,12 +1655,70 @@ class EmscriptenApplication::InputEvent {
CORRADE_ENUMSET_OPERATORS(EmscriptenApplication::InputEvent::Modifiers) CORRADE_ENUMSET_OPERATORS(EmscriptenApplication::InputEvent::Modifiers)
/**
@brief Pointer event
@m_since_latest
@see @ref PointerMoveEvent, @ref MouseScrollEvent, @ref pointerPressEvent(),
@ref pointerReleaseEvent()
*/
class EmscriptenApplication::PointerEvent: public InputEvent {
public:
/** @brief Copying is not allowed */
PointerEvent(const PointerEvent&) = delete;
/** @brief Moving is not allowed */
PointerEvent(PointerEvent&&) = delete;
/** @brief Copying is not allowed */
PointerEvent& operator=(const PointerEvent&) = delete;
/** @brief Moving is not allowed */
PointerEvent& operator=(PointerEvent&&) = delete;
/**
* @brief Pointer type that was pressed or released
*
* The browser is free to report any extra mouse buttons in addition to
* the ones listed in @ref Pointer. In that case a zero value is
* returned and you can get the actual button index through
* @ref event().
*/
Pointer pointer() const { return _pointer; }
/**
* @brief Position
*
* The position is always reported in whole pixels.
*/
Vector2 position() const;
/** @brief Modifiers */
Modifiers modifiers() const;
/** @brief Underlying Emscripten event */
const EmscriptenMouseEvent& event() const { return _event; }
private:
friend EmscriptenApplication;
explicit PointerEvent(const EmscriptenMouseEvent& event, Pointer pointer): _event(event), _pointer{pointer} {}
const EmscriptenMouseEvent& _event;
const Pointer _pointer;
};
#ifdef MAGNUM_BUILD_DEPRECATED
/** /**
@brief Mouse event @brief Mouse event
@m_deprecated_since_latest Use @ref PointerEvent, @ref pointerPressEvent() and
@ref pointerReleaseEvent() instead, which is a better abstraction for
covering both mouse and touch / pen input.
@see @ref MouseMoveEvent, @ref mousePressEvent(), @ref mouseReleaseEvent() @see @ref MouseMoveEvent, @ref MouseScrollEvent, @ref mousePressEvent(),
@ref mouseReleaseEvent()
*/ */
class EmscriptenApplication::MouseEvent: public EmscriptenApplication::InputEvent { class CORRADE_DEPRECATED("use PointerEvent, pointerPressEvent() and pointerReleaseEvent() instead") EmscriptenApplication::MouseEvent: public InputEvent {
public: public:
/** /**
* @brief Mouse button * @brief Mouse button
@ -1588,13 +1751,92 @@ class EmscriptenApplication::MouseEvent: public EmscriptenApplication::InputEven
const EmscriptenMouseEvent& _event; const EmscriptenMouseEvent& _event;
}; };
#endif
/**
@brief Pointer move event
@m_since_latest
@see @ref PointerEvent, @ref MouseScrollEvent, @ref pointerMoveEvent()
*/
class EmscriptenApplication::PointerMoveEvent: public InputEvent {
public:
/** @brief Copying is not allowed */
PointerMoveEvent(const PointerMoveEvent&) = delete;
/** @brief Moving is not allowed */
PointerMoveEvent(PointerMoveEvent&&) = delete;
/** @brief Copying is not allowed */
PointerMoveEvent& operator=(const PointerMoveEvent&) = delete;
/** @brief Moving is not allowed */
PointerMoveEvent& operator=(PointerMoveEvent&&) = delete;
/**
* @brief Pointer type that was added or removed from the set of pressed pointers
*
* Is non-empty only in case a mouse button was pressed in addition to
* an already pressed button, or if one mouse button from multiple
* pressed buttons was released. If non-empty and @ref pointers() don't
* contain given @ref Pointer value, the button was released, if they
* contain given value, the button was pressed.
*/
Containers::Optional<Pointer> pointer() const { return _pointer; }
/**
* @brief Pointer types pressed in this event
*
* Returns an empty set if no pointers are pressed, which happens for
* example when a mouse is just moved around.
* @see @ref pointer()
*/
Pointers pointers() const { return _pointers; }
/**
* @brief Position
*
* The position is always reported in whole pixels.
*/
Vector2 position() const;
/**
* @brief Position relative to the previous touch event
*
* The position is always reported in whole pixels. Unlike
* @ref Sdl2Application, HTML APIs don't provide relative position
* directly, so this is calculated explicitly as a delta from previous
* move event position.
*/
Vector2 relativePosition() const { return _relativePosition; }
/** @brief Modifiers */
Modifiers modifiers() const;
/** @brief Underlying Emscripten event */
const EmscriptenMouseEvent& event() const { return _event; }
private:
friend EmscriptenApplication;
explicit PointerMoveEvent(const EmscriptenMouseEvent& event, Containers::Optional<Pointer> pointer, Pointers pointers, const Vector2& relativePosition): _event(event), _pointer{pointer}, _pointers{pointers}, _relativePosition{relativePosition} {}
const EmscriptenMouseEvent& _event;
const Containers::Optional<Pointer> _pointer;
const Pointers _pointers;
const Vector2 _relativePosition;
};
#ifdef MAGNUM_BUILD_DEPRECATED
/** /**
@brief Mouse move event @brief Mouse move event
@m_deprecated_since_latest Use @ref PointerMoveEvent and
@ref pointerMoveEvent() instead, which is a better abstraction for covering
both mouse and touch / pen input.
@see @ref MouseEvent, @ref mouseMoveEvent() @see @ref MouseEvent, @ref MouseScrollEvent, @ref mouseMoveEvent()
*/ */
class EmscriptenApplication::MouseMoveEvent: public EmscriptenApplication::InputEvent { class CORRADE_DEPRECATED("use PointerMoveEvent and pointerMoveEvent() instead") EmscriptenApplication::MouseMoveEvent: public InputEvent {
public: public:
/** /**
* @brief Mouse button * @brief Mouse button
@ -1649,12 +1891,15 @@ class EmscriptenApplication::MouseMoveEvent: public EmscriptenApplication::Input
const Vector2i _relativePosition; const Vector2i _relativePosition;
}; };
CORRADE_IGNORE_DEPRECATED_PUSH
CORRADE_ENUMSET_OPERATORS(EmscriptenApplication::MouseMoveEvent::Buttons) CORRADE_ENUMSET_OPERATORS(EmscriptenApplication::MouseMoveEvent::Buttons)
CORRADE_IGNORE_DEPRECATED_POP
#endif
/** /**
@brief Mouse scroll event @brief Mouse scroll event
@see @ref MouseEvent, @ref MouseMoveEvent, @ref mouseScrollEvent() @see @ref PointerEvent, @ref PointerMoveEvent, @ref mouseScrollEvent()
*/ */
class EmscriptenApplication::MouseScrollEvent: public EmscriptenApplication::InputEvent { class EmscriptenApplication::MouseScrollEvent: public EmscriptenApplication::InputEvent {
public: public:

53
src/Magnum/Platform/Test/EmscriptenApplicationTest.cpp

@ -65,7 +65,23 @@ static Debug& operator<<(Debug& debug, Application::InputEvent::Modifier value)
return debug << "(" << Debug::nospace << UnsignedInt(value) << Debug::nospace << ")"; return debug << "(" << Debug::nospace << UnsignedInt(value) << Debug::nospace << ")";
} }
static Debug& operator<<(Debug& debug, Application::MouseMoveEvent::Button value) { static Debug& operator<<(Debug& debug, Application::Pointer value) {
debug << "Pointer" << Debug::nospace;
switch(value) {
#define _c(value) case Application::Pointer::value: return debug << "::" #value;
_c(MouseLeft)
_c(MouseMiddle)
_c(MouseRight)
#undef _c
}
return debug << "(" << Debug::nospace << UnsignedInt(value) << Debug::nospace << ")";
}
#ifdef MAGNUM_BUILD_DEPRECATED
CORRADE_IGNORE_DEPRECATED_PUSH
CORRADE_UNUSED static Debug& operator<<(Debug& debug, Application::MouseMoveEvent::Button value) {
debug << "Button" << Debug::nospace; debug << "Button" << Debug::nospace;
switch(value) { switch(value) {
@ -78,6 +94,8 @@ static Debug& operator<<(Debug& debug, Application::MouseMoveEvent::Button value
return debug << "(" << Debug::nospace << UnsignedInt(value) << Debug::nospace << ")"; return debug << "(" << Debug::nospace << UnsignedInt(value) << Debug::nospace << ")";
} }
CORRADE_IGNORE_DEPRECATED_POP
#endif
namespace Test { namespace { namespace Test { namespace {
@ -90,7 +108,17 @@ Debug& operator<<(Debug& debug, Application::InputEvent::Modifiers value) {
}); });
} }
Debug& operator<<(Debug& debug, Application::MouseEvent::Button value) { Debug& operator<<(Debug& debug, Application::Pointers value) {
return Containers::enumSetDebugOutput(debug, value, "Pointers{}", {
Application::Pointer::MouseLeft,
Application::Pointer::MouseMiddle,
Application::Pointer::MouseRight,
});
}
#ifdef MAGNUM_BUILD_DEPRECATED
CORRADE_IGNORE_DEPRECATED_PUSH
CORRADE_UNUSED Debug& operator<<(Debug& debug, Application::MouseEvent::Button value) {
debug << "Button" << Debug::nospace; debug << "Button" << Debug::nospace;
switch(value) { switch(value) {
@ -104,13 +132,15 @@ Debug& operator<<(Debug& debug, Application::MouseEvent::Button value) {
return debug << "(" << Debug::nospace << UnsignedInt(value) << Debug::nospace << ")"; return debug << "(" << Debug::nospace << UnsignedInt(value) << Debug::nospace << ")";
} }
Debug& operator<<(Debug& debug, Application::MouseMoveEvent::Buttons value) { CORRADE_UNUSED Debug& operator<<(Debug& debug, Application::MouseMoveEvent::Buttons value) {
return Containers::enumSetDebugOutput(debug, value, "Buttons{}", { return Containers::enumSetDebugOutput(debug, value, "Buttons{}", {
Application::MouseMoveEvent::Button::Left, Application::MouseMoveEvent::Button::Left,
Application::MouseMoveEvent::Button::Middle, Application::MouseMoveEvent::Button::Middle,
Application::MouseMoveEvent::Button::Right, Application::MouseMoveEvent::Button::Right,
}); });
} }
CORRADE_IGNORE_DEPRECATED_POP
#endif
Debug& operator<<(Debug& debug, const Application::KeyEvent::Key value) { Debug& operator<<(Debug& debug, const Application::KeyEvent::Key value) {
debug << "Key" << Debug::nospace; debug << "Key" << Debug::nospace;
@ -258,17 +288,30 @@ struct EmscriptenApplicationTest: Platform::Application {
} }
#endif #endif
/* Set to 0 to test the deprecated mouse events instead */
#if 1
void pointerPressEvent(PointerEvent& event) override {
Debug{} << "pointer press:" << event.pointer() << event.modifiers() << Debug::packed << event.position();
}
void pointerReleaseEvent(PointerEvent& event) override {
Debug{} << "pointer release:" << event.pointer() << event.modifiers() << Debug::packed << event.position();
}
void pointerMoveEvent(PointerMoveEvent& event) override {
Debug{} << "pointer move:" << event.pointer() << event.pointers() << event.modifiers() << Debug::packed << event.position() << Debug::packed << event.relativePosition();
}
#else
CORRADE_IGNORE_DEPRECATED_PUSH
void mousePressEvent(MouseEvent& event) override { void mousePressEvent(MouseEvent& event) override {
Debug{} << "mouse press:" << event.button() << event.modifiers() << Debug::packed << event.position(); Debug{} << "mouse press:" << event.button() << event.modifiers() << Debug::packed << event.position();
} }
void mouseReleaseEvent(MouseEvent& event) override { void mouseReleaseEvent(MouseEvent& event) override {
Debug{} << "mouse release:" << event.button() << event.modifiers() << Debug::packed << event.position(); Debug{} << "mouse release:" << event.button() << event.modifiers() << Debug::packed << event.position();
} }
void mouseMoveEvent(MouseMoveEvent& event) override { void mouseMoveEvent(MouseMoveEvent& event) override {
Debug{} << "mouse move:" << event.buttons() << event.modifiers() << Debug::packed << event.position() << Debug::packed << event.relativePosition(); Debug{} << "mouse move:" << event.buttons() << event.modifiers() << Debug::packed << event.position() << Debug::packed << event.relativePosition();
} }
CORRADE_IGNORE_DEPRECATED_POP
#endif
void mouseScrollEvent(MouseScrollEvent& event) override { void mouseScrollEvent(MouseScrollEvent& event) override {
Debug{} << "mouse scroll:" << event.modifiers() << Debug::packed << event.offset() << Debug::packed << event.position(); Debug{} << "mouse scroll:" << event.modifiers() << Debug::packed << event.offset() << Debug::packed << event.position();

Loading…
Cancel
Save