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:
parent
f269fb46ea
commit
d32feaa668
230
src/core.c
230
src/core.c
@ -66,7 +66,7 @@
|
||||
#include <jni.h> // Java native interface
|
||||
#include <android/sensor.h> // Android sensors functions
|
||||
#include <android/window.h> // Defines AWINDOW_FLAG_FULLSCREEN and others
|
||||
//#include <android_native_app_glue.h> // Defines basic app state struct and manages activity
|
||||
#include <android_native_app_glue.h> // Defines basic app state struct and manages activity
|
||||
|
||||
#include <EGL/egl.h> // Khronos EGL library - Native platform display device control functions
|
||||
#include <GLES2/gl2.h> // Khronos OpenGL ES 2.0 library
|
||||
@ -103,7 +103,6 @@
|
||||
//----------------------------------------------------------------------------------
|
||||
// Defines and Macros
|
||||
//----------------------------------------------------------------------------------
|
||||
#define MAX_TOUCH_POINTS 256
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Types and Structures Definition
|
||||
@ -121,7 +120,8 @@ static struct android_app *app; // Android activity
|
||||
static struct android_poll_source *source; // Android events polling source
|
||||
static int ident, events;
|
||||
static bool windowReady = false; // Used to detect display initialization
|
||||
|
||||
static bool appEnabled = true; // Used to detec if app is active
|
||||
static bool contextRebindRequired = false; // Used to know context rebind required
|
||||
#elif defined(PLATFORM_RPI)
|
||||
static EGL_DISPMANX_WINDOW_T nativeWindow; // Native window (graphic device)
|
||||
|
||||
@ -149,6 +149,7 @@ static int gamepadStream = -1; // Gamepad device file descripto
|
||||
static EGLDisplay display; // Native display device (physical screen connection)
|
||||
static EGLSurface surface; // Surface to draw on, framebuffers (connected to context)
|
||||
static EGLContext context; // Graphic context, mode in which drawing can be done
|
||||
static EGLConfig config; // Graphic config
|
||||
static uint64_t baseTime; // Base time measure for hi-res timer
|
||||
static bool windowShouldClose = false; // Flag to set window for closing
|
||||
#endif
|
||||
@ -254,10 +255,12 @@ static void TakeScreenshot(void);
|
||||
|
||||
#if defined(PLATFORM_ANDROID)
|
||||
static void AndroidCommandCallback(struct android_app *app, int32_t cmd); // Process Android activity lifecycle commands
|
||||
static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event); // Process Android inputs
|
||||
#endif
|
||||
|
||||
#if defined(PLATFORM_WEB)
|
||||
static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *e, void *userData);
|
||||
static EM_BOOL EmscriptenInputCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData);
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
@ -293,9 +296,15 @@ void InitWindow(int width, int height, const char *title)
|
||||
#endif
|
||||
|
||||
#if defined(PLATFORM_WEB)
|
||||
InitGesturesSystem();
|
||||
|
||||
emscripten_set_fullscreenchange_callback(0, 0, 1, EmscriptenFullscreenChangeCallback);
|
||||
|
||||
// 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);
|
||||
#endif
|
||||
|
||||
mousePosition.x = screenWidth/2;
|
||||
@ -350,24 +359,23 @@ void InitWindow(int width, int height, struct android_app *state)
|
||||
|
||||
//state->userData = &engine;
|
||||
app->onAppCmd = AndroidCommandCallback;
|
||||
|
||||
InitAssetManager(app->activity->assetManager);
|
||||
app->onInputEvent = AndroidInputCallback;
|
||||
|
||||
InitGesturesSystem(app);
|
||||
InitAssetManager(app->activity->assetManager);
|
||||
|
||||
TraceLog(INFO, "Android app initialized successfully");
|
||||
|
||||
// Wait for window to be initialized (display and context)
|
||||
while (!windowReady)
|
||||
{
|
||||
// Wait for window to be initialized (display and context)
|
||||
// Process events loop
|
||||
while ((ident = ALooper_pollAll(0, NULL, &events,(void**)&source)) >= 0)
|
||||
{
|
||||
// Process this event
|
||||
if (source != NULL) source->process(app, source);
|
||||
|
||||
// Check if we are exiting
|
||||
if (app->destroyRequested != 0) windowShouldClose = true;
|
||||
// NOTE: Never close window, native activity is controlled by the system!
|
||||
//if (app->destroyRequested != 0) windowShouldClose = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1221,7 +1229,6 @@ static void InitDisplay(int width, int height)
|
||||
};
|
||||
|
||||
EGLint numConfigs;
|
||||
EGLConfig config;
|
||||
|
||||
// Get an EGL display connection
|
||||
display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||
@ -1455,30 +1462,62 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd)
|
||||
|
||||
if (app->window != NULL)
|
||||
{
|
||||
// Init device display (monitor, LCD, ...)
|
||||
InitDisplay(screenWidth, screenHeight);
|
||||
|
||||
// Init OpenGL graphics
|
||||
InitGraphics();
|
||||
|
||||
// Load default font for convenience
|
||||
// NOTE: External function (defined in module: text)
|
||||
LoadDefaultFont();
|
||||
|
||||
// Init hi-res timer
|
||||
InitTimer();
|
||||
|
||||
// raylib logo appearing animation (if enabled)
|
||||
if (showLogo)
|
||||
if (contextRebindRequired)
|
||||
{
|
||||
SetTargetFPS(60);
|
||||
LogoAnimation();
|
||||
// Reset screen scaling to full display size
|
||||
EGLint displayFormat;
|
||||
eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &displayFormat);
|
||||
ANativeWindow_setBuffersGeometry(app->window, renderWidth, renderHeight, displayFormat);
|
||||
|
||||
// Recreate display surface and re-attach OpenGL context
|
||||
surface = eglCreateWindowSurface(display, config, app->window, NULL);
|
||||
eglMakeCurrent(display, surface, surface, context);
|
||||
|
||||
contextRebindRequired = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Init device display (monitor, LCD, ...)
|
||||
InitDisplay(screenWidth, screenHeight);
|
||||
|
||||
// Init OpenGL graphics
|
||||
InitGraphics();
|
||||
|
||||
// Load default font for convenience
|
||||
// NOTE: External function (defined in module: text)
|
||||
LoadDefaultFont();
|
||||
|
||||
// TODO: GPU assets reload in case of lost focus (lost context)
|
||||
// NOTE: This problem has been solved just unbinding and rebinding context from display
|
||||
/*
|
||||
if (assetsReloadRequired)
|
||||
{
|
||||
for (int i = 0; i < assetsCount; i++)
|
||||
{
|
||||
// TODO: Unload old asset if required
|
||||
|
||||
// Load texture again to pointed texture
|
||||
(*textureAsset + i) = LoadTexture(assetPath[i]);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// Init hi-res timer
|
||||
InitTimer();
|
||||
|
||||
// raylib logo appearing animation (if enabled)
|
||||
if (showLogo)
|
||||
{
|
||||
SetTargetFPS(60); // Not required on Android
|
||||
LogoAnimation();
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case APP_CMD_GAINED_FOCUS:
|
||||
{
|
||||
TraceLog(INFO, "APP_CMD_GAINED_FOCUS");
|
||||
appEnabled = true;
|
||||
//ResumeMusicStream();
|
||||
} break;
|
||||
case APP_CMD_PAUSE:
|
||||
@ -1489,11 +1528,18 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd)
|
||||
{
|
||||
//DrawFrame();
|
||||
TraceLog(INFO, "APP_CMD_LOST_FOCUS");
|
||||
appEnabled = false;
|
||||
//PauseMusicStream();
|
||||
} break;
|
||||
case APP_CMD_TERM_WINDOW:
|
||||
{
|
||||
// TODO: Do display destruction here? -> Yes but only display, don't free buffers!
|
||||
// Dettach OpenGL context and destroy display surface
|
||||
// NOTE 1: Detaching context before destroying display surface avoids losing our resources (textures, shaders, VBOs...)
|
||||
// NOTE 2: In some cases (too many context loaded), OS could unload context automatically... :(
|
||||
eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
eglDestroySurface(display, surface);
|
||||
|
||||
contextRebindRequired = true;
|
||||
|
||||
TraceLog(INFO, "APP_CMD_TERM_WINDOW");
|
||||
} break;
|
||||
@ -1524,6 +1570,61 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd)
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
// Android: Get input events
|
||||
static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
|
||||
{
|
||||
//http://developer.android.com/ndk/reference/index.html
|
||||
|
||||
int type = AInputEvent_getType(event);
|
||||
|
||||
if (type == AINPUT_EVENT_TYPE_MOTION)
|
||||
{
|
||||
touchPosition.x = AMotionEvent_getX(event, 0);
|
||||
touchPosition.y = AMotionEvent_getY(event, 0);
|
||||
}
|
||||
else if (type == AINPUT_EVENT_TYPE_KEY)
|
||||
{
|
||||
int32_t keycode = AKeyEvent_getKeyCode(event);
|
||||
//int32_t AKeyEvent_getMetaState(event);
|
||||
|
||||
//if (keycode == AKEYCODE_HOME) { }
|
||||
//if (keycode == AKEYCODE_POWER) { }
|
||||
if (keycode == AKEYCODE_BACK)
|
||||
{
|
||||
// Eat BACK_BUTTON, just do nothing... and don't let to be handled by OS!
|
||||
return 1;
|
||||
}
|
||||
else if ((keycode == AKEYCODE_VOLUME_UP) || (keycode == AKEYCODE_VOLUME_DOWN))
|
||||
{
|
||||
// Set default OS behaviour
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t action = AMotionEvent_getAction(event);
|
||||
unsigned int flags = action & AMOTION_EVENT_ACTION_MASK;
|
||||
|
||||
GestureEvent gestureEvent;
|
||||
|
||||
// Register touch actions
|
||||
if (flags == AMOTION_EVENT_ACTION_DOWN) gestureEvent.touchAction = TOUCH_DOWN;
|
||||
else if (flags == AMOTION_EVENT_ACTION_UP) gestureEvent.touchAction = TOUCH_UP;
|
||||
else if (flags == AMOTION_EVENT_ACTION_MOVE) gestureEvent.touchAction = TOUCH_MOVE;
|
||||
|
||||
// Register touch points count
|
||||
gestureEvent.pointCount = AMotionEvent_getPointerCount(event);
|
||||
|
||||
// Register touch points position
|
||||
// NOTE: Only two points registered
|
||||
gestureEvent.position[0] = (Vector2){ AMotionEvent_getX(event, 0), AMotionEvent_getY(event, 0) };
|
||||
gestureEvent.position[1] = (Vector2){ AMotionEvent_getX(event, 1), AMotionEvent_getY(event, 1) };
|
||||
|
||||
// Gesture data is sent to gestures system for processing
|
||||
ProcessGestureEvent(gestureEvent);
|
||||
|
||||
return 0; // return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)
|
||||
@ -1613,9 +1714,8 @@ static bool GetMouseButtonStatus(int button)
|
||||
static void PollInputEvents(void)
|
||||
{
|
||||
#if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB)
|
||||
// Touch events reading (requires gestures module)
|
||||
touchPosition = GetRawTouchPosition();
|
||||
|
||||
|
||||
// TODO: Remove this requirement...
|
||||
UpdateGestures();
|
||||
#endif
|
||||
|
||||
@ -1645,23 +1745,18 @@ static void PollInputEvents(void)
|
||||
glfwPollEvents(); // Register keyboard/mouse events... and window events!
|
||||
#elif defined(PLATFORM_ANDROID)
|
||||
|
||||
// TODO: Check virtual keyboard (?)
|
||||
|
||||
// Poll Events (registered events)
|
||||
// TODO: Enable/disable activityMinimized to block activity if minimized
|
||||
//while ((ident = ALooper_pollAll(activityMinimized ? 0 : -1, NULL, &events,(void**)&source)) >= 0)
|
||||
while ((ident = ALooper_pollAll(0, NULL, &events, (void**)&source)) >= 0)
|
||||
// NOTE: Activity is paused if not enabled (appEnabled)
|
||||
while ((ident = ALooper_pollAll(appEnabled ? 0 : -1, NULL, &events,(void**)&source)) >= 0)
|
||||
{
|
||||
// Process this event
|
||||
if (source != NULL) source->process(app, source);
|
||||
|
||||
// Check if we are exiting
|
||||
// NOTE: Never close window, native activity is controlled by the system!
|
||||
if (app->destroyRequested != 0)
|
||||
{
|
||||
// NOTE: Never close window, native activity is controlled by the system!
|
||||
//TraceLog(INFO, "Closing Window...");
|
||||
//windowShouldClose = true;
|
||||
|
||||
//ANativeActivity_finish(app->activity);
|
||||
}
|
||||
}
|
||||
@ -2035,6 +2130,59 @@ static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const Emscripte
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
// Register touch actions
|
||||
if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) gestureEvent.touchAction = TOUCH_DOWN;
|
||||
else if (eventType == EMSCRIPTEN_EVENT_TOUCHEND) gestureEvent.touchAction = TOUCH_UP;
|
||||
else if (eventType == EMSCRIPTEN_EVENT_TOUCHMOVE) gestureEvent.touchAction = TOUCH_MOVE;
|
||||
|
||||
// Register touch points count
|
||||
gestureEvent.pointCount = touchEvent->numTouches;
|
||||
|
||||
// Register touch points position
|
||||
// NOTE: Only two points registered
|
||||
// TODO: Touch data should be scaled accordingly!
|
||||
//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 };
|
||||
|
||||
touchPosition = gestureEvent.position[0];
|
||||
|
||||
// Gesture data is sent to gestures system for processing
|
||||
ProcessGestureEvent(gestureEvent); // Process obtained gestures data
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Plays raylib logo appearing animation
|
||||
|
332
src/gestures.c
332
src/gestures.c
@ -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
|
@ -67,6 +67,17 @@ typedef enum {
|
||||
GESTURE_PINCH_OUT = 1024
|
||||
} Gestures;
|
||||
|
||||
typedef enum { TOUCH_UP, TOUCH_DOWN, TOUCH_MOVE } TouchAction;
|
||||
|
||||
// Gesture events
|
||||
// NOTE: MAX_TOUCH_POINTS fixed to 4
|
||||
typedef struct {
|
||||
int touchAction;
|
||||
int pointCount;
|
||||
int pointerId[4];
|
||||
Vector2 position[4];
|
||||
} GestureEvent;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" { // Prevents name mangling of functions
|
||||
#endif
|
||||
@ -79,19 +90,11 @@ extern "C" { // Prevents name mangling of functions
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module Functions Declaration
|
||||
//----------------------------------------------------------------------------------
|
||||
int GetTouchX(void); // Returns touch position X (relative to screen size)
|
||||
int GetTouchY(void); // Returns touch position Y (relative to screen size)
|
||||
Vector2 GetTouchPosition(void); // Returns touch position XY (relative to screen size)
|
||||
|
||||
#if defined(PLATFORM_WEB)
|
||||
void InitGesturesSystem(void); // Init gestures system (web)
|
||||
#elif defined(PLATFORM_ANDROID)
|
||||
void InitGesturesSystem(struct android_app *app); // Init gestures system (android)
|
||||
#endif
|
||||
void UpdateGestures(void); // Update gestures detected (must be called every frame)
|
||||
bool IsGestureDetected(void); // Check if a gesture have been detected
|
||||
int GetGestureType(void); // Get latest detected gesture
|
||||
void SetGesturesEnabled(unsigned int gestureFlags); // Enable a set of gestures using flags
|
||||
void ProcessGestureEvent(GestureEvent event); // Process gesture event and translate it into gestures
|
||||
|
||||
float GetGestureDragIntensity(void); // Get gesture drag intensity
|
||||
float GetGestureDragAngle(void); // Get gesture drag angle
|
||||
|
20
src/raylib.h
20
src/raylib.h
@ -70,7 +70,7 @@
|
||||
#endif
|
||||
|
||||
#if defined(PLATFORM_ANDROID)
|
||||
#include <android_native_app_glue.h> // Defines android_app struct
|
||||
typedef struct android_app; // Define android_app struct (android_native_app_glue.h)
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
@ -432,6 +432,17 @@ typedef enum {
|
||||
GESTURE_PINCH_OUT = 1024
|
||||
} Gestures;
|
||||
|
||||
typedef enum { TOUCH_UP, TOUCH_DOWN, TOUCH_MOVE } TouchAction;
|
||||
|
||||
// Gesture events
|
||||
// NOTE: MAX_TOUCH_POINTS fixed to 4
|
||||
typedef struct {
|
||||
int touchAction;
|
||||
int pointCount;
|
||||
int pointerId[4];
|
||||
Vector2 position[4];
|
||||
} GestureEvent;
|
||||
|
||||
// Camera system modes
|
||||
typedef enum { CAMERA_CUSTOM = 0, CAMERA_FREE, CAMERA_ORBITAL, CAMERA_FIRST_PERSON, CAMERA_THIRD_PERSON } CameraMode;
|
||||
|
||||
@ -571,16 +582,11 @@ Vector2 GetTouchPosition(void); // Returns touch positio
|
||||
//------------------------------------------------------------------------------------
|
||||
// Gestures and Touch Handling Functions (Module: gestures)
|
||||
//------------------------------------------------------------------------------------
|
||||
Vector2 GetRawTouchPosition(void); // Get touch position (raw)
|
||||
#if defined(PLATFORM_WEB)
|
||||
void InitGesturesSystem(void); // Init gestures system (web)
|
||||
#elif defined(PLATFORM_ANDROID)
|
||||
void InitGesturesSystem(struct android_app *app); // Init gestures system (android)
|
||||
#endif
|
||||
void UpdateGestures(void); // Update gestures detected (must be called every frame)
|
||||
bool IsGestureDetected(void); // Check if a gesture have been detected
|
||||
int GetGestureType(void); // Get latest detected gesture
|
||||
void SetGesturesEnabled(unsigned int gestureFlags); // Enable a set of gestures using flags
|
||||
void ProcessGestureEvent(GestureEvent event); // Process gesture event and translate it into gestures
|
||||
|
||||
float GetGestureDragIntensity(void); // Get gesture drag intensity
|
||||
float GetGestureDragAngle(void); // Get gesture drag angle
|
||||
|
Loading…
Reference in New Issue
Block a user