From d32feaa6685584e9856aa94f4d5bf80b7f5b861c Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sun, 3 Jan 2016 13:01:21 +0100 Subject: [PATCH] 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) --- src/core.c | 230 ++++++++++++++++++++++++++++------ src/gestures.c | 332 +++++++++++++------------------------------------ src/gestures.h | 21 ++-- src/raylib.h | 20 +-- 4 files changed, 297 insertions(+), 306 deletions(-) diff --git a/src/core.c b/src/core.c index acfc63d5..14510a1b 100644 --- a/src/core.c +++ b/src/core.c @@ -66,7 +66,7 @@ #include // Java native interface #include // Android sensors functions #include // Defines AWINDOW_FLAG_FULLSCREEN and others - //#include // Defines basic app state struct and manages activity + #include // Defines basic app state struct and manages activity #include // Khronos EGL library - Native platform display device control functions #include // 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 diff --git a/src/gestures.c b/src/gestures.c index adde85b9..88cdb528 100644 --- a/src/gestures.c +++ b/src/gestures.c @@ -42,23 +42,12 @@ #include // Used for clock functions #endif -#if defined(PLATFORM_ANDROID) - #include // Java native interface - #include // Android sensors functions - #include // Defines AWINDOW_FLAG_FULLSCREEN and others -#endif - -#if defined(PLATFORM_WEB) - #include - #include -#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 \ No newline at end of file diff --git a/src/gestures.h b/src/gestures.h index 896f3028..b5cf2767 100644 --- a/src/gestures.h +++ b/src/gestures.h @@ -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 diff --git a/src/raylib.h b/src/raylib.h index 1113958d..864a240a 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -70,7 +70,7 @@ #endif #if defined(PLATFORM_ANDROID) - #include // 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