From ab898a4652685cdb7f63714ce08f846e78c57fd9 Mon Sep 17 00:00:00 2001 From: cklosters Date: Mon, 19 Dec 2022 17:01:35 +0100 Subject: [PATCH] add pointer input source (mouse or touch), which is used to track if mouse released events must be handling in new gui frame --- modules/napimgui/src/imguiservice.cpp | 20 ++++++--- modules/napimgui/src/imguiservice.h | 28 +++++++------ modules/napinput/src/inputevent.cpp | 7 ++-- modules/napinput/src/inputevent.h | 42 +++++++++++-------- modules/napinput/src/mouse.h | 4 +- modules/napsdlinput/src/sdleventconverter.cpp | 18 ++++++-- 6 files changed, 75 insertions(+), 44 deletions(-) diff --git a/modules/napimgui/src/imguiservice.cpp b/modules/napimgui/src/imguiservice.cpp index 007fac615b..3fc827b2c6 100644 --- a/modules/napimgui/src/imguiservice.cpp +++ b/modules/napimgui/src/imguiservice.cpp @@ -981,16 +981,19 @@ namespace nap { io.MouseDown[i] = context.mMousePressed[i]; - // If a mouse button was released this frame -> disable the press for next frame - // This ensures that buttons that are pressed and released within the same frame are always registered - if (context.mMouseRelease[i]) + // If the mouse button was released this frame -> disable the press for next frame. + // This ensures that buttons that are pressed and released within the same frame are always registered. + // If the button press is from a mouse (instead of touch), take into account current press state. + // This is required because the user can release the button outside of SDL window bounds, in which case no release event is generated. + if (context.mMouseRelease[i] || (context.mMousePressed[i] && + context.mMouseSource[i] == GUIContext::ESource::Mouse && (SDL_GetMouseState(nullptr, nullptr) & SDL_BUTTON(i+1)) == 0)) { context.mMousePressed[i] = false; context.mMouseRelease[i] = false; } } - // Tell the system which keys are pressed, we copy block of memory because iterating over + // Tell the system which keys are pressed, we copy block of memory because iterating over every element is wasteful memcpy(io.KeysDown, context.mKeyPressed.data(), sizeof(bool) * 512); for (const auto& key : context.mKeyRelease) { @@ -1105,7 +1108,9 @@ namespace nap const auto& press_event = static_cast(pointerEvent); if (press_event.mButton != EMouseButton::UNKNOWN) { - context.mMousePressed[static_cast(press_event.mButton)] = true; + int btn_id = static_cast(press_event.mButton); + context.mMousePressed[btn_id] = true; + context.mMouseSource[btn_id] = pointerEvent.mSource; } } @@ -1136,11 +1141,16 @@ namespace nap // Handle touch press if (touchEvent.get_type().is_derived_from(RTTI_OF(nap::TouchPressEvent))) + { context.mMousePressed[0] = true; + context.mMouseSource[0] = GUIContext::ESource::Touch; + } // Handle touch release if (touchEvent.get_type().is_derived_from(RTTI_OF(nap::TouchReleaseEvent))) + { context.mMouseRelease[0] = true; + } } diff --git a/modules/napimgui/src/imguiservice.h b/modules/napimgui/src/imguiservice.h index 7b7396d888..05a63f4a21 100644 --- a/modules/napimgui/src/imguiservice.h +++ b/modules/napimgui/src/imguiservice.h @@ -345,19 +345,21 @@ namespace nap GUIContext(ImGuiContext* context, ImGuiStyle* style); ~GUIContext(); - std::array mMousePressed = { false }; ///< If the mouse was pressed this frame - std::array mMouseRelease = { false }; ///< If the mouse was released this frame - std::array mModPressed = { false }; ///< If the ctrl (0), alt (1) or shift (2) modifier key is pressed - std::array mModRelease = { false }; ///< If the ctrl (0), alt (1) or shift (2) modifier key is released - std::array mKeyPressed = { false }; ///< The keys that were pressed this frame - std::vector mKeyRelease; ///< The keys that were released this frame - glm::ivec2 mMousePosition = { 0, 0 }; ///< Last known mouse position - float mMouseWheel = 0.0f; ///< Mouse wheel - float mScale = 1.0f; ///< GUI Scale - const Display* mDisplay = nullptr; ///< Current display - ImGuiContext* mContext = nullptr; ///< Associated ImGUI context - ImGuiContext* mPreviousContext = nullptr; ///< Context active before this one - ImGuiStyle* mStyle = nullptr; ///< Style of context + using ESource = PointerEvent::ESource; + std::array mMousePressed = { false }; ///< If the mouse was pressed this frame + std::array mMouseRelease = { false }; ///< If the mouse was released this frame + std::array mModPressed = { false }; ///< If the ctrl (0), alt (1) or shift (2) modifier key is pressed + std::array mModRelease = { false }; ///< If the ctrl (0), alt (1) or shift (2) modifier key is released + std::array mMouseSource = { ESource::Mouse}; ///< Pointer input source + std::array mKeyPressed = { false }; ///< The keys that were pressed this frame + std::vector mKeyRelease; ///< The keys that were released this frame + glm::ivec2 mMousePosition = { 0, 0 }; ///< Last known mouse position + float mMouseWheel = 0.0f; ///< Mouse wheel + float mScale = 1.0f; ///< GUI Scale + const Display* mDisplay = nullptr; ///< Current display + ImGuiContext* mContext = nullptr; ///< Associated ImGUI context + ImGuiContext* mPreviousContext = nullptr; ///< Context active before this one + ImGuiStyle* mStyle = nullptr; ///< Style of context // Activates current context void activate(); diff --git a/modules/napinput/src/inputevent.cpp b/modules/napinput/src/inputevent.cpp index 229ce0ad7f..8f1ea2864d 100644 --- a/modules/napinput/src/inputevent.cpp +++ b/modules/napinput/src/inputevent.cpp @@ -4,7 +4,6 @@ #include -// RTTI Definitions RTTI_DEFINE_BASE(nap::InputEvent) RTTI_DEFINE_BASE(nap::WindowInputEvent) RTTI_DEFINE_BASE(nap::ControllerEvent) @@ -23,15 +22,15 @@ RTTI_BEGIN_CLASS_NO_DEFAULT_CONSTRUCTOR(nap::KeyReleaseEvent) RTTI_END_CLASS RTTI_BEGIN_CLASS_NO_DEFAULT_CONSTRUCTOR(nap::PointerPressEvent) - RTTI_CONSTRUCTOR(int, int, nap::EMouseButton, int, int) + RTTI_CONSTRUCTOR(int, int, nap::EMouseButton, int, nap::PointerEvent::ESource) RTTI_END_CLASS RTTI_BEGIN_CLASS_NO_DEFAULT_CONSTRUCTOR(nap::PointerReleaseEvent) - RTTI_CONSTRUCTOR(int, int, nap::EMouseButton, int, int) + RTTI_CONSTRUCTOR(int, int, nap::EMouseButton, int, nap::PointerEvent::ESource) RTTI_END_CLASS RTTI_BEGIN_CLASS_NO_DEFAULT_CONSTRUCTOR(nap::PointerMoveEvent) - RTTI_CONSTRUCTOR(int, int, int, int, int, int) + RTTI_CONSTRUCTOR(int, int, int, int, int, nap::PointerEvent::ESource) RTTI_END_CLASS RTTI_BEGIN_CLASS_NO_DEFAULT_CONSTRUCTOR(nap::MouseWheelEvent) diff --git a/modules/napinput/src/inputevent.h b/modules/napinput/src/inputevent.h index 9969ffbcc0..d70e94e076 100644 --- a/modules/napinput/src/inputevent.h +++ b/modules/napinput/src/inputevent.h @@ -107,26 +107,34 @@ namespace nap ////////////////////////////////////////////////////////////////////////// - // Mouse Input Events, always associated with a with a window + // Pointer Input Events, always associated with a with a window ////////////////////////////////////////////////////////////////////////// /** * Contains all relevant information for pointer specific interaction * Can also be used to signal multi touch gestures (therefore the id) - */ + */ class NAPAPI PointerEvent : public WindowInputEvent { RTTI_ENABLE(WindowInputEvent) public: - PointerEvent(int inX, int inY, int window = 0, int inId = 0) : WindowInputEvent(window), - mX(inX), - mY(inY), - mId(inId) + + /** + * Possible pointer input sources + */ + enum class ESource : int8 + { + Mouse = 0, ///< Pointer event from mouse input + Touch = 1 ///< Pointer event from touch input + }; + + PointerEvent(int inX, int inY, int window = 0, ESource origin = ESource::Mouse) : + WindowInputEvent(window), mX(inX), mY(inY), mSource(origin) { } - int mX; ///< horizontal window pixel coordinate - int mY; ///< vertical window pixel coordinate - int mId; ///< device id + int mX; ///< horizontal window coordinate + int mY; ///< vertical window coordinate + ESource mSource = ESource::Mouse; ///< input device }; @@ -137,8 +145,8 @@ namespace nap { RTTI_ENABLE(PointerEvent) public: - PointerClickEvent(int inX, int inY, EMouseButton inButton, int window = 0, int inId = 0) : - PointerEvent(inX, inY, window, inId), + PointerClickEvent(int inX, int inY, EMouseButton inButton, int window = 0, ESource source = ESource::Mouse) : + PointerEvent(inX, inY, window, source), mButton(inButton) { } @@ -153,8 +161,8 @@ namespace nap { RTTI_ENABLE(PointerClickEvent) public: - PointerPressEvent(int inX, int inY, EMouseButton inButton, int window=0, int inId = 0) : - PointerClickEvent(inX, inY, inButton, window, inId) + PointerPressEvent(int inX, int inY, EMouseButton inButton, int window=0, ESource source = ESource::Mouse) : + PointerClickEvent(inX, inY, inButton, window, source) { } }; @@ -166,8 +174,8 @@ namespace nap { RTTI_ENABLE(PointerClickEvent) public: - PointerReleaseEvent (int inX, int inY, EMouseButton inButton, int window=0, int inId = 0) : - PointerClickEvent(inX, inY, inButton, window, inId) + PointerReleaseEvent (int inX, int inY, EMouseButton inButton, int window=0, ESource source = ESource::Mouse) : + PointerClickEvent(inX, inY, inButton, window, source) { } }; @@ -179,8 +187,8 @@ namespace nap { RTTI_ENABLE(PointerEvent) public: - PointerMoveEvent(int relX, int relY, int inAbsX, int inAbsY, int window=0, int inId = 0) : - PointerEvent(inAbsX, inAbsY, window, inId), + PointerMoveEvent(int relX, int relY, int inAbsX, int inAbsY, int window=0, ESource source = ESource::Mouse) : + PointerEvent(inAbsX, inAbsY, window, source), mRelX(relX), mRelY(relY) { } diff --git a/modules/napinput/src/mouse.h b/modules/napinput/src/mouse.h index 49a4a72b4f..280e3e037c 100644 --- a/modules/napinput/src/mouse.h +++ b/modules/napinput/src/mouse.h @@ -9,7 +9,7 @@ namespace nap { /** - * Enum describing a list of all possible mouse buttons + * All possible mouse buttons */ enum class EMouseButton : int { @@ -18,4 +18,4 @@ namespace nap MIDDLE = 1, RIGHT = 2 }; -} \ No newline at end of file +} diff --git a/modules/napsdlinput/src/sdleventconverter.cpp b/modules/napsdlinput/src/sdleventconverter.cpp index 97ac0b52ab..d397c47517 100644 --- a/modules/napsdlinput/src/sdleventconverter.cpp +++ b/modules/napsdlinput/src/sdleventconverter.cpp @@ -350,11 +350,21 @@ namespace nap return EMouseButton::MIDDLE; case SDL_BUTTON_RIGHT: return EMouseButton::RIGHT; + default: + return EMouseButton::UNKNOWN; } + } - return EMouseButton::UNKNOWN; + + /** + * Helper function to convert an SDL mouse source to nap pointer source + */ + static nap::PointerEvent::ESource toNapMouseSource(uint32_t source) + { + return source == SDL_TOUCH_MOUSEID ? PointerEvent::ESource::Touch : PointerEvent::ESource::Mouse; } + static nap::EControllerAxis toNapAxis(uint8_t axis) { switch (axis) @@ -420,6 +430,7 @@ namespace nap { // Get window int window_id = static_cast(sdlEvent.window.windowID); + SDL_Window* window = SDL_GetWindowFromID(window_id); if (window == nullptr) return nullptr; @@ -442,7 +453,8 @@ namespace nap SDL_GetWindowSize(window, &sx, &sy); int px = sdlEvent.motion.x; int py = sy - 1 - sdlEvent.motion.y; - mouse_event = eventType.create({ px, py, toNapMouseButton(sdlEvent.button.button), window_id, 0 }); + PointerEvent::ESource source = sdlEvent.motion.which == SDL_TOUCH_MOUSEID ? PointerEvent::ESource::Touch : PointerEvent::ESource::Mouse; + mouse_event = eventType.create({ px, py, toNapMouseButton(sdlEvent.button.button), window_id, toNapMouseSource(sdlEvent.motion.which)}); break; } case SDL_MOUSEMOTION: @@ -454,7 +466,7 @@ namespace nap int py = sy - 1 - static_cast(sdlEvent.motion.y); int rx = static_cast(sdlEvent.motion.xrel); int ry = static_cast(-sdlEvent.motion.yrel); - mouse_event = eventType.create({ rx, ry, px, py, window_id, 0 }); + mouse_event = eventType.create({ rx, ry, px, py, window_id, toNapMouseSource(sdlEvent.motion.which) }); break; } default: