From f70be6eb28a2ed6c6bfc23a14d6ad2cebfe1b95b Mon Sep 17 00:00:00 2001 From: Shinwoo Kim Date: Mon, 13 Jun 2016 19:41:38 +0900 Subject: [PATCH] Ecore_Input: define data type for joysticks Summary: This adds support for joysticks for ecore_input Reviewers: cedric, devilhorns, Sergeant_Whitespace, raster, thiepha, zmike, jpeg Reviewed By: thiepha, zmike, jpeg Subscribers: thiepha, stefan_schmidt, zmike, singh.amitesh, Sergeant_Whitespace, jgerecke, cedric, seoz Tags: #efl Differential Revision: https://phab.enlightenment.org/D1538 --- configure.ac | 259 ++++++------ src/Makefile_Ecore_Input.am | 1 + .../ecore/ecore_input_joystick_example.c | 61 +++ src/lib/ecore_input/Ecore_Input.h | 81 ++++ src/lib/ecore_input/ecore_input.c | 6 + src/lib/ecore_input/ecore_input_joystick.c | 386 ++++++++++++++++++ src/lib/ecore_input/ecore_input_private.h | 2 + 7 files changed, 668 insertions(+), 128 deletions(-) create mode 100644 src/examples/ecore/ecore_input_joystick_example.c create mode 100644 src/lib/ecore_input/ecore_input_joystick.c diff --git a/configure.ac b/configure.ac index 9b220f593b..f1cf8dfa42 100644 --- a/configure.ac +++ b/configure.ac @@ -3135,6 +3135,135 @@ EFL_LIB_END([Ecore_File]) #### End of Ecore_File +#### Eeze +have_libmount_new="no" +have_libmount_old="no" +have_eeze_mount="no" + +EFL_LIB_START_OPTIONAL([Eeze], [test "x${build_libeeze}" = "xyes"]) + +### Additional options to configure +AC_ARG_WITH([mount], + [AS_HELP_STRING([--with-mount], [specify mount bin @<:@default=detect@:>@])], + [with_eeze_mount=$withval], [with_eeze_mount="detect"]) +AC_ARG_WITH([umount], + [AS_HELP_STRING([--with-umount], [specify umount bin @<:@default=detect@:>@])], + [with_eeze_umount=$withval], [with_eeze_umount="detect"]) +AC_ARG_WITH([eject], + [AS_HELP_STRING([--with-eject], [specify eject bin @<:@default=detect@:>@])], + [with_eeze_eject=$withval], [with_eeze_eject="detect"]) + +### Default values + +### Checks for programs + +### Checks for libraries +EFL_INTERNAL_DEPEND_PKG([EEZE], [eina]) +EFL_INTERNAL_DEPEND_PKG([EEZE], [ecore]) +EFL_INTERNAL_DEPEND_PKG([EEZE], [eo]) +EFL_INTERNAL_DEPEND_PKG([EEZE], [efl]) +EFL_INTERNAL_DEPEND_PKG([EEZE], [ecore-file]) +EFL_INTERNAL_DEPEND_PKG([EEZE], [ecore-con]) +EFL_INTERNAL_DEPEND_PKG([EEZE], [eet]) +EFL_INTERNAL_DEPEND_PKG([EEZE], [emile]) + +EFL_DEPEND_PKG([EEZE], [UDEV], [libudev >= 148]) + +AC_ARG_ENABLE([libmount], + [AS_HELP_STRING([--disable-libmount],[disable libmount support. @<:@default=enabled@:>@])], + [ + if test "x${enableval}" = "xyes" ; then + want_libmount="yes" + else + want_libmount="no" + CFOPT_WARNING="xyes" + fi + ], + [want_libmount="yes"]) + +EFL_OPTIONAL_DEPEND_PKG([EEZE], [${want_libmount}], + [EEZE_MOUNT], [mount >= 2.18.0]) +EFL_ADD_FEATURE([EEZE], [libmount], [${have_eeze_mount}]) + +PKG_CHECK_EXISTS([libudev < 199], + [have_libudev_old="yes"], + [have_libudev_old="no"]) +AC_MSG_CHECKING([Use old libudev API (before 199)]) +AC_MSG_RESULT([${have_libudev_old}]) + +PKG_CHECK_EXISTS([mount < 2.19.0], + [have_libmount_old="yes"], + [have_libmount_old="no"]) +AC_MSG_CHECKING([Use old libmount API (before 2.19.0)]) +AC_MSG_RESULT([${have_libmount_old}]) + +PKG_CHECK_EXISTS([mount == 2.19.0], + [have_libmount_219="yes"], + [have_libmount_219="no"]) +AC_MSG_CHECKING([Use libmount 2.19.0 API]) +AC_MSG_RESULT([${have_libmount_219}]) + +PKG_CHECK_EXISTS([mount > 2.19.0], + [have_libmount_new="yes"], + [have_libmount_new="no"]) +AC_MSG_CHECKING([Use new libmount API (newer than 2.19.0)]) +AC_MSG_RESULT([${have_libmount_new}]) + +if test "x${have_libudev_old}" = "xyes"; then + AC_DEFINE_UNQUOTED([OLD_LIBUDEV], [1], [using older version of libudev]) +fi + +if test "x${have_libmount_old}" = "xyes"; then + AC_DEFINE_UNQUOTED([OLD_LIBMOUNT], [1], [using first version of libmount]) +fi + +## modules +if test "${want_tizen}" = "yes"; then + PKG_CHECK_MODULES([TIZEN_SENSOR], [capi-system-sensor >= 0.1.17]) +fi +EFL_ADD_FEATURE([EEZE], [tizen]) + +EFL_EVAL_PKGS([EEZE]) + +### Checks for header files + +### Checks for types + +### Checks for structures + +### Checks for compiler characteristics + +### Checks for linker characteristics + +### Checks for library functions + +### Checks for binaries +if test "x$with_eeze_mount" = "xdetect"; then + AC_PATH_PROG([with_eeze_mount], [mount], []) +fi +AC_DEFINE_UNQUOTED([EEZE_MOUNT_BIN], ["$with_eeze_mount"], [mount bin to use]) + +if test "x$with_eeze_umount" = "xdetect";then + AC_PATH_PROG([with_eeze_umount], [umount], []) +fi +AC_DEFINE_UNQUOTED([EEZE_UNMOUNT_BIN], ["$with_eeze_umount"], [umount bin to use]) + +if test "x$with_eeze_eject" = "xdetect";then + AC_PATH_PROG([with_eeze_eject], [eject], []) +fi +AC_DEFINE_UNQUOTED([EEZE_EJECT_BIN], ["$with_eeze_eject"], [eject bin to use]) + +EFL_LIB_END_OPTIONAL([Eeze]) + +AM_CONDITIONAL([EEZE_LIBMOUNT_AFTER_219], + [test "x${have_libmount_new}" = "xyes"]) +AM_CONDITIONAL([EEZE_LIBMOUNT_BEFORE_219], + [test "x${have_libmount_old}" = "xyes"]) +AM_CONDITIONAL([HAVE_EEZE_MOUNT], [test "x${have_eeze_mount}" = "xyes"]) +AM_CONDITIONAL([HAVE_EEZE_TIZEN], [test "x${want_tizen}" = "xyes"]) +#### End of Eeze + + #### Ecore_Input EFL_LIB_START([Ecore_Input]) @@ -3153,6 +3282,8 @@ EFL_INTERNAL_DEPEND_PKG([ECORE_INPUT], [eo]) EFL_INTERNAL_DEPEND_PKG([ECORE_INPUT], [efl]) EFL_INTERNAL_DEPEND_PKG([ECORE_INPUT], [eina]) +EFL_OPTIONAL_INTERNAL_DEPEND_PKG([ECORE_INPUT], [${efl_lib_optional_eeze}], [eeze]) + ### Checks for header files ### Checks for types @@ -3486,134 +3617,6 @@ EFL_LIB_END([Eldbus]) #### End of Eldbus -#### Eeze -have_libmount_new="no" -have_libmount_old="no" -have_eeze_mount="no" - -EFL_LIB_START_OPTIONAL([Eeze], [test "x${build_libeeze}" = "xyes"]) - -### Additional options to configure -AC_ARG_WITH([mount], - [AS_HELP_STRING([--with-mount], [specify mount bin @<:@default=detect@:>@])], - [with_eeze_mount=$withval], [with_eeze_mount="detect"]) -AC_ARG_WITH([umount], - [AS_HELP_STRING([--with-umount], [specify umount bin @<:@default=detect@:>@])], - [with_eeze_umount=$withval], [with_eeze_umount="detect"]) -AC_ARG_WITH([eject], - [AS_HELP_STRING([--with-eject], [specify eject bin @<:@default=detect@:>@])], - [with_eeze_eject=$withval], [with_eeze_eject="detect"]) - -### Default values - -### Checks for programs - -### Checks for libraries -EFL_INTERNAL_DEPEND_PKG([EEZE], [eina]) -EFL_INTERNAL_DEPEND_PKG([EEZE], [ecore]) -EFL_INTERNAL_DEPEND_PKG([EEZE], [eo]) -EFL_INTERNAL_DEPEND_PKG([EEZE], [efl]) -EFL_INTERNAL_DEPEND_PKG([EEZE], [ecore-file]) -EFL_INTERNAL_DEPEND_PKG([EEZE], [ecore-con]) -EFL_INTERNAL_DEPEND_PKG([EEZE], [eet]) -EFL_INTERNAL_DEPEND_PKG([EEZE], [emile]) - -EFL_DEPEND_PKG([EEZE], [UDEV], [libudev >= 148]) - -AC_ARG_ENABLE([libmount], - [AS_HELP_STRING([--disable-libmount],[disable libmount support. @<:@default=enabled@:>@])], - [ - if test "x${enableval}" = "xyes" ; then - want_libmount="yes" - else - want_libmount="no" - CFOPT_WARNING="xyes" - fi - ], - [want_libmount="yes"]) - -EFL_OPTIONAL_DEPEND_PKG([EEZE], [${want_libmount}], - [EEZE_MOUNT], [mount >= 2.18.0]) -EFL_ADD_FEATURE([EEZE], [libmount], [${have_eeze_mount}]) - -PKG_CHECK_EXISTS([libudev < 199], - [have_libudev_old="yes"], - [have_libudev_old="no"]) -AC_MSG_CHECKING([Use old libudev API (before 199)]) -AC_MSG_RESULT([${have_libudev_old}]) - -PKG_CHECK_EXISTS([mount < 2.19.0], - [have_libmount_old="yes"], - [have_libmount_old="no"]) -AC_MSG_CHECKING([Use old libmount API (before 2.19.0)]) -AC_MSG_RESULT([${have_libmount_old}]) - -PKG_CHECK_EXISTS([mount == 2.19.0], - [have_libmount_219="yes"], - [have_libmount_219="no"]) -AC_MSG_CHECKING([Use libmount 2.19.0 API]) -AC_MSG_RESULT([${have_libmount_219}]) - -PKG_CHECK_EXISTS([mount > 2.19.0], - [have_libmount_new="yes"], - [have_libmount_new="no"]) -AC_MSG_CHECKING([Use new libmount API (newer than 2.19.0)]) -AC_MSG_RESULT([${have_libmount_new}]) - -if test "x${have_libudev_old}" = "xyes"; then - AC_DEFINE_UNQUOTED([OLD_LIBUDEV], [1], [using older version of libudev]) -fi - -if test "x${have_libmount_old}" = "xyes"; then - AC_DEFINE_UNQUOTED([OLD_LIBMOUNT], [1], [using first version of libmount]) -fi - -## modules -if test "${want_tizen}" = "yes"; then - PKG_CHECK_MODULES([TIZEN_SENSOR], [capi-system-sensor >= 0.1.17]) -fi -EFL_ADD_FEATURE([EEZE], [tizen]) - -EFL_EVAL_PKGS([EEZE]) - -### Checks for header files - -### Checks for types - -### Checks for structures - -### Checks for compiler characteristics - -### Checks for linker characteristics - -### Checks for library functions - -### Checks for binaries -if test "x$with_eeze_mount" = "xdetect"; then - AC_PATH_PROG([with_eeze_mount], [mount], []) -fi -AC_DEFINE_UNQUOTED([EEZE_MOUNT_BIN], ["$with_eeze_mount"], [mount bin to use]) - -if test "x$with_eeze_umount" = "xdetect";then - AC_PATH_PROG([with_eeze_umount], [umount], []) -fi -AC_DEFINE_UNQUOTED([EEZE_UNMOUNT_BIN], ["$with_eeze_umount"], [umount bin to use]) - -if test "x$with_eeze_eject" = "xdetect";then - AC_PATH_PROG([with_eeze_eject], [eject], []) -fi -AC_DEFINE_UNQUOTED([EEZE_EJECT_BIN], ["$with_eeze_eject"], [eject bin to use]) - -EFL_LIB_END_OPTIONAL([Eeze]) - -AM_CONDITIONAL([EEZE_LIBMOUNT_AFTER_219], - [test "x${have_libmount_new}" = "xyes"]) -AM_CONDITIONAL([EEZE_LIBMOUNT_BEFORE_219], - [test "x${have_libmount_old}" = "xyes"]) -AM_CONDITIONAL([HAVE_EEZE_MOUNT], [test "x${have_eeze_mount}" = "xyes"]) -AM_CONDITIONAL([HAVE_EEZE_TIZEN], [test "x${want_tizen}" = "xyes"]) -#### End of Eeze - #### Ecore_Drm have_libinput_new="no" diff --git a/src/Makefile_Ecore_Input.am b/src/Makefile_Ecore_Input.am index 2b7aaba307..a664cfba6d 100644 --- a/src/Makefile_Ecore_Input.am +++ b/src/Makefile_Ecore_Input.am @@ -11,6 +11,7 @@ lib/ecore_input/Ecore_Input.h lib_ecore_input_libecore_input_la_SOURCES = \ lib/ecore_input/ecore_input.c \ lib/ecore_input/ecore_input_compose.c \ +lib/ecore_input/ecore_input_joystick.c \ lib/ecore_input/ecore_input_compose.h \ lib/ecore_input/ecore_input_private.h diff --git a/src/examples/ecore/ecore_input_joystick_example.c b/src/examples/ecore/ecore_input_joystick_example.c new file mode 100644 index 0000000000..ecf3433427 --- /dev/null +++ b/src/examples/ecore/ecore_input_joystick_example.c @@ -0,0 +1,61 @@ +//Compile with: +// gcc -g -Wall -o ecore_input_joystick_example ecore_input_joystick_example.c `pkg-config --cflags --libs ecore ecore-input` + +#include +#include + +static Eina_Bool +_joystick_event_handler_cb(void *data, int type EINA_UNUSED, void *event) +{ + Ecore_Event_Joystick *ev = event; + switch (ev->type) + { + case ECORE_EVENT_JOYSTICK_EVENT_TYPE_CONNECTED: + printf("joystick is connected: %d\n", ev->index); + break; + case ECORE_EVENT_JOYSTICK_EVENT_TYPE_DISCONNECTED: + printf("joystick is disconnected: %d\n", ev->index); + break; + case ECORE_EVENT_JOYSTICK_EVENT_TYPE_BUTTON: + printf("joystick(%d) button index: %d, value: %f, time: %u\n", + ev->index, ev->button.index, + ev->button.value, ev->timestamp); + break; + case ECORE_EVENT_JOYSTICK_EVENT_TYPE_AXIS: + printf("joystick(%d) axis index: %d, value: %f, time: %u\n", + ev->index, ev->axis.index, + ev->axis.value, ev->timestamp); + break; + default: + printf("unhandled event type: %d\n", ev->type); + break; + } + + if (ev->type == ECORE_EVENT_JOYSTICK_EVENT_TYPE_BUTTON && + ev->button.index == ECORE_EVENT_JOYSTICK_BUTTON_START) + ecore_main_loop_quit(); + + return ECORE_CALLBACK_DONE; +} + +int +main(void) +{ + if (!ecore_event_init()) + { + printf("ERROR: Cannot init Ecore!\n"); + return -1; + } + + ecore_event_handler_add(ECORE_EVENT_JOYSTICK, + _joystick_event_handler_cb, + NULL); + + printf("start the main loop.\n"); + + ecore_main_loop_begin(); + + ecore_shutdown(); + + return 0; +} diff --git a/src/lib/ecore_input/Ecore_Input.h b/src/lib/ecore_input/Ecore_Input.h index c7a74a9d4c..45f6c387bd 100644 --- a/src/lib/ecore_input/Ecore_Input.h +++ b/src/lib/ecore_input/Ecore_Input.h @@ -55,6 +55,7 @@ extern "C" { EAPI extern int ECORE_EVENT_MOUSE_OUT; EAPI extern int ECORE_EVENT_AXIS_UPDATE; /**< @since 1.13 */ EAPI extern int ECORE_EVENT_MOUSE_BUTTON_CANCEL; /**< @since 1.15 */ + EAPI extern int ECORE_EVENT_JOYSTICK; /**< @since 1.18 */ #define ECORE_EVENT_MODIFIER_SHIFT 0x0001 #define ECORE_EVENT_MODIFIER_CTRL 0x0002 @@ -82,6 +83,7 @@ extern "C" { typedef struct _Ecore_Event_Modifiers Ecore_Event_Modifiers; typedef struct _Ecore_Event_Axis_Update Ecore_Event_Axis_Update; /**< @since 1.13 */ typedef struct _Ecore_Axis Ecore_Axis; /**< @since 1.13 */ + typedef struct _Ecore_Event_Joystick Ecore_Event_Joystick; /**< @since 1.18 */ /** * @typedef Ecore_Event_Modifier @@ -132,6 +134,59 @@ extern "C" { ECORE_COMPOSE_DONE } Ecore_Compose_State; + /** + * @struct _Ecore_Event_Joystic_Button + * Contains information about a joystick button event. + */ + typedef enum _Ecore_Event_Joystick_Button + { + ECORE_EVENT_JOYSTICK_BUTTON_NONE, + ECORE_EVENT_JOYSTICK_BUTTON_FACE_0, + ECORE_EVENT_JOYSTICK_BUTTON_FACE_1, + ECORE_EVENT_JOYSTICK_BUTTON_FACE_2, + ECORE_EVENT_JOYSTICK_BUTTON_FACE_3, + ECORE_EVENT_JOYSTICK_BUTTON_LEFT_SHOULDER, + ECORE_EVENT_JOYSTICK_BUTTON_RIGHT_SHOULDER, + ECORE_EVENT_JOYSTICK_BUTTON_SELECT, + ECORE_EVENT_JOYSTICK_BUTTON_START, + ECORE_EVENT_JOYSTICK_BUTTON_LEFT_ANALOG_STICK, + ECORE_EVENT_JOYSTICK_BUTTON_RIGHT_ANALOG_STICK, + ECORE_EVENT_JOYSTICK_BUTTON_META, + ECORE_EVENT_JOYSTICK_BUTTON_LAST + } Ecore_Event_Joystick_Button; /**< @since 1.18 */ + + /** + * @struct _Ecore_Event_Joystic_Axis + * Contains information about a joystick axis event. + */ + typedef enum _Ecore_Event_Joystick_Axis + { + ECORE_EVENT_JOYSTICK_AXIS_NONE, + ECORE_EVENT_JOYSTICK_AXIS_HAT_X, + ECORE_EVENT_JOYSTICK_AXIS_HAT_Y, + ECORE_EVENT_JOYSTICK_AXIS_LEFT_SHOULDER, + ECORE_EVENT_JOYSTICK_AXIS_RIGHT_SHOULDER, + ECORE_EVENT_JOYSTICK_AXIS_LEFT_ANALOG_HOR, + ECORE_EVENT_JOYSTICK_AXIS_LEFT_ANALOG_VER, + ECORE_EVENT_JOYSTICK_AXIS_RIGHT_ANALOG_HOR, + ECORE_EVENT_JOYSTICK_AXIS_RIGHT_ANALOG_VER, + ECORE_EVENT_JOYSTICK_AXIS_LAST + } Ecore_Event_Joystick_Axis; /**< @since 1.18 */ + + /** + * @struct _Ecore_Event_Joystic_Event_Type + * Contains information about a joystick event type. + */ + typedef enum _Ecore_Event_Joystick_Event + { + ECORE_EVENT_JOYSTICK_EVENT_TYPE_NONE, + ECORE_EVENT_JOYSTICK_EVENT_TYPE_CONNECTED, + ECORE_EVENT_JOYSTICK_EVENT_TYPE_DISCONNECTED, + ECORE_EVENT_JOYSTICK_EVENT_TYPE_BUTTON, + ECORE_EVENT_JOYSTICK_EVENT_TYPE_AXIS, + ECORE_EVENT_JOYSTICK_EVENT_TYPE_LAST + } Ecore_Event_Joystick_Event_Type; /**< @since 1.18 */ + /** * @struct _Ecore_Event_Key * Contains information about an Ecore keyboard event. @@ -313,6 +368,32 @@ extern "C" { unsigned int array[ECORE_LAST]; }; + /** + * @struct _Ecore_Event_Joystick + * Contains information about a joystick event. + */ + struct _Ecore_Event_Joystick + { + Ecore_Event_Joystick_Event_Type type; + unsigned int index; + unsigned int timestamp; + + union + { + struct + { + Ecore_Event_Joystick_Axis index; + double value; /* [-1.0 .. 1.0] -1.0 == up or left, 1.0 == down or right */ + } axis; + + struct + { + Ecore_Event_Joystick_Button index; + double value; /* [0.0 .. 1.0] 0.0 == fully unpressed, 1.0 == fully pressed */ + } button; + }; + }; + /** * Initialises the Ecore Event system. */ diff --git a/src/lib/ecore_input/ecore_input.c b/src/lib/ecore_input/ecore_input.c index 6b52eff631..32441ddb9f 100644 --- a/src/lib/ecore_input/ecore_input.c +++ b/src/lib/ecore_input/ecore_input.c @@ -24,6 +24,7 @@ EAPI int ECORE_EVENT_MOUSE_IN = 0; EAPI int ECORE_EVENT_MOUSE_OUT = 0; EAPI int ECORE_EVENT_AXIS_UPDATE = 0; EAPI int ECORE_EVENT_MOUSE_BUTTON_CANCEL = 0; +EAPI int ECORE_EVENT_JOYSTICK = 0; static int _ecore_event_init_count = 0; @@ -56,6 +57,9 @@ ecore_event_init(void) ECORE_EVENT_MOUSE_OUT = ecore_event_type_new(); ECORE_EVENT_AXIS_UPDATE = ecore_event_type_new(); ECORE_EVENT_MOUSE_BUTTON_CANCEL = ecore_event_type_new(); + ECORE_EVENT_JOYSTICK = ecore_event_type_new(); + + ecore_input_joystick_init(); return _ecore_event_init_count; } @@ -76,6 +80,8 @@ ecore_event_shutdown(void) ECORE_EVENT_MOUSE_OUT = 0; ECORE_EVENT_AXIS_UPDATE = 0; ECORE_EVENT_MOUSE_BUTTON_CANCEL = 0; + ECORE_EVENT_JOYSTICK = 0; + ecore_input_joystick_shutdown(); eina_log_domain_unregister(_ecore_input_log_dom); _ecore_input_log_dom = -1; ecore_shutdown(); diff --git a/src/lib/ecore_input/ecore_input_joystick.c b/src/lib/ecore_input/ecore_input_joystick.c new file mode 100644 index 0000000000..1f65ce48db --- /dev/null +++ b/src/lib/ecore_input/ecore_input_joystick.c @@ -0,0 +1,386 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +/*FIXME: change OS specific value */ +#ifdef __linux__ +# include +#endif + +#include +#include +#include + +#ifdef HAVE_EEZE + #include "Eeze.h" +#endif +#include "Ecore.h" +#include "Ecore_Input.h" +#include "ecore_input_private.h" + +static int _ecore_input_joystick_init_count = 0; + +#ifdef HAVE_EEZE + +typedef void (*Joystick_Mapper)(struct js_event *event, Ecore_Event_Joystick *e); +static void _joystick_xiinput_mapper(struct js_event *event, Ecore_Event_Joystick *e); + +struct _Joystick_Info +{ + Ecore_Fd_Handler *fd_handler; + Eina_Stringshare *system_path; + int index; + Joystick_Mapper mapper; +}; +typedef struct _Joystick_Info Joystick_Info; + +struct _Joystick_Mapping_Info +{ + const char *vendor; + const char *product; + Joystick_Mapper mapper; +} Joystick_Mapping_Info[] = {{"045e", "028e", _joystick_xiinput_mapper}}; + +static const char joystickPrefix[] = "/dev/input/js"; +static Eina_List *joystick_list; +static Eeze_Udev_Watch *watch = NULL; + +static void +_joystick_connected_event_add(int index, Eina_Bool connected) +{ + Ecore_Event_Joystick *e; + if (!(e = calloc(1, sizeof(Ecore_Event_Joystick)))) return; + + e->index = index; + if (connected) + e->type = ECORE_EVENT_JOYSTICK_EVENT_TYPE_CONNECTED; + else + e->type = ECORE_EVENT_JOYSTICK_EVENT_TYPE_DISCONNECTED; + + INF("index: %d, connected: %d", index, connected); + ecore_event_add(ECORE_EVENT_JOYSTICK, e, NULL, NULL); +} + +static void +_joystick_xiinput_mapper(struct js_event *event, Ecore_Event_Joystick *e) +{ + if (event->type == JS_EVENT_BUTTON) + { + e->type = ECORE_EVENT_JOYSTICK_EVENT_TYPE_BUTTON; + e->button.value = event->value; + switch (event->number) + { + case 0: + e->button.index = ECORE_EVENT_JOYSTICK_BUTTON_FACE_0; + break; + + case 1: + e->button.index = ECORE_EVENT_JOYSTICK_BUTTON_FACE_1; + break; + + case 2: + e->button.index = ECORE_EVENT_JOYSTICK_BUTTON_FACE_2; + break; + + case 3: + e->button.index = ECORE_EVENT_JOYSTICK_BUTTON_FACE_3; + break; + + case 4: + e->button.index = ECORE_EVENT_JOYSTICK_BUTTON_LEFT_SHOULDER; + break; + + case 5: + e->button.index = ECORE_EVENT_JOYSTICK_BUTTON_RIGHT_SHOULDER; + break; + + case 6: + e->button.index = ECORE_EVENT_JOYSTICK_BUTTON_SELECT; + break; + + case 7: + e->button.index = ECORE_EVENT_JOYSTICK_BUTTON_START; + break; + + case 8: + e->button.index = ECORE_EVENT_JOYSTICK_BUTTON_META; + break; + + case 9: + e->button.index = ECORE_EVENT_JOYSTICK_BUTTON_LEFT_ANALOG_STICK; + break; + + case 10: + e->button.index = ECORE_EVENT_JOYSTICK_BUTTON_RIGHT_ANALOG_STICK; + break; + + default: + ERR("Unsupported joystick event: %d", event->number); + break; + } + } + else + { + e->type = ECORE_EVENT_JOYSTICK_EVENT_TYPE_AXIS; + e->axis.value = event->value / 32767.0f;; + switch (event->number) + { + case 0: + e->axis.index = ECORE_EVENT_JOYSTICK_AXIS_LEFT_ANALOG_HOR; + break; + + case 1: + e->axis.index = ECORE_EVENT_JOYSTICK_AXIS_LEFT_ANALOG_VER; + break; + + case 2: + e->axis.index = ECORE_EVENT_JOYSTICK_AXIS_LEFT_SHOULDER; + break; + + case 3: + e->axis.index = ECORE_EVENT_JOYSTICK_AXIS_RIGHT_ANALOG_HOR; + break; + + case 4: + e->axis.index = ECORE_EVENT_JOYSTICK_AXIS_RIGHT_ANALOG_VER; + break; + + case 5: + e->axis.index = ECORE_EVENT_JOYSTICK_AXIS_RIGHT_SHOULDER; + break; + + case 6: + e->axis.index = ECORE_EVENT_JOYSTICK_AXIS_HAT_X; + break; + + case 7: + e->axis.index = ECORE_EVENT_JOYSTICK_AXIS_HAT_Y; + break; + + default: + ERR("Unsupported joystick event: %d", event->number); + break; + } + } +} + +static void +_joystick_event_add(struct js_event *event, Joystick_Info *ji) +{ + Ecore_Event_Joystick *e; + + if ((event->type != JS_EVENT_BUTTON) && (event->type != JS_EVENT_AXIS)) return; + if (!(e = calloc(1, sizeof(Ecore_Event_Joystick)))) return; + + e->index = ji->index; + e->timestamp = event->time; + + ji->mapper(event, e); + + ecore_event_add(ECORE_EVENT_JOYSTICK, e, NULL, NULL); +} + +static Eina_Bool +_fd_handler_cb(void* userData, Ecore_Fd_Handler* fdHandler) +{ + int fd; + Joystick_Info *ji = userData; + struct js_event event; + ssize_t len; + + fd = ecore_main_fd_handler_fd_get(fdHandler); + + len = read(fd, &event, sizeof(event)); + if (len == -1) return ECORE_CALLBACK_RENEW; + + INF("index: %d, type: %d, number: %d, value: %d", + ji->index, event.type, event.number, event.value); + + _joystick_event_add(&event, ji); + + return ECORE_CALLBACK_RENEW; +} + +static Joystick_Mapper +_joystick_mapping_info_get(const char* syspath) +{ + int index, mapping_info_size; + const char *parent, *vendor, *product; + Joystick_Mapper ret; + + ret = NULL; + parent = eeze_udev_syspath_get_parent_filtered(syspath, "input", NULL); + vendor = eeze_udev_syspath_get_sysattr(parent, "id/vendor"); + product = eeze_udev_syspath_get_sysattr(parent, "id/product"); + + mapping_info_size = (int)(sizeof(Joystick_Mapping_Info) / sizeof(Joystick_Mapping_Info[0])); + for (index = 0; index < mapping_info_size; index++) + { + if ((vendor && !strcmp(vendor, Joystick_Mapping_Info[index].vendor)) && + (product && !strcmp(product, Joystick_Mapping_Info[index].product))) + { + INF("joystick mapping info found (vendor: %s, product: %s)", vendor, product); + ret = Joystick_Mapping_Info[index].mapper; + break; + } + } + + eina_stringshare_del(parent); + eina_stringshare_del(vendor); + eina_stringshare_del(product); + + return ret; +} + +static int +_joystick_index_get(const char *dev) +{ + int plen, dlen, diff, ret = -1; + + dlen = strlen(dev); + plen = strlen(joystickPrefix); + diff = dlen - plen; + + if (diff > 0) + { + ret = atoi(dev + plen); + } + + return ret; +} + +static void +_joystick_register(const char* syspath) +{ + int fd, index; + const char *devnode; + Joystick_Info *ji; + Joystick_Mapper mapper; + + devnode = eeze_udev_syspath_get_devpath(syspath); + if (!devnode) return; + if (!eina_str_has_prefix(devnode, joystickPrefix)) goto register_failed; + + mapper = _joystick_mapping_info_get(syspath); + if (!mapper) + { + ERR("Unsupported joystick."); + goto register_failed; + } + + index = _joystick_index_get(devnode); + if (index == -1) + { + ERR("Invalid index value."); + goto register_failed; + } + + ji = calloc(1, sizeof(Joystick_Info)); + if (!ji) + { + ERR("Cannot allocate memory."); + goto register_failed; + } + + ji->index = index; + ji->mapper = mapper; + ji->system_path = eina_stringshare_ref(syspath); + + fd = open(devnode, O_RDONLY | O_NONBLOCK); + ji->fd_handler = ecore_main_fd_handler_add(fd, ECORE_FD_READ, + _fd_handler_cb, ji, 0, 0); + + joystick_list = eina_list_append(joystick_list, ji); + _joystick_connected_event_add(index, EINA_TRUE); + +register_failed: + eina_stringshare_del(devnode); +} + +static void +_joystick_unregister(const char *syspath) +{ + int fd; + Eina_List *l, *l2; + Joystick_Info *ji; + + EINA_LIST_FOREACH_SAFE(joystick_list, l, l2, ji) + { + if (syspath == ji->system_path) + { + fd = ecore_main_fd_handler_fd_get(ji->fd_handler); + close(fd); + ecore_main_fd_handler_del(ji->fd_handler); + joystick_list = eina_list_remove(joystick_list, ji); + _joystick_connected_event_add(ji->index, EINA_FALSE); + eina_stringshare_del(ji->system_path); + free(ji); + break; + } + } +} + +static void +_watch_cb(const char *syspath, Eeze_Udev_Event event, + void *data EINA_UNUSED, Eeze_Udev_Watch *w EINA_UNUSED) +{ + switch (event) { + case EEZE_UDEV_EVENT_ADD: + _joystick_register(syspath); + break; + case EEZE_UDEV_EVENT_REMOVE: + _joystick_unregister(syspath); + break; + default: + break; + } + + eina_stringshare_del(syspath); +} +#endif + +int +ecore_input_joystick_init(void) +{ +#ifdef HAVE_EEZE + Eina_List *syspaths; + const char *syspath; + + if (++_ecore_input_joystick_init_count != 1) + return _ecore_input_joystick_init_count; + + if (!eeze_init()) + return --_ecore_input_joystick_init_count; + + watch = eeze_udev_watch_add(EEZE_UDEV_TYPE_JOYSTICK, + (EEZE_UDEV_EVENT_ADD | EEZE_UDEV_EVENT_REMOVE), + _watch_cb, NULL); + + syspaths = eeze_udev_find_by_type(EEZE_UDEV_TYPE_JOYSTICK, NULL); + EINA_LIST_FREE(syspaths, syspath) + { + _joystick_register(syspath); + eina_stringshare_del(syspath); + } +#endif + + return _ecore_input_joystick_init_count; +} + +int +ecore_input_joystick_shutdown(void) +{ +#ifdef HAVE_EEZE + if (--_ecore_input_joystick_init_count != 0) + return _ecore_input_joystick_init_count; + + if (watch) + { + eeze_udev_watch_del(watch); + watch = NULL; + } + eeze_shutdown(); +#endif + + return _ecore_input_joystick_init_count; +} diff --git a/src/lib/ecore_input/ecore_input_private.h b/src/lib/ecore_input/ecore_input_private.h index 70af2276e7..4d085a19b4 100644 --- a/src/lib/ecore_input/ecore_input_private.h +++ b/src/lib/ecore_input/ecore_input_private.h @@ -34,4 +34,6 @@ extern int _ecore_input_log_dom; #endif #define CRI(...) EINA_LOG_DOM_CRIT(_ecore_input_log_dom, __VA_ARGS__) +int ecore_input_joystick_init(void); +int ecore_input_joystick_shutdown(void); #endif