|
|
@ -46,7 +46,11 @@ |
|
|
|
// Defines and Macros |
|
|
|
//---------------------------------------------------------------------------------- |
|
|
|
#define FORCE_TO_SWIPE 20 |
|
|
|
#define TAP_TIMEOUT 300 |
|
|
|
#define FORCE_TO_DRAG 20 |
|
|
|
#define FORCE_TO_PINCH 5 |
|
|
|
#define TAP_TIMEOUT 300 // Time in milliseconds |
|
|
|
#define PINCH_TIMEOUT 300 // Time in milliseconds |
|
|
|
#define DOUBLETAP_RANGE 30 |
|
|
|
//#define MAX_TOUCH_POINTS 4 |
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------- |
|
|
@ -61,10 +65,6 @@ typedef enum { |
|
|
|
//---------------------------------------------------------------------------------- |
|
|
|
// Global Variables Definition |
|
|
|
//---------------------------------------------------------------------------------- |
|
|
|
static GestureType gestureType = TYPE_MOTIONLESS; |
|
|
|
static double eventTime = 0; |
|
|
|
//static int32_t touchId; // Not used... |
|
|
|
|
|
|
|
// Tap gesture variables |
|
|
|
static Vector2 initialTapPosition = { 0, 0 }; |
|
|
|
|
|
|
@ -78,6 +78,21 @@ static Vector2 endDragPosition = { 0, 0 }; |
|
|
|
static Vector2 lastDragPosition = { 0, 0 }; |
|
|
|
static Vector2 dragVector = { 0, 0 }; |
|
|
|
|
|
|
|
// Albert&Ian |
|
|
|
static Vector2 touchDownPosition = { 0, 0 }; |
|
|
|
static Vector2 touchDownPosition2 = { 0, 0 }; |
|
|
|
static Vector2 touchUpPosition = { 0, 0 }; |
|
|
|
static Vector2 moveDownPosition = { 0, 0 }; |
|
|
|
static Vector2 moveDownPosition2 = { 0, 0 }; |
|
|
|
|
|
|
|
static int numTap = 0; |
|
|
|
static int numHold = 0; |
|
|
|
static int numPinch = 0; |
|
|
|
static int pointCount = 0; |
|
|
|
static int touchId = -1; |
|
|
|
|
|
|
|
static double eventTime = 0; |
|
|
|
|
|
|
|
static float magnitude = 0; // Distance traveled dragging |
|
|
|
static float angle = 0; // Angle direction of the drag |
|
|
|
static float intensity = 0; // How fast we did the drag (pixels per frame) |
|
|
@ -95,7 +110,7 @@ static int previousGesture = GESTURE_NONE; |
|
|
|
static int currentGesture = GESTURE_NONE; |
|
|
|
|
|
|
|
// Enabled gestures flags, all gestures enabled by default |
|
|
|
static unsigned int enabledGestures = 0b0000011111111111; |
|
|
|
static unsigned int enabledGestures = 0b0000001111111111; |
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------- |
|
|
|
// Module specific Functions Declaration |
|
|
@ -105,6 +120,7 @@ static float CalculateAngle(Vector2 initialPosition, Vector2 actualPosition, flo |
|
|
|
static float VectorDistance(Vector2 v1, Vector2 v2); |
|
|
|
static float VectorDotProduct(Vector2 v1, Vector2 v2); |
|
|
|
static double GetCurrentTime(); |
|
|
|
static float Vector2Distance(); |
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------- |
|
|
|
// Module Functions Definition |
|
|
@ -119,173 +135,160 @@ void ProcessGestureEvent(GestureEvent event) |
|
|
|
|
|
|
|
previousGesture = currentGesture; |
|
|
|
|
|
|
|
switch (gestureType) |
|
|
|
{ |
|
|
|
case TYPE_MOTIONLESS: // Detect TAP, DOUBLE_TAP and HOLD events |
|
|
|
pointCount = event.pointCount; |
|
|
|
|
|
|
|
// Albert&Ian |
|
|
|
if (pointCount < 2) |
|
|
|
{ |
|
|
|
touchId = event.pointerId[0]; |
|
|
|
if (event.touchAction == TOUCH_DOWN) |
|
|
|
{ |
|
|
|
if (event.touchAction == TOUCH_DOWN) |
|
|
|
numTap++; // Tap counter |
|
|
|
|
|
|
|
// Detect GESTURE_DOUBLE_TAP |
|
|
|
if ((currentGesture == GESTURE_NONE) && (numTap >= 2) && ((GetCurrentTime() - eventTime) < TAP_TIMEOUT) && (GetMagnitude(touchDownPosition, event.position[0]) < DOUBLETAP_RANGE)) |
|
|
|
{ |
|
|
|
if (event.pointCount > 1) InitPinchGesture(event.position[0], event.position[1]); |
|
|
|
else |
|
|
|
{ |
|
|
|
// Set the press position |
|
|
|
initialTapPosition = event.position[0]; |
|
|
|
|
|
|
|
// If too much time have passed, we reset the double tap |
|
|
|
if (GetCurrentTime() - eventTime > TAP_TIMEOUT) untap = false; |
|
|
|
|
|
|
|
// If we are in time, we detect the double tap |
|
|
|
if (untap) doubleTapping = true; |
|
|
|
|
|
|
|
// Update our event time |
|
|
|
eventTime = GetCurrentTime(); |
|
|
|
|
|
|
|
// Set hold |
|
|
|
if (doubleTapping) currentGesture = GESTURE_DOUBLETAP; |
|
|
|
else currentGesture = GESTURE_TAP; |
|
|
|
} |
|
|
|
currentGesture = GESTURE_DOUBLETAP; |
|
|
|
numTap = 0; |
|
|
|
} |
|
|
|
else if (event.touchAction == TOUCH_UP) |
|
|
|
else // Detect GESTURE_TAP |
|
|
|
{ |
|
|
|
currentGesture = GESTURE_NONE; |
|
|
|
|
|
|
|
// Detect that we are tapping instead of holding |
|
|
|
if (GetCurrentTime() - eventTime < TAP_TIMEOUT) |
|
|
|
{ |
|
|
|
if (doubleTapping) untap = false; |
|
|
|
else untap = true; |
|
|
|
} |
|
|
|
|
|
|
|
// Tap finished |
|
|
|
doubleTapping = false; |
|
|
|
|
|
|
|
// Update our event time |
|
|
|
eventTime = GetCurrentTime(); |
|
|
|
numTap = 1; |
|
|
|
currentGesture = GESTURE_TAP; |
|
|
|
} |
|
|
|
// Begin dragging |
|
|
|
else if (event.touchAction == TOUCH_MOVE) |
|
|
|
|
|
|
|
touchDownPosition = event.position[0]; |
|
|
|
|
|
|
|
touchUpPosition = touchDownPosition; |
|
|
|
eventTime = GetCurrentTime(); |
|
|
|
} |
|
|
|
else if (event.touchAction == TOUCH_UP) |
|
|
|
{ |
|
|
|
if (currentGesture = GESTURE_DRAG) |
|
|
|
{ |
|
|
|
if (event.pointCount > 1) InitPinchGesture(event.position[0], event.position[1]); |
|
|
|
else |
|
|
|
{ |
|
|
|
// Set the drag starting position |
|
|
|
initialDragPosition = initialTapPosition; |
|
|
|
endDragPosition = initialDragPosition; |
|
|
|
|
|
|
|
// Initialize drag |
|
|
|
draggingTimeCounter = 0; |
|
|
|
gestureType = TYPE_DRAG; |
|
|
|
currentGesture = GESTURE_NONE; |
|
|
|
} |
|
|
|
touchUpPosition = event.position[0]; |
|
|
|
} |
|
|
|
} break; |
|
|
|
case TYPE_DRAG: // Detect DRAG and SWIPE events |
|
|
|
{ |
|
|
|
// end of the drag |
|
|
|
if (event.touchAction == TOUCH_UP) |
|
|
|
|
|
|
|
// Calculate for swipe |
|
|
|
magnitude = GetMagnitude(touchDownPosition, touchUpPosition); |
|
|
|
intensity = magnitude / (float)draggingTimeCounter; |
|
|
|
|
|
|
|
// Detect GESTURE_SWIPE |
|
|
|
if ((intensity > FORCE_TO_SWIPE) && (touchId == 0)) |
|
|
|
{ |
|
|
|
angle = CalculateAngle(touchDownPosition, touchUpPosition, magnitude); |
|
|
|
if ((angle < 30) || (angle > 330)) currentGesture = GESTURE_SWIPE_RIGHT; // Right |
|
|
|
else if ((angle > 30) && (angle < 120)) currentGesture = GESTURE_SWIPE_UP; // Up |
|
|
|
else if ((angle > 120) && (angle < 210)) currentGesture = GESTURE_SWIPE_LEFT; // Left |
|
|
|
else if ((angle > 210) && (angle < 300)) currentGesture = GESTURE_SWIPE_DOWN; // Down |
|
|
|
else currentGesture = GESTURE_NONE; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
// Return Swipe if we have enough sensitivity |
|
|
|
if (intensity > FORCE_TO_SWIPE) |
|
|
|
{ |
|
|
|
if (angle < 30 || angle > 330) currentGesture = GESTURE_SWIPE_RIGHT; // Right |
|
|
|
else if (angle > 60 && angle < 120) currentGesture = GESTURE_SWIPE_UP; // Up |
|
|
|
else if (angle > 150 && angle < 210) currentGesture = GESTURE_SWIPE_LEFT; // Left |
|
|
|
else if (angle > 240 && angle < 300) currentGesture = GESTURE_SWIPE_DOWN; // Down |
|
|
|
} |
|
|
|
|
|
|
|
magnitude = 0; |
|
|
|
angle = 0; |
|
|
|
intensity = 0; |
|
|
|
|
|
|
|
gestureType = TYPE_MOTIONLESS; |
|
|
|
currentGesture = GESTURE_NONE; |
|
|
|
} |
|
|
|
// Update while we are dragging |
|
|
|
else if (event.touchAction == TOUCH_MOVE) |
|
|
|
|
|
|
|
draggingTimeCounter = 0; |
|
|
|
} |
|
|
|
else if (event.touchAction == TOUCH_MOVE) |
|
|
|
{ |
|
|
|
if (GetMagnitude(moveDownPosition, event.position[0]) > 5) eventTime = GetCurrentTime(); |
|
|
|
moveDownPosition = event.position[0]; |
|
|
|
|
|
|
|
if (currentGesture == GESTURE_HOLD) |
|
|
|
{ |
|
|
|
if (event.pointCount > 1) InitPinchGesture(event.position[0], event.position[1]); |
|
|
|
else |
|
|
|
{ |
|
|
|
lastDragPosition = endDragPosition; |
|
|
|
endDragPosition = event.position[0]; |
|
|
|
|
|
|
|
//endDragPosition.x = AMotionEvent_getX(event, 0); |
|
|
|
//endDragPosition.y = AMotionEvent_getY(event, 0); |
|
|
|
|
|
|
|
// Calculate attributes |
|
|
|
dragVector = (Vector2){ endDragPosition.x - lastDragPosition.x, endDragPosition.y - lastDragPosition.y }; |
|
|
|
magnitude = sqrt(pow(endDragPosition.x - initialDragPosition.x, 2) + pow(endDragPosition.y - initialDragPosition.y, 2)); |
|
|
|
angle = CalculateAngle(initialDragPosition, endDragPosition, magnitude); |
|
|
|
intensity = magnitude / (float)draggingTimeCounter; |
|
|
|
|
|
|
|
// Check if drag movement is less than minimum to keep it as hold state or switch to drag state |
|
|
|
if(magnitude > FORCE_TO_SWIPE) |
|
|
|
{ |
|
|
|
currentGesture = GESTURE_DRAG; |
|
|
|
draggingTimeCounter++; |
|
|
|
} |
|
|
|
else currentGesture = GESTURE_HOLD; |
|
|
|
} |
|
|
|
if (numHold == 1) touchDownPosition = event.position[0]; |
|
|
|
|
|
|
|
numHold = 2; |
|
|
|
|
|
|
|
magnitude = GetMagnitude(touchDownPosition, moveDownPosition); |
|
|
|
|
|
|
|
// Detect GESTURE_DRAG |
|
|
|
if (magnitude >= FORCE_TO_DRAG) currentGesture = GESTURE_DRAG; |
|
|
|
} |
|
|
|
} break; |
|
|
|
case TYPE_DUAL_INPUT: |
|
|
|
|
|
|
|
draggingTimeCounter++; |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
// two fingers |
|
|
|
|
|
|
|
if (event.touchAction == TOUCH_DOWN) |
|
|
|
{ |
|
|
|
touchDownPosition = event.position[0]; |
|
|
|
touchDownPosition2 = event.position[1]; |
|
|
|
|
|
|
|
currentGesture = GESTURE_HOLD; |
|
|
|
} |
|
|
|
else if (event.touchAction == TOUCH_MOVE) |
|
|
|
{ |
|
|
|
if (event.touchAction == TOUCH_UP) |
|
|
|
magnitude = GetMagnitude(moveDownPosition, moveDownPosition2); |
|
|
|
|
|
|
|
touchDownPosition = moveDownPosition; |
|
|
|
touchDownPosition2 = moveDownPosition2; |
|
|
|
|
|
|
|
moveDownPosition = event.position[0]; |
|
|
|
moveDownPosition2 = event.position[1]; |
|
|
|
|
|
|
|
if ( (GetMagnitude(touchDownPosition, moveDownPosition) > FORCE_TO_PINCH) || (GetMagnitude(touchDownPosition2, moveDownPosition2) > FORCE_TO_PINCH)) |
|
|
|
{ |
|
|
|
if (event.pointCount == 1) |
|
|
|
{ |
|
|
|
// Set the drag starting position |
|
|
|
initialTapPosition = event.position[0]; |
|
|
|
} |
|
|
|
gestureType = TYPE_MOTIONLESS; |
|
|
|
if ((GetMagnitude(moveDownPosition, moveDownPosition2) - magnitude) < 0) currentGesture = GESTURE_PINCH_IN; |
|
|
|
else currentGesture = GESTURE_PINCH_OUT; |
|
|
|
} |
|
|
|
else if (event.touchAction == TOUCH_MOVE) |
|
|
|
else |
|
|
|
{ |
|
|
|
// Adapt the ending position of the inputs |
|
|
|
firstEndPinchPosition = event.position[0]; |
|
|
|
secondEndPinchPosition = event.position[1]; |
|
|
|
|
|
|
|
// If there is no more than two inputs |
|
|
|
if (event.pointCount == 2) |
|
|
|
{ |
|
|
|
// Calculate distances |
|
|
|
float initialDistance = VectorDistance(firstInitialPinchPosition, secondInitialPinchPosition); |
|
|
|
float endDistance = VectorDistance(firstEndPinchPosition, secondEndPinchPosition); |
|
|
|
|
|
|
|
// Calculate Vectors |
|
|
|
Vector2 firstTouchVector = { firstEndPinchPosition.x - firstInitialPinchPosition.x, firstEndPinchPosition.y - firstInitialPinchPosition.y }; |
|
|
|
Vector2 secondTouchVector = { secondEndPinchPosition.x - secondInitialPinchPosition.x, secondEndPinchPosition.y - secondInitialPinchPosition.y }; |
|
|
|
|
|
|
|
// Detect the pinch gesture |
|
|
|
if (VectorDotProduct(firstTouchVector, secondTouchVector) < -0.5) pinchDelta = initialDistance - endDistance; |
|
|
|
else pinchDelta = 0; |
|
|
|
|
|
|
|
// Pinch gesture resolution |
|
|
|
if (pinchDelta != 0) |
|
|
|
{ |
|
|
|
if (pinchDelta > 0) currentGesture = GESTURE_PINCH_IN; |
|
|
|
else currentGesture = GESTURE_PINCH_OUT; |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
// Set the drag starting position |
|
|
|
initialTapPosition = event.position[0]; |
|
|
|
|
|
|
|
gestureType = TYPE_MOTIONLESS; |
|
|
|
} |
|
|
|
|
|
|
|
// Readapt the initial position of the inputs |
|
|
|
firstInitialPinchPosition = firstEndPinchPosition; |
|
|
|
secondInitialPinchPosition = secondEndPinchPosition; |
|
|
|
currentGesture = GESTURE_HOLD; |
|
|
|
} |
|
|
|
} break; |
|
|
|
} |
|
|
|
else if (event.touchAction == TOUCH_UP) |
|
|
|
{ |
|
|
|
currentGesture = GESTURE_NONE; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Update gestures detected (must be called every frame) |
|
|
|
void UpdateGestures(void) |
|
|
|
{ |
|
|
|
// NOTE: Gestures are processed through system callbacks on touch events |
|
|
|
|
|
|
|
// Detect GESTURE_HOLD |
|
|
|
if (((currentGesture == GESTURE_TAP) || (currentGesture == GESTURE_DOUBLETAP)) && pointCount < 2) currentGesture = GESTURE_HOLD; |
|
|
|
if ((GetCurrentTime() - eventTime) > TAP_TIMEOUT && (currentGesture == GESTURE_DRAG) && pointCount < 2) |
|
|
|
{ |
|
|
|
currentGesture = GESTURE_HOLD; |
|
|
|
numHold = 1; |
|
|
|
} |
|
|
|
|
|
|
|
// Detect GESTURE_NONE |
|
|
|
if ((currentGesture == GESTURE_SWIPE_RIGHT) || (currentGesture == GESTURE_SWIPE_UP) || (currentGesture == GESTURE_SWIPE_LEFT) || (currentGesture == GESTURE_SWIPE_DOWN)) |
|
|
|
{ |
|
|
|
currentGesture = GESTURE_NONE; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Calculate distance between two vectors |
|
|
|
float Vector2Distance(Vector2 v1, Vector3 v2) |
|
|
|
{ |
|
|
|
float result; |
|
|
|
|
|
|
|
float dx = v2.x - v1.x; |
|
|
|
float dy = v2.y - v1.y; |
|
|
|
|
|
|
|
result = sqrt(dx*dx + dy*dy); |
|
|
|
|
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
// Check if a gesture have been detected |
|
|
|
bool IsGestureDetected(void) |
|
|
|
{ |
|
|
|
if (currentGesture != GESTURE_NONE) return true; |
|
|
|
if (p">(enabledGestures & currentGesture) != GESTURE_NONE) return true; |
|
|
|
else return false; |
|
|
|
} |
|
|
|
|
|
|
@ -298,7 +301,7 @@ int GetGestureType(void) |
|
|
|
|
|
|
|
void SetGesturesEnabled(unsigned int gestureFlags) |
|
|
|
{ |
|
|
|
enabledGestures = enabledGestures | gestureFlags; |
|
|
|
enabledGestures = gestureFlags; |
|
|
|
} |
|
|
|
|
|
|
|
// Get drag intensity (pixels per frame) |
|
|
@ -440,6 +443,7 @@ static float VectorDotProduct(Vector2 v1, Vector2 v2) |
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
// Time measure returned are milliseconds |
|
|
|
static double GetCurrentTime() |
|
|
|
{ |
|
|
|
double time = 0; |
|
|
|