RetroArch/input/drivers/android_input.c

1347 lines
41 KiB
C
Raw Normal View History

/* RetroArch - A frontend for libretro.
2014-01-01 01:50:59 +01:00
* Copyright (C) 2010-2014 - Hans-Kristian Arntzen
2016-01-10 04:33:01 +01:00
* Copyright (C) 2011-2016 - Daniel De Matteis
2015-01-07 17:46:50 +01:00
* Copyright (C) 2012-2015 - Michael Lelli
2014-01-01 01:50:59 +01:00
* Copyright (C) 2013-2014 - Steven Crowe
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
2012-11-01 05:48:20 +01:00
#include <unistd.h>
#include <dlfcn.h>
2015-09-05 20:40:11 +02:00
#include <android/keycodes.h>
2015-04-21 02:46:50 +02:00
2015-12-05 21:18:06 +01:00
#include <dynamic/dylib.h>
2015-04-21 02:46:50 +02:00
#include <retro_inline.h>
2015-12-26 07:54:17 +01:00
#include <string/stdstring.h>
2015-04-21 02:46:50 +02:00
2015-09-16 05:45:50 +02:00
#include "../../frontend/drivers/platform_linux.h"
2015-01-12 06:16:52 +01:00
#include "../input_autodetect.h"
#include "../input_config.h"
#include "../input_joypad_driver.h"
2015-11-29 16:18:29 +01:00
#include "../drivers_keyboard/keyboard_event_android.h"
2015-01-12 06:16:52 +01:00
#include "../../performance.h"
#include "../../general.h"
#include "../../driver.h"
2015-05-09 09:38:45 +02:00
#ifdef HAVE_MENU
#include "../../menu/menu_display.h"
#endif
2015-05-09 09:38:45 +02:00
#define MAX_TOUCH 16
#define MAX_NUM_KEYBOARDS 3
2015-05-09 09:38:45 +02:00
typedef struct
{
float x;
float y;
float z;
} sensor_t;
struct input_pointer
{
int16_t x, y;
int16_t full_x, full_y;
};
static int pad_id1 = -1;
static int pad_id2 = -1;
static int kbd_id[MAX_NUM_KEYBOARDS];
static int kbd_num = 0;
enum
{
AXIS_X = 0,
AXIS_Y = 1,
AXIS_Z = 11,
AXIS_RZ = 14,
AXIS_HAT_X = 15,
2013-07-31 19:04:28 +02:00
AXIS_HAT_Y = 16,
AXIS_LTRIGGER = 17,
AXIS_RTRIGGER = 18,
AXIS_GAS = 22,
2015-07-09 18:11:53 +02:00
AXIS_BRAKE = 23
};
2015-05-09 09:38:45 +02:00
typedef struct state_device
{
int id;
int port;
char name[256];
} state_device_t;
2015-12-02 22:12:43 +01:00
typedef struct android_input_data
{
2015-05-09 09:38:45 +02:00
state_device_t pad_states[MAX_PADS];
int16_t analog_state[MAX_PADS][MAX_AXIS];
int8_t hat_state[MAX_PADS][2];
2015-12-02 22:12:43 +01:00
unsigned pads_connected;
2015-05-09 09:38:45 +02:00
sensor_t accelerometer_state;
struct input_pointer pointer[MAX_TOUCH];
unsigned pointer_count;
2015-12-02 22:12:43 +01:00
} android_input_data_t;
typedef struct android_input
{
bool blocked;
android_input_data_t thread, copy;
const input_device_driver_t *joypad;
} android_input_t;
static void frontend_android_get_version_sdk(int32_t *sdk);
static void frontend_android_get_name(char *s, size_t len);
2015-05-09 09:38:45 +02:00
bool (*engine_lookup_name)(char *buf,
int *vendorId, int *productId, size_t size, int id);
void (*engine_handle_dpad)(android_input_data_t *, AInputEvent*, int, int);
2015-11-29 16:18:29 +01:00
static bool android_input_set_sensor_state(void *data, unsigned port,
enum retro_sensor_action action, unsigned event_rate);
extern float AMotionEvent_getAxisValue(const AInputEvent* motion_event,
2014-10-20 20:31:00 +02:00
int32_t axis, size_t pointer_idx);
static typeof(AMotionEvent_getAxisValue) *p_AMotionEvent_getAxisValue;
#define AMotionEvent_getAxisValue (*p_AMotionEvent_getAxisValue)
static void *libandroid_handle;
2015-05-09 09:38:45 +02:00
static bool android_input_lookup_name_prekitkat(char *buf,
int *vendorId, int *productId, size_t size, int id)
{
2015-07-09 18:09:45 +02:00
jobject name = NULL;
jmethodID getName = NULL;
jobject device = NULL;
jmethodID method = NULL;
jclass class = 0;
const char *str = NULL;
JNIEnv *env = (JNIEnv*)jni_thread_getenv();
2015-05-09 09:38:45 +02:00
if (!env)
goto error;
2015-07-09 18:09:45 +02:00
RARCH_LOG("Using old lookup");
2015-05-09 09:38:45 +02:00
FIND_CLASS(env, class, "android/view/InputDevice");
if (!class)
goto error;
GET_STATIC_METHOD_ID(env, method, class, "getDevice",
"(I)Landroid/view/InputDevice;");
if (!method)
goto error;
CALL_OBJ_STATIC_METHOD_PARAM(env, device, class, method, (jint)id);
if (!device)
{
RARCH_ERR("Failed to find device for ID: %d\n", id);
goto error;
}
GET_METHOD_ID(env, getName, class, "getName", "()Ljava/lang/String;");
if (!getName)
goto error;
CALL_OBJ_METHOD(env, name, device, getName);
if (!name)
{
RARCH_ERR("Failed to find name for device ID: %d\n", id);
goto error;
}
buf[0] = '\0';
str = (*env)->GetStringUTFChars(env, name, 0);
if (str)
strlcpy(buf, str, size);
(*env)->ReleaseStringUTFChars(env, name, str);
RARCH_LOG("device name: %s\n", buf);
return true;
error:
return false;
}
static bool android_input_lookup_name(char *buf,
int *vendorId, int *productId, size_t size, int id)
{
2015-07-09 18:09:45 +02:00
jmethodID getVendorId = NULL;
jmethodID getProductId = NULL;
jmethodID getName = NULL;
jobject device = NULL;
jobject name = NULL;
jmethodID method = NULL;
jclass class = NULL;
const char *str = NULL;
JNIEnv *env = (JNIEnv*)jni_thread_getenv();
2015-05-09 09:38:45 +02:00
if (!env)
goto error;
2015-07-09 18:09:45 +02:00
RARCH_LOG("Using new lookup");
2015-05-09 09:38:45 +02:00
FIND_CLASS(env, class, "android/view/InputDevice");
if (!class)
goto error;
GET_STATIC_METHOD_ID(env, method, class, "getDevice",
"(I)Landroid/view/InputDevice;");
if (!method)
goto error;
CALL_OBJ_STATIC_METHOD_PARAM(env, device, class, method, (jint)id);
if (!device)
{
RARCH_ERR("Failed to find device for ID: %d\n", id);
goto error;
}
GET_METHOD_ID(env, getName, class, "getName", "()Ljava/lang/String;");
if (!getName)
goto error;
CALL_OBJ_METHOD(env, name, device, getName);
if (!name)
{
RARCH_ERR("Failed to find name for device ID: %d\n", id);
goto error;
}
buf[0] = '\0';
str = (*env)->GetStringUTFChars(env, name, 0);
if (str)
strlcpy(buf, str, size);
(*env)->ReleaseStringUTFChars(env, name, str);
RARCH_LOG("device name: %s\n", buf);
GET_METHOD_ID(env, getVendorId, class, "getVendorId", "()I");
if (!getVendorId)
goto error;
CALL_INT_METHOD(env, *vendorId, device, getVendorId);
2015-05-09 09:38:45 +02:00
RARCH_LOG("device vendor id: %d\n", *vendorId);
GET_METHOD_ID(env, getProductId, class, "getProductId", "()I");
if (!getProductId)
goto error;
*productId = 0;
CALL_INT_METHOD(env, *productId, device, getProductId);
2015-05-09 09:38:45 +02:00
RARCH_LOG("device product id: %d\n", *productId);
return true;
error:
return false;
}
2015-11-28 18:39:43 +01:00
static void android_input_poll_main_cmd(void)
{
2015-05-09 09:38:45 +02:00
int8_t cmd;
struct android_app *android_app = (struct android_app*)g_android;
2015-05-09 09:38:45 +02:00
if (read(android_app->msgread, &cmd, sizeof(cmd)) != sizeof(cmd))
cmd = -1;
switch (cmd)
{
case APP_CMD_REINIT_DONE:
slock_lock(android_app->mutex);
android_app->reinitRequested = 0;
scond_broadcast(android_app->cond);
slock_unlock(android_app->mutex);
break;
case APP_CMD_INPUT_CHANGED:
2015-05-09 09:38:45 +02:00
slock_lock(android_app->mutex);
if (android_app->inputQueue)
AInputQueue_detachLooper(android_app->inputQueue);
android_app->inputQueue = android_app->pendingInputQueue;
if (android_app->inputQueue)
{
RARCH_LOG("Attaching input queue to looper");
AInputQueue_attachLooper(android_app->inputQueue,
android_app->looper, LOOPER_ID_INPUT, NULL,
NULL);
}
2015-05-09 09:38:45 +02:00
scond_broadcast(android_app->cond);
slock_unlock(android_app->mutex);
break;
case APP_CMD_INIT_WINDOW:
2015-05-09 09:38:45 +02:00
slock_lock(android_app->mutex);
android_app->window = android_app->pendingWindow;
android_app->reinitRequested = 1;
2015-05-09 09:38:45 +02:00
scond_broadcast(android_app->cond);
slock_unlock(android_app->mutex);
break;
2015-12-02 08:54:24 +01:00
case APP_CMD_SAVE_STATE:
2015-05-09 09:38:45 +02:00
slock_lock(android_app->mutex);
2015-12-02 08:54:24 +01:00
android_app->stateSaved = 1;
2015-05-09 09:38:45 +02:00
scond_broadcast(android_app->cond);
slock_unlock(android_app->mutex);
break;
2015-12-02 08:54:24 +01:00
case APP_CMD_RESUME:
case APP_CMD_START:
case APP_CMD_PAUSE:
case APP_CMD_STOP:
2015-05-09 09:38:45 +02:00
slock_lock(android_app->mutex);
android_app->activityState = cmd;
2015-05-09 09:38:45 +02:00
scond_broadcast(android_app->cond);
slock_unlock(android_app->mutex);
break;
case APP_CMD_CONFIG_CHANGED:
AConfiguration_fromAssetManager(android_app->config,
android_app->activity->assetManager);
break;
case APP_CMD_TERM_WINDOW:
2015-05-09 09:38:45 +02:00
slock_lock(android_app->mutex);
/* The window is being hidden or closed, clean it up. */
/* terminate display/EGL context here */
android_app->window = NULL;
2015-05-09 09:38:45 +02:00
scond_broadcast(android_app->cond);
slock_unlock(android_app->mutex);
break;
case APP_CMD_GAINED_FOCUS:
2015-09-26 13:20:15 +02:00
{
bool boolean = false;
2015-11-30 21:42:59 +01:00
runloop_ctl(RUNLOOP_CTL_SET_PAUSED, &boolean);
runloop_ctl(RUNLOOP_CTL_SET_IDLE, &boolean);
#ifdef HAVE_MENU
menu_display_ctl(MENU_DISPLAY_CTL_UNSET_STUB_DRAW_FRAME, NULL);
2015-12-07 21:21:13 +01:00
video_driver_ctl(RARCH_DISPLAY_CTL_UNSET_STUB_FRAME, NULL);
#endif
2015-09-26 13:20:15 +02:00
if ((android_app->sensor_state_mask
& (UINT64_C(1) << RETRO_SENSOR_ACCELEROMETER_ENABLE))
&& android_app->accelerometerSensor == NULL)
input_sensor_set_state(0,
2015-09-26 13:20:15 +02:00
RETRO_SENSOR_ACCELEROMETER_ENABLE,
android_app->accelerometer_event_rate);
}
slock_lock(android_app->mutex);
android_app->unfocused = false;
scond_broadcast(android_app->cond);
slock_unlock(android_app->mutex);
break;
case APP_CMD_LOST_FOCUS:
2015-11-27 00:23:35 +01:00
{
bool boolean = true;
2015-11-30 21:42:59 +01:00
runloop_ctl(RUNLOOP_CTL_SET_PAUSED, &boolean);
runloop_ctl(RUNLOOP_CTL_SET_IDLE, &boolean);
#ifdef HAVE_MENU
menu_display_ctl(MENU_DISPLAY_CTL_SET_STUB_DRAW_FRAME, NULL);
2015-12-07 21:21:13 +01:00
video_driver_ctl(RARCH_DISPLAY_CTL_SET_STUB_FRAME, NULL);
#endif
2015-11-27 00:23:35 +01:00
/* Avoid draining battery while app is not being used. */
if ((android_app->sensor_state_mask
& (UINT64_C(1) << RETRO_SENSOR_ACCELEROMETER_ENABLE))
&& android_app->accelerometerSensor != NULL
)
input_sensor_set_state(0,
2015-11-27 00:23:35 +01:00
RETRO_SENSOR_ACCELEROMETER_DISABLE,
android_app->accelerometer_event_rate);
}
slock_lock(android_app->mutex);
android_app->unfocused = true;
scond_broadcast(android_app->cond);
slock_unlock(android_app->mutex);
break;
case APP_CMD_DESTROY:
2015-12-02 08:54:24 +01:00
RARCH_LOG("APP_CMD_DESTROY\n");
android_app->destroyRequested = 1;
break;
}
}
static void engine_handle_dpad_default(android_input_data_t *android_data,
AInputEvent *event, int port, int source)
{
size_t motion_ptr = AMotionEvent_getAction(event) >>
AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
float x = AMotionEvent_getX(event, motion_ptr);
float y = AMotionEvent_getY(event, motion_ptr);
android_data->analog_state[port][0] = (int16_t)(x * 32767.0f);
android_data->analog_state[port][1] = (int16_t)(y * 32767.0f);
}
static void engine_handle_dpad_getaxisvalue(android_input_data_t *android_data,
AInputEvent *event, int port, int source)
{
size_t motion_ptr = AMotionEvent_getAction(event) >>
AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
float x = AMotionEvent_getAxisValue(event, AXIS_X, motion_ptr);
float y = AMotionEvent_getAxisValue(event, AXIS_Y, motion_ptr);
float z = AMotionEvent_getAxisValue(event, AXIS_Z, motion_ptr);
float rz = AMotionEvent_getAxisValue(event, AXIS_RZ, motion_ptr);
float hatx = AMotionEvent_getAxisValue(event, AXIS_HAT_X, motion_ptr);
float haty = AMotionEvent_getAxisValue(event, AXIS_HAT_Y, motion_ptr);
float ltrig = AMotionEvent_getAxisValue(event, AXIS_LTRIGGER, motion_ptr);
float rtrig = AMotionEvent_getAxisValue(event, AXIS_RTRIGGER, motion_ptr);
float brake = AMotionEvent_getAxisValue(event, AXIS_BRAKE, motion_ptr);
float gas = AMotionEvent_getAxisValue(event, AXIS_GAS, motion_ptr);
android_data->hat_state[port][0] = (int)hatx;
android_data->hat_state[port][1] = (int)haty;
/* XXX: this could be a loop instead, but do we really want to
* loop through every axis? */
android_data->analog_state[port][0] = (int16_t)(x * 32767.0f);
android_data->analog_state[port][1] = (int16_t)(y * 32767.0f);
android_data->analog_state[port][2] = (int16_t)(z * 32767.0f);
android_data->analog_state[port][3] = (int16_t)(rz * 32767.0f);
#if 0
android_data->analog_state[port][4] = (int16_t)(hatx * 32767.0f);
android_data->analog_state[port][5] = (int16_t)(haty * 32767.0f);
#endif
android_data->analog_state[port][6] = (int16_t)(ltrig * 32767.0f);
android_data->analog_state[port][7] = (int16_t)(rtrig * 32767.0f);
android_data->analog_state[port][8] = (int16_t)(brake * 32767.0f);
android_data->analog_state[port][9] = (int16_t)(gas * 32767.0f);
}
static bool android_input_init_handle(void)
{
if (libandroid_handle != NULL) /* already initialized */
return true;
if ((libandroid_handle = dlopen("/system/lib/libandroid.so",
RTLD_LOCAL | RTLD_LAZY)) == 0)
return false;
if ((p_AMotionEvent_getAxisValue = dlsym(RTLD_DEFAULT,
"AMotionEvent_getAxisValue")))
{
RARCH_LOG("Set engine_handle_dpad to 'Get Axis Value' (for reading extra analog sticks)");
engine_handle_dpad = engine_handle_dpad_getaxisvalue;
}
pad_id1 = -1;
pad_id2 = -1;
return true;
}
static void *android_input_init(void)
{
2015-05-09 09:38:45 +02:00
int32_t sdk;
settings_t *settings = config_get_ptr();
2015-12-08 13:47:46 +01:00
struct android_app *android_app = (struct android_app*)g_android;
2015-07-09 18:09:45 +02:00
android_input_t *android = (android_input_t*)
calloc(1, sizeof(*android));
if (!android)
return NULL;
android->thread.pads_connected = 0;
2015-12-02 22:12:43 +01:00
android->copy.pads_connected = 0;
2015-07-09 18:09:45 +02:00
android->joypad = input_joypad_init_driver(
settings->input.joypad_driver, android);
input_keymaps_init_keyboard_lut(rarch_key_map_android);
2015-05-09 09:38:45 +02:00
frontend_android_get_version_sdk(&sdk);
RARCH_LOG("sdk version: %d\n", sdk);
2015-05-09 09:38:45 +02:00
if (sdk >= 19)
engine_lookup_name = android_input_lookup_name;
else
engine_lookup_name = android_input_lookup_name_prekitkat;
engine_handle_dpad = engine_handle_dpad_default;
if (!android_input_init_handle())
{
RARCH_WARN("Unable to open libandroid.so\n");
}
2015-12-08 13:47:46 +01:00
android_app->input_alive = true;
return android;
}
static INLINE int android_input_poll_event_type_motion(
2015-12-03 01:59:43 +01:00
android_input_data_t *android_data, AInputEvent *event,
int port, int source)
{
int getaction, action;
2015-07-09 18:09:45 +02:00
size_t motion_ptr;
bool keyup;
if (source & ~(AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_MOUSE))
return 1;
2015-07-09 18:09:45 +02:00
getaction = AMotionEvent_getAction(event);
action = getaction & AMOTION_EVENT_ACTION_MASK;
motion_ptr = getaction >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
keyup = (
action == AMOTION_EVENT_ACTION_UP ||
action == AMOTION_EVENT_ACTION_CANCEL ||
action == AMOTION_EVENT_ACTION_POINTER_UP) ||
(source == AINPUT_SOURCE_MOUSE &&
action != AMOTION_EVENT_ACTION_DOWN);
2015-07-09 18:09:45 +02:00
if (keyup && motion_ptr < MAX_TOUCH)
2014-06-11 08:23:00 +02:00
{
2015-12-02 22:12:43 +01:00
memmove(android_data->pointer + motion_ptr,
android_data->pointer + motion_ptr + 1,
2015-07-09 18:09:45 +02:00
(MAX_TOUCH - motion_ptr - 1) * sizeof(struct input_pointer));
2015-12-02 22:12:43 +01:00
if (android_data->pointer_count > 0)
android_data->pointer_count--;
2014-06-02 14:28:26 +02:00
}
else
{
float x, y;
2016-03-02 00:07:31 +01:00
int pointer_max = MIN(AMotionEvent_getPointerCount(event), MAX_TOUCH);
2015-07-09 18:09:45 +02:00
for (motion_ptr = 0; motion_ptr < pointer_max; motion_ptr++)
{
2015-07-09 18:09:45 +02:00
x = AMotionEvent_getX(event, motion_ptr);
y = AMotionEvent_getY(event, motion_ptr);
input_translate_coord_viewport(x, y,
2015-12-02 22:12:43 +01:00
&android_data->pointer[motion_ptr].x,
&android_data->pointer[motion_ptr].y,
&android_data->pointer[motion_ptr].full_x,
&android_data->pointer[motion_ptr].full_y);
2016-03-02 00:07:31 +01:00
android_data->pointer_count = MAX(
2015-12-02 22:12:43 +01:00
android_data->pointer_count,
2015-07-09 18:09:45 +02:00
motion_ptr + 1);
}
}
return 0;
}
bool is_keyboard_id(int id)
{
for(int i=0; i<kbd_num; i++)
if (id == kbd_id[i]) return true;
return false;
}
static INLINE void android_input_poll_event_type_keyboard(
AInputEvent *event, int keycode, int *handled)
{
int keydown = (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN);
unsigned keyboardcode = input_keymaps_translate_keysym_to_rk(keycode);
// Set keyboard modifier based on shift,ctrl and alt state
uint16_t mod = 0;
int meta = AKeyEvent_getMetaState(event);
if(meta & AMETA_ALT_ON) mod |= RETROKMOD_ALT;
if(meta & AMETA_CTRL_ON) mod |= RETROKMOD_CTRL;
if(meta & AMETA_SHIFT_ON) mod |= RETROKMOD_SHIFT;
input_keyboard_event(keydown, keyboardcode, keyboardcode, mod, RETRO_DEVICE_KEYBOARD);
if ((keycode == AKEYCODE_VOLUME_UP || keycode == AKEYCODE_VOLUME_DOWN))
*handled = 0;
}
static INLINE void android_input_poll_event_type_key(
2015-12-03 01:59:43 +01:00
struct android_app *android_app,
AInputEvent *event, int port, int keycode, int source,
int type_event, int *handled)
{
2015-11-29 16:18:29 +01:00
uint8_t *buf = android_keyboard_state_get(port);
int action = AKeyEvent_getAction(event);
/* some controllers send both the up and down events at once
* when the button is released for "special" buttons, like menu buttons
* work around that by only using down events for meta keys (which get
* cleared every poll anyway)
*/
2015-07-09 18:09:45 +02:00
switch (action)
{
case AKEY_EVENT_ACTION_UP:
BIT_CLEAR(buf, keycode);
break;
case AKEY_EVENT_ACTION_DOWN:
BIT_SET(buf, keycode);
break;
}
2014-06-02 14:28:26 +02:00
if ((keycode == AKEYCODE_VOLUME_UP || keycode == AKEYCODE_VOLUME_DOWN))
*handled = 0;
2014-06-02 14:28:26 +02:00
}
2015-12-02 22:12:43 +01:00
static int android_input_get_id_port(android_input_data_t *android_data, int id,
int source)
{
unsigned i;
int ret = -1;
if (source & (AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_MOUSE |
AINPUT_SOURCE_TOUCHPAD))
ret = 0; /* touch overlay is always user 1 */
2015-12-02 22:12:43 +01:00
for (i = 0; i < android_data->pads_connected; i++)
if (android_data->pad_states[i].id == id)
ret = i;
return ret;
}
/* Returns the index inside android->pad_state */
2015-12-02 22:12:43 +01:00
static int android_input_get_id_index_from_name(android_input_data_t *android_data,
const char *name)
{
int i;
2015-12-02 22:12:43 +01:00
for (i = 0; i < android_data->pads_connected; i++)
{
2016-01-21 02:48:00 +01:00
if (string_is_equal(name, android_data->pad_states[i].name))
return i;
}
return -1;
}
2015-12-02 22:12:43 +01:00
static void handle_hotplug(android_input_data_t *android_data,
struct android_app *android_app, int *port, int id,
2014-06-11 00:11:30 +02:00
int source)
{
2015-06-13 00:02:28 +02:00
char device_name[256] = {0};
char name_buf[256] = {0};
2015-07-09 17:55:52 +02:00
int vendorId = 0;
int productId = 0;
bool back_mapped = false;
2015-06-13 00:02:28 +02:00
settings_t *settings = config_get_ptr();
char device_model[256] = {0};
frontend_android_get_name(device_model, sizeof(device_model));
RARCH_LOG("Device model: (%s).\n", device_model);
2014-06-11 16:21:05 +02:00
if (*port > MAX_PADS)
{
RARCH_ERR("Max number of pads reached.\n");
return;
}
if (!engine_lookup_name(device_name, &vendorId, &productId, sizeof(device_name), id))
{
RARCH_ERR("Could not look up device name or IDs.\n");
return;
}
/* FIXME - per-device hacks for NVidia Shield, Xperia Play and
* similar devices
*
* These hacks depend on autoconf, but can work with user
* created autoconfs properly
*/
/* NVIDIA Shield Console
* This is the most complicated example, the built-in controller
* has an extra button that can't be used and a remote.
*
* We map the remote for navigation and overwrite whenever a
* real controller is connected.
* Also group the NVIDIA button on the controller with the
* main controller inputs so it's usable. It's mapped to
* menu by default
*
* The NVIDIA button is identified as "Virtual" device when first
* pressed. CEC remote input is also identified as "Virtual" device.
* If a virtual device is detected before a controller then it will
* be assigned to port 0 as "SHIELD Virtual Controller". When a real
* controller is detected it will overwrite the virtual controller
* and be grouped with the NVIDIA button of the virtual device.
*
*/
if(strstr(device_model, "SHIELD Android TV") && (
strstr(device_name, "Virtual") ||
strstr(device_name, "NVIDIA Corporation NVIDIA Controller v01.03")))
{
/* only use the hack if the device is one of the built-in devices */
RARCH_LOG("Special Device Detected: %s\n", device_model);
{
#if 0
RARCH_LOG("- Pads Mapped: %d\n- Device Name: %s\n- IDS: %d, %d, %d", android_data->pads_connected, device_name, id, pad_id1, pad_id2);
#endif
/* remove the remote or virtual controller device if it is mapped */
if (strstr(android_data->pad_states[0].name,"SHIELD Remote") ||
strstr(android_data->pad_states[0].name,"SHIELD Virtual Controller"))
{
pad_id1 = -1;
pad_id2 = -1;
android_data->pads_connected = 0;
*port = 0;
strlcpy(name_buf, device_name, sizeof(name_buf));
}
/* if the actual controller has not been mapped yet, then configure Virtual device for now */
if (strstr(device_name, "Virtual") && android_data->pads_connected==0)
strlcpy (name_buf, "SHIELD Virtual Controller", sizeof(name_buf));
else
strlcpy (name_buf, "NVIDIA SHIELD Controller", sizeof(name_buf));
/* apply the hack only for the first controller
* store the id for later use
*/
if (strstr(device_name, "NVIDIA Corporation NVIDIA Controller v01.03") && android_data->pads_connected==0)
pad_id1 = id;
else if (strstr(device_name, "Virtual") && pad_id1 != -1)
{
id = pad_id1;
return;
}
}
}
/* NVIDIA Shield Portable
* This is a simple hack, basically groups the "back"
* button with the rest of the gamepad
*/
else if(strstr(device_model, "SHIELD") && (
strstr(device_name, "Virtual") || strstr(device_name, "gpio") ||
strstr(device_name, "NVIDIA Corporation NVIDIA Controller v01.01")))
{
/* only use the hack if the device is one of the built-in devices */
RARCH_LOG("Special Device Detected: %s\n", device_model);
{
if ( pad_id1 < 0 )
pad_id1 = id;
else
pad_id2 = id;
if ( pad_id2 > 0)
return;
strlcpy (name_buf, "NVIDIA SHIELD Portable", sizeof(name_buf));
}
}
/* GPD XD
* This is a simple hack, basically groups the "back"
* button with the rest of the gamepad
*/
2015-12-09 10:00:32 -05:00
else if(strstr(device_model, "XD") && (
strstr(device_name, "Virtual") || strstr(device_name, "rk29-keypad") ||
strstr(device_name,"Playstation3") || strstr(device_name,"XBOX")))
{
/* only use the hack if the device is one of the built-in devices */
RARCH_LOG("Special Device Detected: %s\n", device_model);
{
if ( pad_id1 < 0 )
pad_id1 = id;
2015-12-09 10:00:32 -05:00
else
pad_id2 = id;
2015-12-09 10:00:32 -05:00
if ( pad_id2 > 0)
2015-12-09 10:00:32 -05:00
return;
strlcpy (name_buf, "GPD XD", sizeof(name_buf));
*port = 0;
}
}
/* XPERIA Play
* This device is composed of two hid devices
* We make it look like one device
*/
else if(strstr(device_model, "R800") && (
strstr(device_name, "keypad-game-zeus") || strstr(device_name, "keypad-zeus")))
{
/* only use the hack if the device is one of the built-in devices */
RARCH_LOG("Special Device Detected: %s\n", device_model);
{
if ( pad_id1 < 0 )
pad_id1 = id;
else
pad_id2 = id;
if ( pad_id2 > 0)
return;
strlcpy (name_buf, "XPERIA Play", sizeof(name_buf));
*port = 0;
}
}
/* ARCHOS Gamepad
* This device is composed of two hid devices
* We make it look like one device
*/
2015-12-09 10:00:32 -05:00
else if(strstr(device_model, "ARCHOS GAMEPAD") && (
strstr(device_name, "joy_key") || strstr(device_name, "joystick")))
{
/* only use the hack if the device is one of the built-in devices */
RARCH_LOG("ARCHOS GAMEPAD Detected: %s\n", device_model);
{
if ( pad_id1 < 0 )
pad_id1 = id;
2015-12-09 10:00:32 -05:00
else
pad_id2 = id;
2015-12-09 10:00:32 -05:00
if ( pad_id2 > 0)
2015-12-09 10:00:32 -05:00
return;
strlcpy (name_buf, "ARCHOS GamePad", sizeof(name_buf));
*port = 0;
}
}
/* Other uncommon devices
* These are mostly remote control type devices, bind them always to port 0
* And overwrite the binding whenever a controller button is pressed
*/
else if (strstr(device_name, "Amazon Fire TV Remote")
|| strstr(device_name, "Nexus Remote")
|| strstr(device_name, "SHIELD Remote"))
{
android_data->pads_connected = 0;
*port = 0;
strlcpy(name_buf, device_name, sizeof(name_buf));
}
else if (strstr(device_name, "iControlPad-"))
2014-08-13 23:04:59 +02:00
strlcpy(name_buf, "iControlPad HID Joystick profile", sizeof(name_buf));
else if (strstr(device_name, "TTT THT Arcade console 2P USB Play"))
{
if (*port == 0)
2015-01-05 02:03:17 +01:00
strlcpy(name_buf, "TTT THT Arcade (User 1)", sizeof(name_buf));
else if (*port == 1)
2015-01-05 02:03:17 +01:00
strlcpy(name_buf, "TTT THT Arcade (User 2)", sizeof(name_buf));
}
else if (strstr(device_name, "360 Wireless"))
strlcpy(name_buf, "XBox 360 Wireless", sizeof(name_buf));
else if (strstr(device_name, "Microsoft"))
{
2015-05-09 09:38:45 +02:00
if (strstr(device_name, "Dual Strike"))
strlcpy(device_name, "SideWinder Dual Strike", sizeof(device_name));
else if (strstr(device_name, "SideWinder"))
strlcpy(name_buf, "SideWinder Classic", sizeof(name_buf));
}
2015-07-16 03:22:28 -04:00
else if (
strstr(device_name, "PLAYSTATION(R)3") ||
strstr(device_name, "Dualshock3") ||
strstr(device_name, "Sixaxis")
)
strlcpy(name_buf, "PlayStation3", sizeof(name_buf));
2015-07-16 03:22:28 -04:00
else if (strstr(device_name, "MOGA"))
strlcpy(name_buf, "Moga IME", sizeof(name_buf));
// if device is keyboard only and didn't match any of the devices above
// then assume it is a keyboard, register the id, and return unless the
// maximum number of keyboards are already registered
else if(source == AINPUT_SOURCE_KEYBOARD && kbd_num < MAX_NUM_KEYBOARDS)
{
kbd_id[kbd_num] = id;
kbd_num++;
return;
}
// if device was not keyboard only, yet did not match any of the devices
// then try to autoconfigure as gamepad based on device_name
2015-12-26 07:54:17 +01:00
else if (!string_is_empty(device_name))
2014-08-13 22:02:31 +02:00
strlcpy(name_buf, device_name, sizeof(name_buf));
2015-05-09 09:38:45 +02:00
if (strstr(android_app->current_ime, "net.obsidianx.android.mogaime"))
strlcpy(name_buf, android_app->current_ime, sizeof(name_buf));
else if (strstr(android_app->current_ime, "com.ccpcreations.android.WiiUseAndroid"))
strlcpy(name_buf, android_app->current_ime, sizeof(name_buf));
else if (strstr(android_app->current_ime, "com.hexad.bluezime"))
strlcpy(name_buf, android_app->current_ime, sizeof(name_buf));
if (*port < 0)
*port = android_data->pads_connected;
2015-07-09 17:55:52 +02:00
if (settings->input.autodetect_enable)
{
bool autoconfigured;
2015-07-09 17:55:52 +02:00
autoconfig_params_t params = {{0}};
RARCH_LOG("Pads Connected: %d Port: %d\n %s VID/PID: %d/%d\n",android_data->pads_connected, *port, name_buf, params.vid, params.pid);
2015-07-09 17:55:52 +02:00
2015-05-09 09:38:45 +02:00
strlcpy(params.name, name_buf, sizeof(params.name));
2015-07-09 17:55:52 +02:00
params.idx = *port;
2015-03-27 16:57:58 +01:00
params.vid = vendorId;
params.pid = productId;
settings->input.pid[*port] = params.pid;
settings->input.vid[*port] = params.vid;
2015-05-09 09:38:45 +02:00
strlcpy(params.driver, android_joypad.ident, sizeof(params.driver));
autoconfigured = input_config_autoconfigure_joypad(&params);
if (autoconfigured)
{
if (settings->input.autoconf_binds[*port][RARCH_MENU_TOGGLE].joykey != 0)
back_mapped = true;
}
}
2015-12-26 07:54:17 +01:00
if (!string_is_empty(name_buf))
2015-12-12 20:56:42 -05:00
{
strlcpy(settings->input.device_names[*port],
name_buf, sizeof(settings->input.device_names[*port]));
}
if (!back_mapped && settings->input.back_as_menu_toggle_enable)
settings->input.autoconf_binds[*port][RARCH_MENU_TOGGLE].joykey = AKEYCODE_BACK;
2015-12-02 22:12:43 +01:00
android_data->pad_states[android_data->pads_connected].id = id;
android_data->pad_states[android_data->pads_connected].port = *port;
strlcpy(android_data->pad_states[*port].name, name_buf,
sizeof(android_data->pad_states[*port].name));
2015-12-02 22:12:43 +01:00
android_data->pads_connected++;
}
2015-12-03 01:59:43 +01:00
static int android_input_get_id(AInputEvent *event)
{
int id = AInputEvent_getDeviceId(event);
if (id == pad_id2)
id = pad_id1;
return id;
2014-06-21 06:43:21 +02:00
}
2015-11-28 18:39:43 +01:00
static void android_input_poll_input(void *data)
2015-04-21 02:58:12 +02:00
{
2015-05-09 09:38:45 +02:00
AInputEvent *event = NULL;
struct android_app *android_app = (struct android_app*)g_android;
2015-12-02 22:12:43 +01:00
android_input_t *android = (android_input_t*)data;
android_input_data_t *android_data = (android_input_data_t*)&android->thread;
2015-04-21 02:58:12 +02:00
/* Read all pending events. */
2015-05-09 09:38:45 +02:00
while (AInputQueue_hasEvents(android_app->inputQueue))
2015-04-21 02:58:12 +02:00
{
2015-05-09 09:38:45 +02:00
while (AInputQueue_getEvent(android_app->inputQueue, &event) >= 0)
{
2015-07-09 18:09:45 +02:00
int32_t handled = 1;
2015-05-09 09:38:45 +02:00
int predispatched = AInputQueue_preDispatchEvent(android_app->inputQueue, event);
2015-07-09 18:09:45 +02:00
int source = AInputEvent_getSource(event);
int type_event = AInputEvent_getType(event);
2015-12-03 01:59:43 +01:00
int id = android_input_get_id(event);
2015-12-02 22:12:43 +01:00
int port = android_input_get_id_port(android_data, id, source);
2015-05-09 09:38:45 +02:00
if (port < 0 && !is_keyboard_id(id))
2015-12-02 22:12:43 +01:00
handle_hotplug(android_data, android_app,
&port, id, source);
2015-05-09 09:38:45 +02:00
switch (type_event)
{
2015-05-09 09:38:45 +02:00
case AINPUT_EVENT_TYPE_MOTION:
2015-12-03 01:59:43 +01:00
if (android_input_poll_event_type_motion(android_data, event,
2015-05-09 09:38:45 +02:00
port, source))
engine_handle_dpad(android_data, event, port, source);
2015-05-09 09:38:45 +02:00
break;
case AINPUT_EVENT_TYPE_KEY:
{
int keycode = AKeyEvent_getKeyCode(event);
if (is_keyboard_id(id))
{
2016-02-08 01:53:33 +01:00
if (!predispatched)
{
android_input_poll_event_type_keyboard(event, keycode, &handled);
android_input_poll_event_type_key(android_app, event, ANDROID_KEYBOARD_PORT, keycode, source, type_event, &handled);
}
}
else
android_input_poll_event_type_key(android_app,
2015-05-09 09:38:45 +02:00
event, port, keycode, source, type_event, &handled);
}
break;
}
2015-05-09 09:38:45 +02:00
if (!predispatched)
AInputQueue_finishEvent(android_app->inputQueue, event,
handled);
}
}
2015-04-21 02:58:12 +02:00
}
2015-11-28 18:39:43 +01:00
static void android_input_poll_user(void *data)
2015-04-21 02:58:12 +02:00
{
2015-05-09 09:38:45 +02:00
struct android_app *android_app = (struct android_app*)g_android;
2015-12-02 22:12:43 +01:00
android_input_t *android = (android_input_t*)data;
android_input_data_t *android_data = (android_input_data_t*)&android->thread;
2015-04-21 02:58:12 +02:00
if ((android_app->sensor_state_mask & (UINT64_C(1) <<
2015-04-21 02:58:12 +02:00
RETRO_SENSOR_ACCELEROMETER_ENABLE))
2015-05-09 09:38:45 +02:00
&& android_app->accelerometerSensor)
2015-04-21 02:58:12 +02:00
{
ASensorEvent event;
while (ASensorEventQueue_getEvents(android_app->sensorEventQueue, &event, 1) > 0)
2015-04-21 02:58:12 +02:00
{
2015-12-02 22:12:43 +01:00
android_data->accelerometer_state.x = event.acceleration.x;
android_data->accelerometer_state.y = event.acceleration.y;
android_data->accelerometer_state.z = event.acceleration.z;
2015-04-21 02:58:12 +02:00
}
}
}
static void android_input_poll_memcpy(void *data)
{
unsigned i, j;
android_input_t *android = (android_input_t*)data;
struct android_app *android_app = (struct android_app*)g_android;
memcpy(&android->copy, &android->thread, sizeof(android->copy));
for (i = 0; i < MAX_PADS; i++)
{
for (j = 0; j < 2; j++)
android_app->hat_state[i][j] = android->copy.hat_state[i][j];
for (j = 0; j < MAX_AXIS; j++)
android_app->analog_state[i][j] = android->copy.analog_state[i][j];
}
}
2015-05-09 09:38:45 +02:00
/* Handle all events. If our activity is in pause state,
* block until we're unpaused.
*/
static void android_input_poll(void *data)
{
2015-05-09 09:38:45 +02:00
int ident;
2015-12-10 12:47:36 +01:00
unsigned key = RARCH_PAUSE_TOGGLE;
struct android_app *android_app = (struct android_app*)g_android;
while ((ident =
2015-12-10 12:47:36 +01:00
ALooper_pollAll((input_driver_ctl(RARCH_INPUT_CTL_KEY_PRESSED, &key))
? -1 : 1,
2015-05-09 09:38:45 +02:00
NULL, NULL, NULL)) >= 0)
{
2015-04-21 02:58:12 +02:00
switch (ident)
{
case LOOPER_ID_INPUT:
2015-11-28 18:39:43 +01:00
android_input_poll_input(data);
break;
case LOOPER_ID_USER:
2015-11-28 18:39:43 +01:00
android_input_poll_user(data);
break;
2015-04-21 02:58:12 +02:00
case LOOPER_ID_MAIN:
2015-11-28 18:39:43 +01:00
android_input_poll_main_cmd();
2015-04-21 02:58:12 +02:00
break;
}
if (android_app->destroyRequested != 0)
{
runloop_ctl(RUNLOOP_CTL_SET_SHUTDOWN, NULL);
return;
}
if (android_app->reinitRequested != 0)
{
if (runloop_ctl(RUNLOOP_CTL_IS_PAUSED, NULL))
event_cmd_ctl(EVENT_CMD_REINIT, NULL);
android_app_write_cmd(android_app, APP_CMD_REINIT_DONE);
return;
}
}
2015-12-08 13:47:46 +01:00
if (android_app->input_alive)
android_input_poll_memcpy(data);
2015-05-09 09:38:45 +02:00
}
2015-05-09 09:38:45 +02:00
bool android_run_events(void *data)
{
struct android_app *android_app = (struct android_app*)g_android;
if (ALooper_pollOnce(-1, NULL, NULL, NULL) == LOOPER_ID_MAIN)
2015-11-28 18:39:43 +01:00
android_input_poll_main_cmd();
2015-05-09 09:38:45 +02:00
/* Check if we are exiting. */
if (android_app->destroyRequested != 0)
{
runloop_ctl(RUNLOOP_CTL_SET_SHUTDOWN, NULL);
2015-05-09 09:38:45 +02:00
return false;
}
if (android_app->reinitRequested != 0)
{
if (runloop_ctl(RUNLOOP_CTL_IS_PAUSED, NULL))
event_cmd_ctl(EVENT_CMD_REINIT, NULL);
android_app_write_cmd(android_app, APP_CMD_REINIT_DONE);
}
2015-05-09 09:38:45 +02:00
return true;
2015-05-02 00:43:24 +02:00
}
static int16_t android_input_state(void *data,
const struct retro_keybind **binds, unsigned port, unsigned device,
2014-10-20 20:31:00 +02:00
unsigned idx, unsigned id)
{
settings_t *settings = config_get_ptr();
2015-12-02 22:12:43 +01:00
android_input_t *android = (android_input_t*)data;
android_input_data_t *android_data = (android_input_data_t*)&android->copy;
2012-12-17 20:53:36 +01:00
switch (device)
2012-10-28 22:20:22 +01:00
{
2012-12-17 20:53:36 +01:00
case RETRO_DEVICE_JOYPAD:
return input_joypad_pressed(android->joypad, port, binds[port], id) ||
android_keyboard_port_input_pressed(binds[port],id);
2013-07-31 19:04:28 +02:00
case RETRO_DEVICE_ANALOG:
2014-10-20 20:31:00 +02:00
return input_joypad_analog(android->joypad, port, idx, id,
binds[port]);
case RETRO_DEVICE_POINTER:
2013-07-31 19:04:28 +02:00
switch (id)
{
case RETRO_DEVICE_ID_POINTER_X:
2015-12-02 22:12:43 +01:00
return android_data->pointer[idx].x;
case RETRO_DEVICE_ID_POINTER_Y:
2015-12-02 22:12:43 +01:00
return android_data->pointer[idx].y;
case RETRO_DEVICE_ID_POINTER_PRESSED:
2015-12-02 22:12:43 +01:00
return (idx < android_data->pointer_count) &&
(android_data->pointer[idx].x != -0x8000) &&
(android_data->pointer[idx].y != -0x8000);
case RARCH_DEVICE_ID_POINTER_BACK:
if(settings->input.autoconf_binds[0][RARCH_MENU_TOGGLE].joykey == 0)
2015-11-29 16:18:29 +01:00
return android_keyboard_input_pressed(AKEYCODE_BACK);
}
break;
case RARCH_DEVICE_POINTER_SCREEN:
2013-07-31 19:04:28 +02:00
switch (id)
{
case RETRO_DEVICE_ID_POINTER_X:
2015-12-02 22:12:43 +01:00
return android_data->pointer[idx].full_x;
case RETRO_DEVICE_ID_POINTER_Y:
2015-12-02 22:12:43 +01:00
return android_data->pointer[idx].full_y;
case RETRO_DEVICE_ID_POINTER_PRESSED:
2015-12-02 22:12:43 +01:00
return (idx < android_data->pointer_count) &&
(android_data->pointer[idx].full_x != -0x8000) &&
(android_data->pointer[idx].full_y != -0x8000);
case RARCH_DEVICE_ID_POINTER_BACK:
if(settings->input.autoconf_binds[0][RARCH_MENU_TOGGLE].joykey == 0)
2015-11-29 16:18:29 +01:00
return android_keyboard_input_pressed(AKEYCODE_BACK);
}
break;
2012-12-17 20:53:36 +01:00
}
return 0;
}
2015-11-07 20:59:12 +01:00
static bool android_input_key_pressed(void *data, int key)
{
2014-06-10 21:59:18 +02:00
android_input_t *android = (android_input_t*)data;
settings_t *settings = config_get_ptr();
2015-03-20 22:32:09 +01:00
if(android_keyboard_port_input_pressed(settings->input.binds[0],key))
return true;
2015-10-23 08:34:15 +02:00
if (input_joypad_pressed(android->joypad,
0, settings->input.binds[0], key))
return true;
2015-10-23 08:34:15 +02:00
return false;
}
2015-11-07 20:59:12 +01:00
static bool android_input_meta_key_pressed(void *data, int key)
2015-07-17 03:31:51 +02:00
{
return false;
}
2012-11-27 00:50:29 +01:00
static void android_input_free_input(void *data)
{
2015-05-09 09:38:45 +02:00
android_input_t *android = (android_input_t*)data;
struct android_app *android_app = (struct android_app*)g_android;
2015-05-09 09:38:45 +02:00
if (!android)
return;
if (android_app->sensorManager)
ASensorManager_destroyEventQueue(android_app->sensorManager,
android_app->sensorEventQueue);
2015-12-02 19:28:15 +01:00
if (android->joypad)
android->joypad->destroy();
android->joypad = NULL;
2015-12-08 13:47:46 +01:00
android_app->input_alive = false;
dylib_close((dylib_t)libandroid_handle);
libandroid_handle = NULL;
2015-11-29 16:18:29 +01:00
android_keyboard_free();
free(data);
}
2013-11-02 21:50:38 +01:00
static uint64_t android_input_get_capabilities(void *data)
{
2014-10-05 18:08:22 +02:00
(void)data;
return
2014-10-05 18:08:22 +02:00
(1 << RETRO_DEVICE_JOYPAD) |
(1 << RETRO_DEVICE_POINTER) |
(1 << RETRO_DEVICE_ANALOG);
}
static void android_input_enable_sensor_manager(struct android_app *android_app)
{
android_app->sensorManager = ASensorManager_getInstance();
2015-05-09 09:38:45 +02:00
android_app->accelerometerSensor =
ASensorManager_getDefaultSensor(android_app->sensorManager,
ASENSOR_TYPE_ACCELEROMETER);
android_app->sensorEventQueue =
ASensorManager_createEventQueue(android_app->sensorManager,
android_app->looper, LOOPER_ID_USER, NULL, NULL);
}
static bool android_input_set_sensor_state(void *data, unsigned port,
enum retro_sensor_action action, unsigned event_rate)
{
2015-05-09 09:38:45 +02:00
struct android_app *android_app = (struct android_app*)g_android;
if (event_rate == 0)
event_rate = 60;
switch (action)
{
case RETRO_SENSOR_ACCELEROMETER_ENABLE:
2015-05-09 09:38:45 +02:00
if (!android_app->accelerometerSensor)
android_input_enable_sensor_manager(android_app);
2015-05-09 09:38:45 +02:00
if (android_app->accelerometerSensor)
ASensorEventQueue_enableSensor(android_app->sensorEventQueue,
2015-05-09 09:38:45 +02:00
android_app->accelerometerSensor);
2015-07-09 18:09:45 +02:00
/* Events per second (in microseconds). */
2015-05-09 09:38:45 +02:00
if (android_app->accelerometerSensor)
ASensorEventQueue_setEventRate(android_app->sensorEventQueue,
2015-05-09 09:38:45 +02:00
android_app->accelerometerSensor, (1000L / event_rate)
* 1000);
2015-07-09 18:09:45 +02:00
BIT64_CLEAR(android_app->sensor_state_mask, RETRO_SENSOR_ACCELEROMETER_DISABLE);
BIT64_SET(android_app->sensor_state_mask, RETRO_SENSOR_ACCELEROMETER_ENABLE);
return true;
case RETRO_SENSOR_ACCELEROMETER_DISABLE:
2015-05-09 09:38:45 +02:00
if (android_app->accelerometerSensor)
ASensorEventQueue_disableSensor(android_app->sensorEventQueue,
2015-05-09 09:38:45 +02:00
android_app->accelerometerSensor);
2015-07-09 18:09:45 +02:00
BIT64_CLEAR(android_app->sensor_state_mask, RETRO_SENSOR_ACCELEROMETER_ENABLE);
BIT64_SET(android_app->sensor_state_mask, RETRO_SENSOR_ACCELEROMETER_DISABLE);
return true;
default:
2015-05-09 09:38:45 +02:00
return false;
}
return false;
}
static float android_input_get_sensor_input(void *data,
unsigned port,unsigned id)
{
2015-12-02 22:12:43 +01:00
android_input_t *android = (android_input_t*)data;
android_input_data_t *android_data = (android_input_data_t*)&android->copy;
2014-01-20 14:59:06 +01:00
switch (id)
{
case RETRO_SENSOR_ACCELEROMETER_X:
2015-12-02 22:12:43 +01:00
return android_data->accelerometer_state.x;
case RETRO_SENSOR_ACCELEROMETER_Y:
2015-12-02 22:12:43 +01:00
return android_data->accelerometer_state.y;
case RETRO_SENSOR_ACCELEROMETER_Z:
2015-12-02 22:12:43 +01:00
return android_data->accelerometer_state.z;
}
return 0;
}
static const input_device_driver_t *android_input_get_joypad_driver(void *data)
{
2014-06-10 21:59:18 +02:00
android_input_t *android = (android_input_t*)data;
2015-01-11 00:07:59 +01:00
if (!android)
return NULL;
return android->joypad;
}
static bool android_input_keyboard_mapping_is_blocked(void *data)
{
android_input_t *android = (android_input_t*)data;
if (!android)
return false;
return android->blocked;
}
static void android_input_keyboard_mapping_set_block(void *data, bool value)
{
android_input_t *android = (android_input_t*)data;
if (!android)
return;
android->blocked = value;
}
static void android_input_grab_mouse(void *data, bool state)
{
(void)data;
(void)state;
}
static bool android_input_set_rumble(void *data, unsigned port,
enum retro_rumble_effect effect, uint16_t strength)
{
(void)data;
(void)port;
(void)effect;
(void)strength;
return false;
}
2014-09-11 07:06:20 +02:00
input_driver_t input_android = {
2012-11-27 00:50:29 +01:00
android_input_init,
android_input_poll,
android_input_state,
android_input_key_pressed,
2015-07-17 03:31:51 +02:00
android_input_meta_key_pressed,
2012-11-27 00:50:29 +01:00
android_input_free_input,
android_input_set_sensor_state,
android_input_get_sensor_input,
android_input_get_capabilities,
"android",
android_input_grab_mouse,
NULL,
android_input_set_rumble,
android_input_get_joypad_driver,
2015-11-16 02:39:38 +01:00
NULL,
android_input_keyboard_mapping_is_blocked,
android_input_keyboard_mapping_set_block,
};