diff --git a/src/Magnum/Platform/AndroidApplication.cpp b/src/Magnum/Platform/AndroidApplication.cpp index d70dccbd25..6134ee452f 100644 --- a/src/Magnum/Platform/AndroidApplication.cpp +++ b/src/Magnum/Platform/AndroidApplication.cpp @@ -248,25 +248,91 @@ std::int32_t AndroidApplication::inputEvent(android_app* state, AInputEvent* eve AndroidApplication& app = *static_cast(state->userData)->instance; if(AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) { const std::int32_t action = AMotionEvent_getAction(event) & AMOTION_EVENT_ACTION_MASK; + + // Extract the index of the pointer that left the touch sensor + // ! Don't mix up AMotionEvent_getAction(event) and 'action' ! + + // (i32 & 0xff00) >> 8 is less than 2^8 (or 256), so size_t is too much, + // but AMotionEvent_getPointerId() uses size_t as an argument + const std::size_t pointerIndex = (AMotionEvent_getAction(event) & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) + >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; + + // always >= 1 + const std::size_t pointerCount = AMotionEvent_getPointerCount(event); + + // Get the persistent id from the index + // (for what if we have a pointerIndex? + // They are a bit different. + // Pointer id saves the order of touch events, + // so if you would release fingers in various orders, + // the 'pointerId' will have the value of initial 'pointerIndex', which might be useful. + // Btw, somehow 'pointerId' does not tell you the last released touch initial index --- + // --- no, 'pointerId' actually tells it, but in AMOTION_EVENT_ACTION_UP|DOWN case) + std::int32_t pointerId = AMotionEvent_getPointerId(event, pointerIndex); + + switch(action) { case AMOTION_EVENT_ACTION_DOWN: case AMOTION_EVENT_ACTION_UP: { /* On a touch screen move events aren't reported when the finger is moving above (of course), so remember the position always */ - app._previousMouseMovePosition = {Int(AMotionEvent_getX(event, 0)), Int(AMotionEvent_getY(event, 0))}; - MouseEvent e(event); - action == AMOTION_EVENT_ACTION_DOWN ? app.mousePressEvent(e) : app.mouseReleaseEvent(e); + MouseEvent e(event, pointerIndex, pointerId, pointerCount); + + if(action == AMOTION_EVENT_ACTION_DOWN){ + app._previousMouseMovePosition[pointerId] = {Int(AMotionEvent_getX(event, pointerIndex)), + Int(AMotionEvent_getY(event, pointerIndex))}; + app.mousePressEvent(e); + } + else{ + app._previousMouseMovePosition[pointerId] = Vector2i{-1}; + app.mouseReleaseEvent(e); + } return e.isAccepted() ? 1 : 0; } - + + // does not depend on 'pointerIndex' (at least on my device its always 0 here) case AMOTION_EVENT_ACTION_MOVE: { - Vector2i position{Int(AMotionEvent_getX(event, 0)), Int(AMotionEvent_getY(event, 0))}; - MouseMoveEvent e{event, - app._previousMouseMovePosition == Vector2i{-1} ? Vector2i{} : - position - app._previousMouseMovePosition}; - app._previousMouseMovePosition = position; - app.mouseMoveEvent(e); + std::int32_t r = 0; + + for(size_t pointerIndex = 0; pointerIndex < pointerCount; ++pointerIndex){ + std::int32_t pointerId = AMotionEvent_getPointerId(event, pointerIndex); + + // position is received twice: inside MouseMoveEvent.position() and here, + // move 'position' or '_previousMouseMovePosition' to 'MouseMoveEvent' as a data? + Vector2i position{Int(AMotionEvent_getX(event, pointerIndex)), + Int(AMotionEvent_getY(event, pointerIndex))}; + MouseMoveEvent e{event, + app._previousMouseMovePosition[pointerId].x() == -1 ? Vector2i{} : + position - app._previousMouseMovePosition[pointerId], + pointerIndex, pointerId, pointerCount}; + app._previousMouseMovePosition[pointerId] = position; + app.mouseMoveEvent(e); + + // is it ok? + r = r || e.isAccepted(); + } + + return r; + } + + /* Look here: + https://android-developers.googleblog.com/2010/06/making-sense-of-multitouch.html + for ACTION_POINTER_UP|DOWN */ + + case AMOTION_EVENT_ACTION_POINTER_DOWN: + case AMOTION_EVENT_ACTION_POINTER_UP: { + if(pointerIndex >= arraySize(app._previousMouseMovePosition)) + Containers::arrayAppend(app._previousMouseMovePosition, + {Int(AMotionEvent_getX(event, pointerIndex)), + Int(AMotionEvent_getY(event, pointerIndex))}); + else + app._previousMouseMovePosition[pointerId] = {Int(AMotionEvent_getX(event, pointerIndex)), + Int(AMotionEvent_getY(event, pointerIndex))}; + + MouseEvent e(event, pointerIndex, pointerId, pointerCount); + action == AMOTION_EVENT_ACTION_POINTER_DOWN ? + app.mousePressEvent(e) : app.mouseReleaseEvent(e); return e.isAccepted() ? 1 : 0; } } diff --git a/src/Magnum/Platform/AndroidApplication.h b/src/Magnum/Platform/AndroidApplication.h index 4157b2ea4e..b663fb3cf1 100644 --- a/src/Magnum/Platform/AndroidApplication.h +++ b/src/Magnum/Platform/AndroidApplication.h @@ -41,6 +41,10 @@ #include "Magnum/Platform/Platform.h" #include "Magnum/Platform/GLContext.h" +//Is it ok? +#include "Corrade/Containers/Array.h" +#include "Corrade/Containers/GrowableArray.h" + #if defined(CORRADE_TARGET_ANDROID) || defined(DOXYGEN_GENERATING_OUTPUT) #include @@ -434,7 +438,11 @@ class AndroidApplication { EGLDisplay _display; EGLSurface _surface; EGLContext _glContext; - Vector2i _previousMouseMovePosition{-1}; + /* Create array from given value like here: + https://doc.magnum.graphics/corrade/classCorrade_1_1Containers_1_1Array.html + The exact number of pointers is unknown, isn't it? + */ + Containers::Array _previousMouseMovePosition{Corrade::InPlaceInit, {{-1,-1}}}; /* Has to be in an Optional because it gets explicitly destroyed before the GL context */ @@ -802,12 +810,32 @@ class AndroidApplication::MouseEvent: public InputEvent { /** @brief Position */ Vector2i position() { - return {Int(AMotionEvent_getX(_event, 0)), - Int(AMotionEvent_getY(_event, 0))}; + return {Int(AMotionEvent_getX(_event, _pointerIndex)), + Int(AMotionEvent_getY(_event, _pointerIndex))}; } + /** @brief Pointer Index + * note: generally Index != Id + */ + std::size_t pointerIndex() const { return _pointerIndex; } + + /** @brief Pointer Id + * note: generally Index != Id + */ + std::size_t pointerId() const { return _pointerId; } + + /** @brief Number of pointers */ + std::size_t pointerCount() const { return _pointerCount; } + private: - explicit MouseEvent(AInputEvent* event): InputEvent(event) {} + explicit MouseEvent(AInputEvent* event, + std::size_t pointerIndex = 0, std::int32_t pointerId = 0, std::size_t pointerCount = 1): + InputEvent(event), + _pointerIndex{pointerIndex}, _pointerId{pointerId}, _pointerCount{pointerCount} {} + + const std::size_t _pointerIndex; + const std::int32_t _pointerId; + const std::size_t _pointerCount; }; /** @@ -869,8 +897,8 @@ class AndroidApplication::MouseMoveEvent: public InputEvent { /** @brief Position */ Vector2i position() const { - return {Int(AMotionEvent_getX(_event, 0)), - Int(AMotionEvent_getY(_event, 0))}; + return {Int(AMotionEvent_getX(_event, _pointerIndex)), + Int(AMotionEvent_getY(_event, _pointerIndex))}; } /** @@ -893,10 +921,30 @@ class AndroidApplication::MouseMoveEvent: public InputEvent { #endif } + /** @brief Pointer Index + * note: generally Index != Id + */ + std::size_t pointerIndex() const { return _pointerIndex; } + + /** @brief Pointer Id + * note: generally Index != Id + */ + std::size_t pointerId() const { return _pointerId; } + + /** @brief Number of pointers */ + std::size_t pointerCount() const { return _pointerCount; } + private: - explicit MouseMoveEvent(AInputEvent* event, Vector2i relativePosition): InputEvent{event}, _relativePosition{relativePosition} {} + explicit MouseMoveEvent(AInputEvent* event, Vector2i relativePosition, + std::size_t pointerIndex = 0, std::int32_t pointerId = 0, std::size_t pointerCount = 1): + InputEvent{event}, _relativePosition{relativePosition}, + _pointerIndex{pointerIndex}, _pointerId{pointerId}, _pointerCount{pointerCount} {} const Vector2i _relativePosition; + + const std::size_t _pointerIndex; + const std::int32_t _pointerId; + const std::size_t _pointerCount; }; CORRADE_ENUMSET_OPERATORS(AndroidApplication::MouseMoveEvent::Buttons)