Skip to content

Commit

Permalink
Reviewed Android inputs and gestures system
Browse files Browse the repository at this point in the history
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)
  • Loading branch information
raysan5 committed Jan 3, 2016
1 parent f269fb4 commit d32feaa
Show file tree
Hide file tree
Showing 4 changed files with 294 additions and 303 deletions.
224 changes: 186 additions & 38 deletions src/core.c
Expand Up @@ -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
Expand Down Expand Up @@ -103,7 +103,6 @@
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
#define MAX_TOUCH_POINTS 256

//----------------------------------------------------------------------------------
// Types and Structures Definition
Expand All @@ -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)

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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

//----------------------------------------------------------------------------------
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
}
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
if (contextRebindRequired)
{
// Reset screen scaling to full display size
EGLint displayFormat;
eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &displayFormat);
ANativeWindow_setBuffersGeometry(app->window, renderWidth, renderHeight, displayFormat);

// Init OpenGL graphics
InitGraphics();
// Recreate display surface and re-attach OpenGL context
surface = eglCreateWindowSurface(display, config, app->window, NULL);
eglMakeCurrent(display, surface, surface, context);

// Load default font for convenience
// NOTE: External function (defined in module: text)
LoadDefaultFont();
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();
// Init hi-res timer
InitTimer();

// raylib logo appearing animation (if enabled)
if (showLogo)
{
SetTargetFPS(60);
LogoAnimation();
// 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:
Expand All @@ -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;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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

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

0 comments on commit d32feaa

Please sign in to comment.