Reviewed Android inputs and gestures system

Corrected Android processing for some inputs (BACK button, VOLUME
buttons)
Redesigned Gestures system (some work still required)
SetEnabledGestures() - Only support desired gestures (requires some
review)
This commit is contained in:
raysan5
2016-01-03 13:01:21 +01:00
parent f269fb46ea
commit d32feaa668
4 changed files with 297 additions and 306 deletions

View File

@@ -42,23 +42,12 @@
#include <time.h> // Used for clock functions
#endif
#if defined(PLATFORM_ANDROID)
#include <jni.h> // Java native interface
#include <android/sensor.h> // Android sensors functions
#include <android/window.h> // Defines AWINDOW_FLAG_FULLSCREEN and others
#endif
#if defined(PLATFORM_WEB)
#include <emscripten/emscripten.h>
#include <emscripten/html5.h>
#endif
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
#define FORCE_TO_SWIPE 20
#define TAP_TIMEOUT 300
#define MAX_TOUCH_POINTS 4
//#define MAX_TOUCH_POINTS 4
//----------------------------------------------------------------------------------
// Types and Structures Definition
@@ -69,20 +58,6 @@ typedef enum {
TYPE_DUAL_INPUT
} GestureType;
typedef enum {
UP,
DOWN,
MOVE
} ActionType;
typedef struct {
ActionType action;
int pointCount;
int pointerId[MAX_TOUCH_POINTS];
Vector2 position[MAX_TOUCH_POINTS];
} GestureEvent;
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
@@ -119,133 +94,24 @@ static float pinchDelta = 0; // Pinch delta displacement
static int previousGesture = GESTURE_NONE;
static int currentGesture = GESTURE_NONE;
static unsigned int enabledGestures = 0; // TODO: Currently not in use...
static Vector2 rawTouchPosition;
// Enabled gestures flags, all gestures enabled by default
static unsigned int enabledGestures = 0b0000011111111111;
//----------------------------------------------------------------------------------
// Module specific Functions Declaration
//----------------------------------------------------------------------------------
static void ProcessMotionEvent(GestureEvent event);
static void InitPinchGesture(Vector2 posA, Vector2 posB);
static float CalculateAngle(Vector2 initialPosition, Vector2 actualPosition, float magnitude);
static float VectorDistance(Vector2 v1, Vector2 v2);
static float VectorDotProduct(Vector2 v1, Vector2 v2);
static double GetCurrentTime();
#if defined(PLATFORM_WEB)
static EM_BOOL EmscriptenInputCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData);
#endif
#if defined(PLATFORM_ANDROID)
static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event);
#endif
//----------------------------------------------------------------------------------
// Module Functions Definition
//----------------------------------------------------------------------------------
// Get touch position (could require further processing depending on display size)
Vector2 GetRawTouchPosition(void)
{
return rawTouchPosition;
}
// Check if a gesture have been detected
bool IsGestureDetected(void)
{
if (currentGesture != GESTURE_NONE) return true;
else return false;
}
// Check gesture type
int GetGestureType(void)
{
return currentGesture;
}
void SetGesturesEnabled(unsigned int gestureFlags)
{
enabledGestures = gestureFlags;
}
// Get drag intensity (pixels per frame)
float GetGestureDragIntensity(void)
{
return intensity;
}
// Get drag angle
// NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise
float GetGestureDragAngle(void)
{
return angle;
}
// Get drag vector (between initial and final position)
Vector2 GetGestureDragVector(void)
{
return dragVector;
}
// Hold time measured in frames
int GetGestureHoldDuration(void)
{
return 0;
}
// Get magnitude between two pinch points
float GetGesturePinchDelta(void)
{
return pinchDelta;
}
// Get angle beween two pinch points
// NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise
float GetGesturePinchAngle(void)
{
return 0;
}
#if defined(PLATFORM_WEB)
// Init gestures system (web)
void InitGesturesSystem(void)
{
// Init gestures system web (emscripten)
// NOTE: Some code examples
//emscripten_set_touchstart_callback(0, NULL, 1, Emscripten_HandleTouch);
//emscripten_set_touchend_callback("#canvas", data, 0, Emscripten_HandleTouch);
emscripten_set_touchstart_callback("#canvas", NULL, 1, EmscriptenInputCallback);
emscripten_set_touchend_callback("#canvas", NULL, 1, EmscriptenInputCallback);
emscripten_set_touchmove_callback("#canvas", NULL, 1, EmscriptenInputCallback);
emscripten_set_touchcancel_callback("#canvas", NULL, 1, EmscriptenInputCallback);
}
#elif defined(PLATFORM_ANDROID)
// Init gestures system (android)
void InitGesturesSystem(struct android_app *app)
{
app->onInputEvent = AndroidInputCallback;
// TODO: Receive frameBuffer data: displayWidth/displayHeight, renderWidth/renderHeight, screenWidth/screenHeight
}
#endif
// Update gestures detected (must be called every frame)
void UpdateGestures(void)
{
// NOTE: Gestures are processed through system callbacks on touch events
if ((previousGesture == GESTURE_TAP) && (currentGesture == GESTURE_TAP)) currentGesture = GESTURE_HOLD;
else if (currentGesture != GESTURE_HOLD) currentGesture = GESTURE_NONE;
}
//----------------------------------------------------------------------------------
// Module specific Functions Definition
//----------------------------------------------------------------------------------
static void ProcessMotionEvent(GestureEvent event)
// Process gesture event and translate it into gestures
void ProcessGestureEvent(GestureEvent event)
{
// Resets
dragVector = (Vector2){ 0, 0 };
@@ -257,7 +123,7 @@ static void ProcessMotionEvent(GestureEvent event)
{
case TYPE_MOTIONLESS: // Detect TAP, DOUBLE_TAP and HOLD events
{
if (event.action == DOWN)
if (event.touchAction == TOUCH_DOWN)
{
if (event.pointCount > 1) InitPinchGesture(event.position[0], event.position[1]);
else
@@ -279,7 +145,7 @@ static void ProcessMotionEvent(GestureEvent event)
else currentGesture = GESTURE_TAP;
}
}
else if (event.action == UP)
else if (event.touchAction == TOUCH_UP)
{
currentGesture = GESTURE_NONE;
@@ -297,7 +163,7 @@ static void ProcessMotionEvent(GestureEvent event)
eventTime = GetCurrentTime();
}
// Begin dragging
else if (event.action == MOVE)
else if (event.touchAction == TOUCH_MOVE)
{
if (event.pointCount > 1) InitPinchGesture(event.position[0], event.position[1]);
else
@@ -316,7 +182,7 @@ static void ProcessMotionEvent(GestureEvent event)
case TYPE_DRAG: // Detect DRAG and SWIPE events
{
// end of the drag
if (event.action == UP)
if (event.touchAction == TOUCH_UP)
{
// Return Swipe if we have enough sensitivity
if (intensity > FORCE_TO_SWIPE)
@@ -334,14 +200,13 @@ static void ProcessMotionEvent(GestureEvent event)
gestureType = TYPE_MOTIONLESS;
}
// Update while we are dragging
else if (event.action == MOVE)
else if (event.touchAction == TOUCH_MOVE)
{
if (event.pointCount > 1) InitPinchGesture(event.position[0], event.position[1]);
else
{
lastDragPosition = endDragPosition;
endDragPosition = rawTouchPosition;
endDragPosition = event.position[0];
//endDragPosition.x = AMotionEvent_getX(event, 0);
//endDragPosition.y = AMotionEvent_getY(event, 0);
@@ -359,7 +224,7 @@ static void ProcessMotionEvent(GestureEvent event)
} break;
case TYPE_DUAL_INPUT:
{
if (event.action == UP)
if (event.touchAction == TOUCH_UP)
{
if (event.pointCount == 1)
{
@@ -368,7 +233,7 @@ static void ProcessMotionEvent(GestureEvent event)
}
gestureType = TYPE_MOTIONLESS;
}
else if (event.action == MOVE)
else if (event.touchAction == TOUCH_MOVE)
{
// Adapt the ending position of the inputs
firstEndPinchPosition = event.position[0];
@@ -410,9 +275,78 @@ static void ProcessMotionEvent(GestureEvent event)
}
} break;
}
//--------------------------------------------------------------------
}
// Check if a gesture have been detected
bool IsGestureDetected(void)
{
if (currentGesture != GESTURE_NONE) return true;
else return false;
}
// Check gesture type
int GetGestureType(void)
{
// Get current gesture only if enabled
return (enabledGestures & currentGesture);
}
void SetGesturesEnabled(unsigned int gestureFlags)
{
enabledGestures = enabledGestures | gestureFlags;
}
// Get drag intensity (pixels per frame)
float GetGestureDragIntensity(void)
{
return intensity;
}
// Get drag angle
// NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise
float GetGestureDragAngle(void)
{
return angle;
}
// Get drag vector (between initial and final position)
Vector2 GetGestureDragVector(void)
{
return dragVector;
}
// Hold time measured in frames
int GetGestureHoldDuration(void)
{
return 0;
}
// Get magnitude between two pinch points
float GetGesturePinchDelta(void)
{
return pinchDelta;
}
// Get angle beween two pinch points
// NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise
float GetGesturePinchAngle(void)
{
return 0;
}
// Update gestures detected (must be called every frame)
void UpdateGestures(void)
{
// NOTE: Gestures are processed through system callbacks on touch events
if ((previousGesture == GESTURE_TAP) && (currentGesture == GESTURE_TAP)) currentGesture = GESTURE_HOLD;
else if (currentGesture != GESTURE_HOLD) currentGesture = GESTURE_NONE;
}
//----------------------------------------------------------------------------------
// Module specific Functions Definition
//----------------------------------------------------------------------------------
static float CalculateAngle(Vector2 initialPosition, Vector2 finalPosition, float magnitude)
{
float angle;
@@ -520,103 +454,3 @@ static double GetCurrentTime()
return time;
}
#if defined(PLATFORM_ANDROID)
// Android: Get input events
static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
{
int type = AInputEvent_getType(event);
if (type == AINPUT_EVENT_TYPE_MOTION)
{
rawTouchPosition.x = AMotionEvent_getX(event, 0);
rawTouchPosition.y = AMotionEvent_getY(event, 0);
}
else if (type == AINPUT_EVENT_TYPE_KEY)
{
int32_t keycode = AKeyEvent_getKeyCode(event);
int32_t AKeyEvent_getMetaState(event);
// If we are in active mode, we eat the back button and move into pause mode.
// If we are already in pause mode, we allow the back button to be handled by the OS, which means we'll be shut down.
if ((keycode == AKEYCODE_BACK)) // && mActiveMode)
{
//setActiveMode(false);
//return 1;
}
}
int32_t action = AMotionEvent_getAction(event);
unsigned int flags = action & AMOTION_EVENT_ACTION_MASK;
GestureEvent gestureEvent;
// Action
if (flags == AMOTION_EVENT_ACTION_DOWN) gestureEvent.action = DOWN;
else if (flags == AMOTION_EVENT_ACTION_UP) gestureEvent.action = UP;
else if (flags == AMOTION_EVENT_ACTION_MOVE) gestureEvent.action = MOVE;
// Points
gestureEvent.pointCount = AMotionEvent_getPointerCount(event);
// Position
gestureEvent.position[0] = (Vector2){ AMotionEvent_getX(event, 0), AMotionEvent_getY(event, 0) };
gestureEvent.position[1] = (Vector2){ AMotionEvent_getX(event, 1), AMotionEvent_getY(event, 1) };
ProcessMotionEvent(gestureEvent);
return 0; // return 1;
}
#endif
#if defined(PLATFORM_WEB)
// Web: Get input events
static EM_BOOL EmscriptenInputCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)
{
/*
for (int i = 0; i < touchEvent->numTouches; i++)
{
long x, y, id;
if (!touchEvent->touches[i].isChanged) continue;
id = touchEvent->touches[i].identifier;
x = touchEvent->touches[i].canvasX;
y = touchEvent->touches[i].canvasY;
}
printf("%s, numTouches: %d %s%s%s%s\n", emscripten_event_type_to_string(eventType), event->numTouches,
event->ctrlKey ? " CTRL" : "", event->shiftKey ? " SHIFT" : "", event->altKey ? " ALT" : "", event->metaKey ? " META" : "");
for(int i = 0; i < event->numTouches; ++i)
{
const EmscriptenTouchPoint *t = &event->touches[i];
printf(" %ld: screen: (%ld,%ld), client: (%ld,%ld), page: (%ld,%ld), isChanged: %d, onTarget: %d, canvas: (%ld, %ld)\n",
t->identifier, t->screenX, t->screenY, t->clientX, t->clientY, t->pageX, t->pageY, t->isChanged, t->onTarget, t->canvasX, t->canvasY);
}
*/
GestureEvent gestureEvent;
// Action
if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) gestureEvent.action = DOWN;
else if (eventType == EMSCRIPTEN_EVENT_TOUCHEND) gestureEvent.action = UP;
else if (eventType == EMSCRIPTEN_EVENT_TOUCHMOVE) gestureEvent.action = MOVE;
// Points
gestureEvent.pointCount = touchEvent->numTouches;
// Position
//gestureEvent.position[0] = (Vector2){ touchEvent->touches[0].canvasX, touchEvent->touches[0].canvasY };
//gestureEvent.position[1] = (Vector2){ touchEvent->touches[1].canvasX, touchEvent->touches[1].canvasY };
gestureEvent.position[0] = (Vector2){ touchEvent->touches[0].targetX, touchEvent->touches[0].targetY };
gestureEvent.position[1] = (Vector2){ touchEvent->touches[1].targetX, touchEvent->touches[1].targetY };
printf("EVENT DETECTED!\n");
rawTouchPosition = gestureEvent.position[0];
ProcessMotionEvent(gestureEvent);
return 1;
}
#endif