From 20a55b16aabf9d16af9a439b74f1260c15619c40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 23 Jan 2019 20:55:32 +0100 Subject: [PATCH] Platform: implement Sdl2Application::anyEvent(), expose SDL_Event. --- doc/changelog.dox | 3 + src/Magnum/Platform/Sdl2Application.cpp | 30 +++-- src/Magnum/Platform/Sdl2Application.h | 114 +++++++++++++++--- .../Platform/Test/Sdl2ApplicationTest.cpp | 8 ++ 4 files changed, 131 insertions(+), 24 deletions(-) diff --git a/doc/changelog.dox b/doc/changelog.dox index d474208d2..1f333cf1a 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -91,6 +91,9 @@ See also: @ref Platform::GlfwApplication::exitEvent() events for responding to application window close and possibility to cancel it (for example to show an exit confirmation dialog) +- New @ref Platform::Sdl2Application::anyEvent() event together with + @ref Platform::Sdl2Application::InputEvent::event() "event()" accessors to + make it possible to access raw `SDL_Event` data @subsection changelog-latest-changes Changes and improvements diff --git a/src/Magnum/Platform/Sdl2Application.cpp b/src/Magnum/Platform/Sdl2Application.cpp index c6322f67a..46ade2d00 100644 --- a/src/Magnum/Platform/Sdl2Application.cpp +++ b/src/Magnum/Platform/Sdl2Application.cpp @@ -665,7 +665,7 @@ void Sdl2Application::mainLoopIteration() { https://github.com/kripken/emscripten/issues/1731 */ CORRADE_ASSERT_UNREACHABLE(); #else - ViewportEvent e{{event.window.data1, event.window.data2}, framebufferSize(), _dpiScaling}; + ViewportEvent e{event, {event.window.data1, event.window.data2}, framebufferSize(), _dpiScaling}; /** @todo handle also WM_DPICHANGED events when a window is moved between displays with different DPI */ viewportEvent(e); _flags |= Flag::Redraw; @@ -678,49 +678,49 @@ void Sdl2Application::mainLoopIteration() { case SDL_KEYDOWN: case SDL_KEYUP: { - KeyEvent e(static_cast(event.key.keysym.sym), fixedModifiers(event.key.keysym.mod), event.key.repeat != 0); + KeyEvent e{event, static_cast(event.key.keysym.sym), fixedModifiers(event.key.keysym.mod), event.key.repeat != 0}; event.type == SDL_KEYDOWN ? keyPressEvent(e) : keyReleaseEvent(e); } break; case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: { - MouseEvent e(static_cast(event.button.button), {event.button.x, event.button.y} + MouseEvent e{event, static_cast(event.button.button), {event.button.x, event.button.y} #ifndef CORRADE_TARGET_EMSCRIPTEN , event.button.clicks #endif - ); + }; event.type == SDL_MOUSEBUTTONDOWN ? mousePressEvent(e) : mouseReleaseEvent(e); } break; case SDL_MOUSEWHEEL: { - MouseScrollEvent e{{Float(event.wheel.x), Float(event.wheel.y)}}; + MouseScrollEvent e{event, {Float(event.wheel.x), Float(event.wheel.y)}}; mouseScrollEvent(e); } break; case SDL_MOUSEMOTION: { - MouseMoveEvent e({event.motion.x, event.motion.y}, {event.motion.xrel, event.motion.yrel}, static_cast(event.motion.state)); + MouseMoveEvent e{event, {event.motion.x, event.motion.y}, {event.motion.xrel, event.motion.yrel}, static_cast(event.motion.state)}; mouseMoveEvent(e); break; } case SDL_MULTIGESTURE: { - MultiGestureEvent e({event.mgesture.x, event.mgesture.y}, event.mgesture.dTheta, event.mgesture.dDist, event.mgesture.numFingers); + MultiGestureEvent e{event, {event.mgesture.x, event.mgesture.y}, event.mgesture.dTheta, event.mgesture.dDist, event.mgesture.numFingers}; multiGestureEvent(e); break; } case SDL_TEXTINPUT: { - TextInputEvent e{{event.text.text, std::strlen(event.text.text)}}; + TextInputEvent e{event, {event.text.text, std::strlen(event.text.text)}}; textInputEvent(e); } break; case SDL_TEXTEDITING: { - TextEditingEvent e{{event.edit.text, std::strlen(event.text.text)}, event.edit.start, event.edit.length}; + TextEditingEvent e{event, {event.edit.text, std::strlen(event.text.text)}, event.edit.start, event.edit.length}; textEditingEvent(e); } break; case SDL_QUIT: { - ExitEvent e; + ExitEvent e{event}; exitEvent(e); if(e.isAccepted()) { #ifndef CORRADE_TARGET_EMSCRIPTEN @@ -731,6 +731,10 @@ void Sdl2Application::mainLoopIteration() { return; } } break; + + /* Direct everything else to anyEvent(), so users can implement + event handling for things not present in the Application APIs */ + default: if(!(_flags & Flag::NoAnyEvent)) anyEvent(event); } } @@ -816,6 +820,12 @@ void Sdl2Application::tickEvent() { _flags |= Flag::NoTickEvent; } +void Sdl2Application::anyEvent(SDL_Event&) { + /* If this got called, the any event is not implemented by user and thus + we don't need to call it ever again */ + _flags |= Flag::NoAnyEvent; +} + void Sdl2Application::viewportEvent(ViewportEvent& event) { #ifdef MAGNUM_BUILD_DEPRECATED CORRADE_IGNORE_DEPRECATED_PUSH diff --git a/src/Magnum/Platform/Sdl2Application.h b/src/Magnum/Platform/Sdl2Application.h index 9991dbf4b..41c9bd611 100644 --- a/src/Magnum/Platform/Sdl2Application.h +++ b/src/Magnum/Platform/Sdl2Application.h @@ -57,6 +57,10 @@ #include /* For the WinMain entrypoint */ #endif +#ifndef DOXYGEN_GENERATING_OUTPUT +union SDL_Event; /* for anyEvent() */ +#endif + namespace Magnum { namespace Platform { namespace Implementation { @@ -949,6 +953,17 @@ class Sdl2Application { */ virtual void tickEvent(); + /** + * @brief Any event + * + * Called in case a SDL event is not handled by any other event + * functions above. + * @see @ref ViewportEvent::event(), @ref InputEvent::event(), + * @ref MultiGestureEvent::event(), @ref TextInputEvent::event(), + * @ref TextEditingEvent::event(), @ref ExitEvent::event() + */ + virtual void anyEvent(SDL_Event& event); + /*@}*/ private: @@ -956,12 +971,13 @@ class Sdl2Application { Redraw = 1 << 0, VSyncEnabled = 1 << 1, NoTickEvent = 1 << 2, + NoAnyEvent = 1 << 3, #ifndef CORRADE_TARGET_EMSCRIPTEN - Exit = 1 << 3 + Exit = 1 << 4 #endif #ifdef CORRADE_TARGET_EMSCRIPTEN - TextInputActive = 1 << 4, - Resizable = 1 << 5 + TextInputActive = 1 << 5, + Resizable = 1 << 6 #endif }; @@ -1667,11 +1683,20 @@ class Sdl2Application::ExitEvent { */ void setAccepted(bool accepted = true) { _accepted = accepted; } + /** + * @brief Underlying SDL event + * + * Of type `SDL_QUIT`. + * @see @ref Sdl2Application::anyEvent() + */ + const SDL_Event& event() const { return _event; } + private: friend Sdl2Application; - explicit ExitEvent(): _accepted(false) {} + explicit ExitEvent(const SDL_Event& event): _event(event), _accepted(false) {} + const SDL_Event& _event; bool _accepted; }; @@ -1725,11 +1750,33 @@ class Sdl2Application::ViewportEvent { */ Vector2 dpiScaling() const { return _dpiScaling; } + #ifndef CORRADE_TARGET_EMSCRIPTEN + /** + * @brief Underlying SDL event + * + * Of type `SDL_WINDOWEVENT`. + * @note Not available in @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten". + * @see @ref Sdl2Application::anyEvent() + */ + const SDL_Event& event() const { return _event; } + #endif + private: friend Sdl2Application; - explicit ViewportEvent(const Vector2i& windowSize, const Vector2i& framebufferSize, const Vector2& dpiScaling): _windowSize{windowSize}, _framebufferSize{framebufferSize}, _dpiScaling{dpiScaling} {} + explicit ViewportEvent( + #ifndef CORRADE_TARGET_EMSCRIPTEN + const SDL_Event& event, + #endif + const Vector2i& windowSize, const Vector2i& framebufferSize, const Vector2& dpiScaling): + #ifndef CORRADE_TARGET_EMSCRIPTEN + _event(event), + #endif + _windowSize{windowSize}, _framebufferSize{framebufferSize}, _dpiScaling{dpiScaling} {} + #ifndef CORRADE_TARGET_EMSCRIPTEN + const SDL_Event& _event; + #endif const Vector2i _windowSize; const Vector2i _framebufferSize; const Vector2 _dpiScaling; @@ -1823,14 +1870,26 @@ class Sdl2Application::InputEvent { */ void setAccepted(bool accepted = true) { _accepted = accepted; } + /** + * @brief Underlying SDL event + * + * Of type `SDL_KEYDOWN` / `SDL_KEYUP` for @ref KeyEvent, + * `SDL_MOUSEBUTTONUP` / `SDL_MOUSEBUTTONDOWN` for @ref MouseEvent, + * `SDL_MOUSEWHEEL` for @ref MouseScrollEvent and `SDL_MOUSEMOTION` for + * @ref MouseMoveEvent. + * @see @ref Sdl2Application::anyEvent() + */ + const SDL_Event& event() const { return _event; } + #ifndef DOXYGEN_GENERATING_OUTPUT protected: - explicit InputEvent(): _accepted(false) {} + explicit InputEvent(const SDL_Event& event): _event(event), _accepted(false) {} ~InputEvent() = default; #endif private: + const SDL_Event& _event; bool _accepted; }; @@ -2050,7 +2109,7 @@ class Sdl2Application::KeyEvent: public Sdl2Application::InputEvent { bool isRepeated() const { return _repeated; } private: - explicit KeyEvent(Key key, Modifiers modifiers, bool repeated): _key{key}, _modifiers{modifiers}, _repeated{repeated} {} + explicit KeyEvent(const SDL_Event& event, Key key, Modifiers modifiers, bool repeated): InputEvent{event}, _key{key}, _modifiers{modifiers}, _repeated{repeated} {} const Key _key; const Modifiers _modifiers; @@ -2107,11 +2166,11 @@ class Sdl2Application::MouseEvent: public Sdl2Application::InputEvent { Modifiers modifiers(); private: - explicit MouseEvent(Button button, const Vector2i& position + explicit MouseEvent(const SDL_Event& event, Button button, const Vector2i& position #ifndef CORRADE_TARGET_EMSCRIPTEN , Int clickCount #endif - ): _button{button}, _position{position}, + ): InputEvent{event}, _button{button}, _position{position}, #ifndef CORRADE_TARGET_EMSCRIPTEN _clickCount{clickCount}, #endif @@ -2180,7 +2239,7 @@ class Sdl2Application::MouseMoveEvent: public Sdl2Application::InputEvent { Modifiers modifiers(); private: - explicit MouseMoveEvent(const Vector2i& position, const Vector2i& relativePosition, Buttons buttons): _position{position}, _relativePosition{relativePosition}, _buttons{buttons}, _modifiersLoaded{false} {} + explicit MouseMoveEvent(const SDL_Event& event, const Vector2i& position, const Vector2i& relativePosition, Buttons buttons): InputEvent{event}, _position{position}, _relativePosition{relativePosition}, _buttons{buttons}, _modifiersLoaded{false} {} const Vector2i _position, _relativePosition; const Buttons _buttons; @@ -2215,7 +2274,7 @@ class Sdl2Application::MouseScrollEvent: public Sdl2Application::InputEvent { Modifiers modifiers(); private: - explicit MouseScrollEvent(const Vector2& offset): _offset{offset}, _positionLoaded{false}, _modifiersLoaded{false} {} + explicit MouseScrollEvent(const SDL_Event& event, const Vector2& offset): InputEvent{event}, _offset{offset}, _positionLoaded{false}, _modifiersLoaded{false} {} const Vector2 _offset; bool _positionLoaded; @@ -2283,9 +2342,18 @@ class Sdl2Application::MultiGestureEvent { */ Int fingerCount() const { return _fingerCount; } + /** + * @brief Underlying SDL event + * + * Of type `SDL_MULTIGESTURE`. + * @see @ref Sdl2Application::anyEvent() + */ + const SDL_Event& event() const { return _event; } + private: - explicit MultiGestureEvent(const Vector2& center, Float relativeRotation, Float relativeDistance, Int fingerCount): _center{center}, _relativeRotation{relativeRotation}, _relativeDistance{relativeDistance}, _fingerCount{fingerCount}, _accepted{false} {} + explicit MultiGestureEvent(const SDL_Event& event, const Vector2& center, Float relativeRotation, Float relativeDistance, Int fingerCount): _event(event), _center{center}, _relativeRotation{relativeRotation}, _relativeDistance{relativeDistance}, _fingerCount{fingerCount}, _accepted{false} {} + const SDL_Event& _event; const Vector2 _center; const Float _relativeRotation; const Float _relativeDistance; @@ -2330,9 +2398,18 @@ class Sdl2Application::TextInputEvent { /** @brief Input text in UTF-8 */ Containers::ArrayView text() const { return _text; } + /** + * @brief Underlying SDL event + * + * Of type `SDL_TEXTINPUT`. + * @see @ref Sdl2Application::anyEvent() + */ + const SDL_Event& event() const { return _event; } + private: - explicit TextInputEvent(Containers::ArrayView text): _text{text}, _accepted{false} {} + explicit TextInputEvent(const SDL_Event& event, Containers::ArrayView text): _event(event), _text{text}, _accepted{false} {} + const SDL_Event& _event; const Containers::ArrayView _text; bool _accepted; }; @@ -2380,9 +2457,18 @@ class Sdl2Application::TextEditingEvent { /** @brief Number of characters to edit from the start point */ Int length() const { return _length; } + /** + * @brief Underlying SDL event + * + * Of type `SDL_TEXTEDITING`. + * @see @ref Sdl2Application::anyEvent() + */ + const SDL_Event& event() const { return _event; } + private: - explicit TextEditingEvent(Containers::ArrayView text, Int start, Int length): _text{text}, _start{start}, _length{length}, _accepted{false} {} + explicit TextEditingEvent(const SDL_Event& event, Containers::ArrayView text, Int start, Int length): _event(event), _text{text}, _start{start}, _length{length}, _accepted{false} {} + const SDL_Event& _event; const Containers::ArrayView _text; const Int _start; const Int _length; diff --git a/src/Magnum/Platform/Test/Sdl2ApplicationTest.cpp b/src/Magnum/Platform/Test/Sdl2ApplicationTest.cpp index 74372d95d..414625c8b 100644 --- a/src/Magnum/Platform/Test/Sdl2ApplicationTest.cpp +++ b/src/Magnum/Platform/Test/Sdl2ApplicationTest.cpp @@ -25,6 +25,8 @@ #include "Magnum/Platform/Sdl2Application.h" +#include + namespace Magnum { namespace Platform { namespace Test { namespace { struct Sdl2ApplicationTest: Platform::Application { @@ -52,6 +54,12 @@ struct Sdl2ApplicationTest: Platform::Application { void keyPressEvent(KeyEvent& event) override { Debug{} << event.keyName(); } + + /* Should fire on currently not handled events, such as minimize/maximize. + Comment out to verify correct behavior with the override not present. */ + void anyEvent(SDL_Event& event) override { + Debug{} << "any event" << event.type; + } }; }}}}