Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Android multitouch events support #527

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
86 changes: 76 additions & 10 deletions src/Magnum/Platform/AndroidApplication.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,25 +248,91 @@ std::int32_t AndroidApplication::inputEvent(android_app* state, AInputEvent* eve
AndroidApplication& app = *static_cast<Data*>(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;
}
}
Expand Down
62 changes: 55 additions & 7 deletions src/Magnum/Platform/AndroidApplication.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <android/input.h>

Expand Down Expand Up @@ -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<Vector2i> _previousMouseMovePosition{Corrade::InPlaceInit, {{-1,-1}}};

/* Has to be in an Optional because it gets explicitly destroyed before
the GL context */
Expand Down Expand Up @@ -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;
};

/**
Expand Down Expand Up @@ -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))};
}

/**
Expand All @@ -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)
Expand Down