Browse Source

Platform: replace mouse events with pointer events in XApplication.

A special case here is that the event `state` doesn't yet include the
currently pressed button on press, and still includes the currently
release button on release. Which is the inverse of what the other
toolkits do, and contrary to the docs, so I patch it.

Furthermore, the buttons were originally reported on all input events,
but as the PointerEvent is now fired only when the first ever button is
pressed or the last remaining button is released, it doesn't make sense
to have a PointerEvent::pointers() getter, as it'd return always either
pointer() itself on pressed, or nothing at all on release. So the
pointers() getter is now moved directly to a KeyEvent, PointerMoveEvent
and MouseScrollEvent.
pull/651/head
Vladimír Vondruš 2 years ago
parent
commit
4b76918c36
  1. 5
      doc/changelog.dox
  2. 164
      src/Magnum/Platform/AbstractXApplication.cpp
  3. 303
      src/Magnum/Platform/AbstractXApplication.h
  4. 60
      src/Magnum/Platform/Test/AbstractXApplicationTest.cpp

5
doc/changelog.dox

@ -1396,8 +1396,9 @@ 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::GlfwApplication. The same change is done in @ref Platform::AbstractXApplication and
- @ref Platform::AbstractXApplication::MouseEvent::Button `WheelUp` and @ref Platform::GlfwApplication.
- @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
done for all other application classes in 2016 already. done for all other application classes in 2016 already.

164
src/Magnum/Platform/AbstractXApplication.cpp

@ -140,6 +140,34 @@ int AbstractXApplication::exec() {
return _exitCode; return _exitCode;
} }
namespace {
AbstractXApplication::Pointer buttonToPointer(const unsigned int button) {
switch(button) {
case 1 /*Button1*/:
return AbstractXApplication::Pointer::MouseLeft;
case 2 /*Button2*/:
return AbstractXApplication::Pointer::MouseMiddle;
case 3 /*Button3*/:
return AbstractXApplication::Pointer::MouseRight;
}
CORRADE_INTERNAL_ASSERT_UNREACHABLE();
}
AbstractXApplication::Pointers buttonsToPointers(const unsigned int state) {
AbstractXApplication::Pointers pointers;
if(state & Button1Mask)
pointers |= AbstractXApplication::Pointer::MouseLeft;
if(state & Button2Mask)
pointers |= AbstractXApplication::Pointer::MouseMiddle;
if(state & Button3Mask)
pointers |= AbstractXApplication::Pointer::MouseRight;
return pointers;
}
}
bool AbstractXApplication::mainLoopIteration() { bool AbstractXApplication::mainLoopIteration() {
/* If exit was requested directly in the constructor, exit immediately /* If exit was requested directly in the constructor, exit immediately
without calling anything else */ without calling anything else */
@ -184,15 +212,52 @@ bool AbstractXApplication::mainLoopIteration() {
if(event.type == ButtonPress) if(event.type == ButtonPress)
mouseScrollEvent(e); mouseScrollEvent(e);
} else { } else {
MouseEvent e(MouseEvent::Button(event.xbutton.button), event.xkey.state, {event.xbutton.x, event.xbutton.y}); const Pointer pointer = buttonToPointer(event.xbutton.button);
event.type == ButtonPress ? mousePressEvent(e) : mouseReleaseEvent(e); Pointers pointers = buttonsToPointers(event.xbutton.state);
/* Compared to other toolkits, the `pointers` don't include
the currently pressed button on press yet, and still
include the currently released button on release. Make
it consistent. */
if(event.type == ButtonPress) {
CORRADE_INTERNAL_ASSERT(!(pointers & pointer));
pointers |= pointer;
} else {
CORRADE_INTERNAL_ASSERT(pointers & pointer);
pointers &= ~pointer;
}
/* If an additional mouse button was pressed or some other
buttons are still left pressed after a release, call a
move event instead */
if((event.type == ButtonPress && (pointers & ~pointer)) ||
(event.type == ButtonRelease && pointers)) {
/* As we are patching up the set of currently pressed
pointers, the move event can't just figure that
out from the state */
PointerMoveEvent e{pointer, pointers,
{Float(event.xbutton.x), Float(event.xbutton.y)},
event.xbutton.state};
pointerMoveEvent(e);
} else {
PointerEvent e(pointer,
{Float(event.xbutton.x), Float(event.xbutton.y)},
event.xbutton.state);
event.type == ButtonPress ?
pointerPressEvent(e) : pointerReleaseEvent(e);
}
} }
} break; } break;
/* Mouse move events */ /* Mouse move events */
case MotionNotify: { case MotionNotify: {
MouseMoveEvent e(event.xmotion.state, {event.xmotion.x, event.xmotion.y}); /* Because for the move-from-press/release above we're patching
mouseMoveEvent(e); up the set of pressed pointers, we need to explicitly pass
it in here as well. No need to patch anything in this case
tho -- the set should be up-to-date. */
PointerMoveEvent e({}, buttonsToPointers(event.xmotion.state),
{Float(event.xmotion.x), Float(event.xmotion.y)},
event.xmotion.state);
pointerMoveEvent(e);
} break; } break;
} }
} }
@ -208,9 +273,92 @@ bool AbstractXApplication::mainLoopIteration() {
void AbstractXApplication::viewportEvent(ViewportEvent&) {} void AbstractXApplication::viewportEvent(ViewportEvent&) {}
void AbstractXApplication::keyPressEvent(KeyEvent&) {} void AbstractXApplication::keyPressEvent(KeyEvent&) {}
void AbstractXApplication::keyReleaseEvent(KeyEvent&) {} void AbstractXApplication::keyReleaseEvent(KeyEvent&) {}
#ifdef MAGNUM_BUILD_DEPRECATED
namespace {
CORRADE_IGNORE_DEPRECATED_PUSH
AbstractXApplication::MouseEvent::Button pointerToButton(const AbstractXApplication::Pointer pointer) {
switch(pointer) {
case AbstractXApplication::Pointer::MouseLeft:
return AbstractXApplication::MouseEvent::Button::Left;
case AbstractXApplication::Pointer::MouseMiddle:
return AbstractXApplication::MouseEvent::Button::Middle;
case AbstractXApplication::Pointer::MouseRight:
return AbstractXApplication::MouseEvent::Button::Right;
}
CORRADE_INTERNAL_ASSERT_UNREACHABLE();
}
CORRADE_IGNORE_DEPRECATED_POP
}
#endif
void AbstractXApplication::pointerPressEvent(PointerEvent& event) {
#ifdef MAGNUM_BUILD_DEPRECATED
CORRADE_IGNORE_DEPRECATED_PUSH
/* The positions are reported in integers in the first place, no need to
round anything */
MouseEvent mouseEvent{pointerToButton(event.pointer()), event._modifiers, Vector2i{event.position()}};
mousePressEvent(mouseEvent);
CORRADE_IGNORE_DEPRECATED_POP
#else
static_cast<void>(event);
#endif
}
#ifdef MAGNUM_BUILD_DEPRECATED
CORRADE_IGNORE_DEPRECATED_PUSH
void AbstractXApplication::mousePressEvent(MouseEvent&) {} void AbstractXApplication::mousePressEvent(MouseEvent&) {}
CORRADE_IGNORE_DEPRECATED_POP
#endif
void AbstractXApplication::pointerReleaseEvent(PointerEvent& event) {
#ifdef MAGNUM_BUILD_DEPRECATED
CORRADE_IGNORE_DEPRECATED_PUSH
/* The positions are reported in integers in the first place, no need to
round anything */
MouseEvent mouseEvent{pointerToButton(event.pointer()), event._modifiers, Vector2i{event.position()}};
mouseReleaseEvent(mouseEvent);
CORRADE_IGNORE_DEPRECATED_POP
#else
static_cast<void>(event);
#endif
}
#ifdef MAGNUM_BUILD_DEPRECATED
CORRADE_IGNORE_DEPRECATED_PUSH
void AbstractXApplication::mouseReleaseEvent(MouseEvent&) {} void AbstractXApplication::mouseReleaseEvent(MouseEvent&) {}
CORRADE_IGNORE_DEPRECATED_POP
#endif
void AbstractXApplication::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()) {
MouseEvent mouseEvent{pointerToButton(*event.pointer()), event._modifiers,
Vector2i{event.position()}};
event.pointers() >= *event.pointer() ?
mousePressEvent(mouseEvent) : mouseReleaseEvent(mouseEvent);
} else {
MouseMoveEvent mouseEvent{event._modifiers, Vector2i{event.position()}};
mouseMoveEvent(mouseEvent);
}
CORRADE_IGNORE_DEPRECATED_POP
#else
static_cast<void>(event);
#endif
}
#ifdef MAGNUM_BUILD_DEPRECATED
CORRADE_IGNORE_DEPRECATED_PUSH
void AbstractXApplication::mouseMoveEvent(MouseMoveEvent&) {} void AbstractXApplication::mouseMoveEvent(MouseMoveEvent&) {}
CORRADE_IGNORE_DEPRECATED_POP
#endif
void AbstractXApplication::mouseScrollEvent(MouseScrollEvent& event) { void AbstractXApplication::mouseScrollEvent(MouseScrollEvent& event) {
#ifdef MAGNUM_BUILD_DEPRECATED #ifdef MAGNUM_BUILD_DEPRECATED
@ -232,4 +380,12 @@ AbstractXApplication::Configuration::Configuration():
_size(800, 600) {} _size(800, 600) {}
AbstractXApplication::Configuration::~Configuration() = default; AbstractXApplication::Configuration::~Configuration() = default;
AbstractXApplication::Pointers AbstractXApplication::KeyEvent::pointers() const {
return buttonsToPointers(_modifiers);
}
AbstractXApplication::Pointers AbstractXApplication::MouseScrollEvent::pointers() const {
return buttonsToPointers(_modifiers);
}
}} }}

303
src/Magnum/Platform/AbstractXApplication.h

@ -104,10 +104,28 @@ class AbstractXApplication {
class ViewportEvent; class ViewportEvent;
class InputEvent; class InputEvent;
class KeyEvent; class KeyEvent;
class PointerEvent;
class PointerMoveEvent;
#ifdef MAGNUM_BUILD_DEPRECATED
class MouseEvent; class MouseEvent;
class MouseMoveEvent; class MouseMoveEvent;
#endif
class MouseScrollEvent; class MouseScrollEvent;
/* 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 KeyEvent::pointers(), @ref PointerMoveEvent::pointers(),
* @ref MouseScrollEvent::pointers()
*/
typedef Containers::EnumSet<Pointer> Pointers;
/** @brief Copying is not allowed */ /** @brief Copying is not allowed */
AbstractXApplication(const AbstractXApplication&) = delete; AbstractXApplication(const AbstractXApplication&) = delete;
@ -286,16 +304,92 @@ class AbstractXApplication {
* @} * @}
*/ */
/** @{ @name Mouse handling */ /** @{ @name Pointer handling */
/** @copydoc Sdl2Application::mousePressEvent() */ /**
virtual void mousePressEvent(MouseEvent& event); * @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
* @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
/** @copydoc Sdl2Application::mouseReleaseEvent() */ /**
virtual void mouseReleaseEvent(MouseEvent& event); * @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.
*
* On builds with @ref MAGNUM_BUILD_DEPRECATED enabled, default
* implementation delegates to @ref mouseReleaseEvent(). On builds with
* deprecated functionality disabled, default implementation does
* nothing.
*/
virtual void pointerReleaseEvent(PointerEvent& event);
/** @copydoc Sdl2Application::mouseMoveEvent() */ #ifdef MAGNUM_BUILD_DEPRECATED
virtual void mouseMoveEvent(MouseMoveEvent& 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.
*
* 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.
*/
virtual void pointerMoveEvent(PointerMoveEvent& event);
#ifdef MAGNUM_BUILD_DEPRECATED
/**
* @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.
*
* Default implementation does nothing.
*/
virtual CORRADE_DEPRECATED("use pointerMoveEvent() instead") void mouseMoveEvent(MouseMoveEvent& event);
#endif
/** /**
* @brief Mouse scroll event * @brief Mouse scroll event
@ -351,6 +445,31 @@ class AbstractXApplication {
Flags _flags; Flags _flags;
}; };
/**
@brief Pointer type
@m_since_latest
@see @ref Pointers, @ref KeyEvent::pointers(), @ref PointerEvent::pointer(),
@ref PointerMoveEvent::pointer(), @ref PointerMoveEvent::pointers(),
@ref MouseScrollEvent::pointers()
*/
enum class AbstractXApplication::Pointer: UnsignedByte {
/** Left mouse button. Corresponds to `Button1` / `Button1Mask`. */
MouseLeft = 1 << 0,
/**
* Middle mouse button. Corresponds to `Button2` / `Button2Mask`.
*/
MouseMiddle = 1 << 1,
/**
* Right mouse button. Corresponds to `Button3` / `Button3Mask`.
*/
MouseRight = 1 << 2
};
CORRADE_ENUMSET_OPERATORS(AbstractXApplication::Pointers)
/** /**
@brief OpenGL context configuration @brief OpenGL context configuration
@ -563,9 +682,10 @@ class AbstractXApplication::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 keyReleaseEvent(), @ref mousePressEvent(), @ref mouseReleaseEvent(), @ref MouseScrollEvent, @ref keyPressEvent(), @ref keyReleaseEvent(),
@ref mouseMoveEvent() @ref pointerPressEvent(), @ref pointerReleaseEvent(),
@ref pointerMoveEvent(), @ref mouseScrollEvent()
*/ */
class AbstractXApplication::InputEvent { class AbstractXApplication::InputEvent {
public: public:
@ -621,12 +741,12 @@ class AbstractXApplication::InputEvent {
*/ */
typedef Containers::EnumSet<Modifier> Modifiers; typedef Containers::EnumSet<Modifier> Modifiers;
#ifdef MAGNUM_BUILD_DEPRECATED
/** /**
* @brief Mouse button * @brief Mouse button
* * @m_deprecated_since_latest Use @ref Pointer instead.
* @see @ref Buttons, @ref buttons()
*/ */
enum class Button: unsigned int { enum class CORRADE_DEPRECATED_ENUM("use Pointer instead") Button: unsigned int {
Left = Button1Mask, /**< Left button */ Left = Button1Mask, /**< Left button */
Middle = Button2Mask, /**< Middle button */ Middle = Button2Mask, /**< Middle button */
Right = Button3Mask /**< Right button */ Right = Button3Mask /**< Right button */
@ -634,10 +754,12 @@ class AbstractXApplication::InputEvent {
/** /**
* @brief Set of mouse buttons * @brief Set of mouse buttons
* * @m_deprecated_since_latest Use @ref Pointers instead.
* @see @ref buttons()
*/ */
typedef Containers::EnumSet<Button> Buttons; CORRADE_IGNORE_DEPRECATED_PUSH
typedef CORRADE_DEPRECATED("use Pointers instead") Containers::EnumSet<Button> Buttons;
CORRADE_IGNORE_DEPRECATED_POP
#endif
/** @brief Copying is not allowed */ /** @brief Copying is not allowed */
InputEvent(const InputEvent&) = delete; InputEvent(const InputEvent&) = delete;
@ -662,10 +784,16 @@ class AbstractXApplication::InputEvent {
return Modifiers(_modifiers & (ShiftMask|ControlMask|Mod1Mask|Mod5Mask|LockMask|Mod2Mask)); return Modifiers(_modifiers & (ShiftMask|ControlMask|Mod1Mask|Mod5Mask|LockMask|Mod2Mask));
} }
/** @brief Mouse buttons */ #ifdef MAGNUM_BUILD_DEPRECATED
Buttons buttons() const { /**
* @brief Mouse buttons
* @m_deprecated_since_latest Use @ref KeyEvent::pointers() or
* @ref PointerMoveEvent::pointers() instead.
*/
CORRADE_DEPRECATED("use pointers() instead") Buttons buttons() const {
return Buttons(_modifiers & (Button1Mask|Button2Mask|Button3Mask)); return Buttons(_modifiers & (Button1Mask|Button2Mask|Button3Mask));
} }
#endif
#ifndef DOXYGEN_GENERATING_OUTPUT #ifndef DOXYGEN_GENERATING_OUTPUT
protected: protected:
@ -675,16 +803,19 @@ class AbstractXApplication::InputEvent {
#endif #endif
private: private:
#ifdef MAGNUM_BUILD_DEPRECATED friend AbstractXApplication;
friend AbstractXApplication; /* mouseScrollEvent() backwards compat */
#endif
unsigned int _modifiers; unsigned int _modifiers;
bool _accepted; bool _accepted;
}; };
CORRADE_ENUMSET_OPERATORS(AbstractXApplication::InputEvent::Modifiers) CORRADE_ENUMSET_OPERATORS(AbstractXApplication::InputEvent::Modifiers)
#ifdef MAGNUM_BUILD_DEPRECATED
CORRADE_IGNORE_DEPRECATED_PUSH
CORRADE_ENUMSET_OPERATORS(AbstractXApplication::InputEvent::Buttons) CORRADE_ENUMSET_OPERATORS(AbstractXApplication::InputEvent::Buttons)
CORRADE_IGNORE_DEPRECATED_POP
#endif
/** /**
@brief Key event @brief Key event
@ -1034,6 +1165,15 @@ class AbstractXApplication::KeyEvent: public AbstractXApplication::InputEvent {
/** @brief Position */ /** @brief Position */
Vector2i position() const { return _position; } Vector2i position() const { return _position; }
/**
* @brief Pointer types pressed in this event
* @m_since_latest
*
* Returns an empty set if no pointers are pressed in addition to the
* key.
*/
Pointers pointers() const;
private: private:
friend AbstractXApplication; friend AbstractXApplication;
@ -1043,13 +1183,57 @@ class AbstractXApplication::KeyEvent: public AbstractXApplication::InputEvent {
const Vector2i _position; const Vector2i _position;
}; };
/**
@brief Pointer event
@m_since_latest
@see @ref PointerMoveEvent, @ref pointerPressEvent(),
@ref pointerReleaseEvent()
*/
class AbstractXApplication::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 */
Pointer pointer() const { return _pointer; }
/**
* @brief Position
*
* For mouse input the position is always reported in whole pixels.
*/
Vector2 position() const { return _position; }
private:
friend AbstractXApplication;
explicit PointerEvent(Pointer pointer, const Vector2& position, unsigned int modifiers): InputEvent{modifiers}, _pointer(pointer), _position{position} {}
const Pointer _pointer;
const Vector2 _position;
};
#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 MouseScrollEvent, @ref mousePressEvent(), @see @ref MouseMoveEvent, @ref MouseScrollEvent, @ref mousePressEvent(),
@ref mouseReleaseEvent() @ref mouseReleaseEvent()
*/ */
class AbstractXApplication::MouseEvent: public AbstractXApplication::InputEvent { class CORRADE_DEPRECATED("use PointerEvent, pointerPressEvent() and pointerReleaseEvent() instead") AbstractXApplication::MouseEvent: public AbstractXApplication::InputEvent {
public: public:
/** /**
* @brief Mouse button * @brief Mouse button
@ -1092,13 +1276,75 @@ class AbstractXApplication::MouseEvent: public AbstractXApplication::InputEvent
const Button _button; const Button _button;
const Vector2i _position; const Vector2i _position;
}; };
#endif
/**
@brief Pointer move event
@m_since_latest
@see @ref PointerEvent, @ref pointerMoveEvent()
*/
class AbstractXApplication::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
*
* For mouse input the position is always reported in whole pixels.
*/
Vector2 position() const { return _position; }
private:
friend AbstractXApplication;
explicit PointerMoveEvent(Containers::Optional<Pointer> pointer, Pointers pointers, const Vector2& position, unsigned int modifiers): InputEvent{modifiers}, _pointer{pointer}, _pointers{pointers}, _position{position} {}
const Containers::Optional<Pointer> _pointer;
Pointers _pointers;
const Vector2 _position;
};
#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 MouseScrollEvent, @ref mouseMoveEvent() @see @ref MouseEvent, @ref MouseScrollEvent, @ref mouseMoveEvent()
*/ */
class AbstractXApplication::MouseMoveEvent: public AbstractXApplication::InputEvent { class CORRADE_DEPRECATED("use PointerMoveEvent and pointerMoveEvent() instead") AbstractXApplication::MouseMoveEvent: public AbstractXApplication::InputEvent {
public: public:
/** @brief Position */ /** @brief Position */
Vector2i position() const { return _position; } Vector2i position() const { return _position; }
@ -1110,12 +1356,13 @@ class AbstractXApplication::MouseMoveEvent: public AbstractXApplication::InputEv
const Vector2i _position; const Vector2i _position;
}; };
#endif
/** /**
@brief Mouse scroll event @brief Mouse scroll event
@m_since_latest @m_since_latest
@see @ref MouseEvent, @ref MouseMoveEvent, @ref mouseScrollEvent() @see @ref PointerEvent, @ref PointerMoveEvent, @ref mouseScrollEvent()
*/ */
class AbstractXApplication::MouseScrollEvent: public InputEvent { class AbstractXApplication::MouseScrollEvent: public InputEvent {
public: public:
@ -1129,6 +1376,14 @@ class AbstractXApplication::MouseScrollEvent: public InputEvent {
/** @brief Position */ /** @brief Position */
Vector2i position() const { return _position; } Vector2i position() const { return _position; }
/**
* @brief Pointer types pressed in this event
*
* Returns an empty set if no pointers are pressed in addition to the
* mouse wheel.
*/
Pointers pointers() const;
private: private:
friend AbstractXApplication; friend AbstractXApplication;

60
src/Magnum/Platform/Test/AbstractXApplicationTest.cpp

@ -57,7 +57,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) {
@ -70,6 +86,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 {
@ -84,7 +102,18 @@ 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) {
@ -100,13 +129,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;
@ -241,31 +272,44 @@ struct AbstractXApplicationTest: Platform::Application {
swapBuffers(); swapBuffers();
} }
/* 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();
}
#else
CORRADE_IGNORE_DEPRECATED_PUSH
void mousePressEvent(MouseEvent& event) override { void mousePressEvent(MouseEvent& event) override {
Debug{} << "mouse press:" << event.button() << event.buttons() << event.modifiers() << Debug::packed << event.position(); Debug{} << "mouse press:" << event.button() << event.buttons() << event.modifiers() << Debug::packed << event.position();
} }
void mouseReleaseEvent(MouseEvent& event) override { void mouseReleaseEvent(MouseEvent& event) override {
Debug{} << "mouse release:" << event.button() << event.buttons() << event.modifiers() << Debug::packed << event.position(); Debug{} << "mouse release:" << event.button() << event.buttons() << 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{} << "mouse move:" << event.buttons() << event.modifiers() << Debug::packed << event.position();
} }
CORRADE_IGNORE_DEPRECATED_POP
#endif
/* Comment out to test the deprecated scroll as press/release reporting */ /* Comment out to test the deprecated scroll as press/release reporting */
#if 1 #if 1
void mouseScrollEvent(MouseScrollEvent& event) override { void mouseScrollEvent(MouseScrollEvent& event) override {
Debug{} << "mouse scroll:" << event.buttons() << event.modifiers() << Debug::packed << event.offset() << Debug::packed << event.position(); Debug{} << "mouse scroll:" << event.pointers() << event.modifiers() << Debug::packed << event.offset() << Debug::packed << event.position();
} }
#endif #endif
void keyPressEvent(KeyEvent& event) override { void keyPressEvent(KeyEvent& event) override {
Debug{} << "key press:" << event.key() << int(event.key()) << event.modifiers() << event.buttons() << Debug::packed << event.position(); Debug{} << "key press:" << event.key() << int(event.key()) << event.modifiers() << event.pointers() << Debug::packed << event.position();
} }
void keyReleaseEvent(KeyEvent& event) override { void keyReleaseEvent(KeyEvent& event) override {
Debug{} << "key release:" << event.key() << int(event.key()) << event.modifiers() << event.buttons() << Debug::packed << event.position(); Debug{} << "key release:" << event.key() << int(event.key()) << event.modifiers() << event.pointers() << Debug::packed << event.position();
} }
}; };

Loading…
Cancel
Save