From 863df65c10b1d0f1e62ad45ba8ab3afaf2273537 Mon Sep 17 00:00:00 2001 From: Shinwoo Kim Date: Mon, 20 Apr 2015 11:53:16 +0900 Subject: [PATCH] [ecore_input] initial version of ecore joystick event Conflicts: src/lib/ecore_input/Ecore_Input.h src/lib/ecore_input/ecore_input.c Change-Id: Ibabaa70deac03b34bc20e08afb315071041c10c0 --- configure.ac | 1 + src/Makefile_Ecore_Input.am | 1 + src/examples/ecore/ecore_input_joystick_example.c | 64 ++++ src/lib/ecore_input/Ecore_Input.h | 93 ++++- src/lib/ecore_input/ecore_input.c | 3 + src/lib/ecore_input/ecore_input_joystick.c | 391 ++++++++++++++++++++++ src/tests/ecore/ecore_test_ecore_input.c | 30 ++ 7 files changed, 582 insertions(+), 1 deletion(-) 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 6b88da8..db45c51 100755 --- a/configure.ac +++ b/configure.ac @@ -2793,6 +2793,7 @@ EFL_INTERNAL_DEPEND_PKG([ECORE_INPUT], [ecore]) EFL_INTERNAL_DEPEND_PKG([ECORE_INPUT], [eo]) EFL_INTERNAL_DEPEND_PKG([ECORE_INPUT], [eina]) +EFL_ADD_LIBS([ECORE_INPUT], [-ludev]) ### Checks for header files ### Checks for types diff --git a/src/Makefile_Ecore_Input.am b/src/Makefile_Ecore_Input.am index 2b7aaba..a664cfb 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 0000000..0486ecd --- /dev/null +++ b/src/examples/ecore/ecore_input_joystick_example.c @@ -0,0 +1,64 @@ +//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); + + ecore_input_joystick_init(); + + printf("start the main loop.\n"); + + ecore_main_loop_begin(); + + ecore_input_joystick_shutdown(); + ecore_shutdown(); + + return 0; +} diff --git a/src/lib/ecore_input/Ecore_Input.h b/src/lib/ecore_input/Ecore_Input.h index 70318ce..d91a943 100644 --- a/src/lib/ecore_input/Ecore_Input.h +++ b/src/lib/ecore_input/Ecore_Input.h @@ -59,6 +59,7 @@ extern "C" { EAPI extern int ECORE_EVENT_DEVICE_ADD; EAPI extern int ECORE_EVENT_DEVICE_DEL; EAPI extern int ECORE_EVENT_DETENT_ROTATE; //TIZEN ONLY + EAPI extern int ECORE_EVENT_JOYSTICK; /**< @since 1.15 */ #define ECORE_EVENT_MODIFIER_SHIFT 0x0001 #define ECORE_EVENT_MODIFIER_CTRL 0x0002 @@ -88,6 +89,7 @@ extern "C" { typedef struct _Ecore_Axis Ecore_Axis; /**< @since 1.13 */ typedef struct _Ecore_Event_Device_Info Ecore_Event_Device_Info; typedef struct _Ecore_Event_Detent_Rotate Ecore_Event_Detent_Rotate; //TIZEN ONLY + typedef struct _Ecore_Event_Joystick Ecore_Event_Joystick; /**< @since 1.15 */ /** * @typedef Ecore_Event_Modifier @@ -155,6 +157,58 @@ extern "C" { }; /** + * @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_LAST + } Ecore_Event_Joystick_Button; /**< @since 1.15 */ + + /** + * @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.15 */ + + /** + * @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.15 */ + + /** * @struct _Ecore_Event_Key * Contains information about an Ecore keyboard event. */ @@ -353,6 +407,32 @@ extern "C" { }; /** + * @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. */ EAPI int ecore_event_init(void); @@ -394,7 +474,18 @@ extern "C" { * @return The status of the composition. */ EAPI Ecore_Compose_State ecore_compose_get(const Eina_List *seq, char **seqstr_ret); - +//TIZEN_ONLY(20160627) - Initial version of ecore joystick event + /** + * Initialises the Ecore Input Joystick system. + * @since 1.15 + */ + EAPI int ecore_input_joystick_init(void); + /** + * Shutdowns the Ecore Input Joystick system. + * @since 1.15 + */ + EAPI int ecore_input_joystick_shutdown(void); +// #ifdef __cplusplus } #endif diff --git a/src/lib/ecore_input/ecore_input.c b/src/lib/ecore_input/ecore_input.c index bd5dab2..1fbb149 100644 --- a/src/lib/ecore_input/ecore_input.c +++ b/src/lib/ecore_input/ecore_input.c @@ -26,6 +26,7 @@ EAPI int ECORE_EVENT_MOUSE_BUTTON_CANCEL = 0; EAPI int ECORE_EVENT_DEVICE_ADD = 0; EAPI int ECORE_EVENT_DEVICE_DEL = 0; EAPI int ECORE_EVENT_DETENT_ROTATE = 0; //TIZEN ONLY +EAPI int ECORE_EVENT_JOYSTICK = 0; static int _ecore_event_init_count = 0; @@ -61,6 +62,7 @@ ecore_event_init(void) ECORE_EVENT_DEVICE_ADD = ecore_event_type_new(); ECORE_EVENT_DEVICE_DEL = ecore_event_type_new(); ECORE_EVENT_DETENT_ROTATE = ecore_event_type_new(); //TIZEN ONLY + ECORE_EVENT_JOYSTICK = ecore_event_type_new(); return _ecore_event_init_count; } @@ -84,6 +86,7 @@ ecore_event_shutdown(void) ECORE_EVENT_DEVICE_ADD = 0; ECORE_EVENT_DEVICE_DEL = 0; ECORE_EVENT_DETENT_ROTATE = 0; //TIZEN ONLY + ECORE_EVENT_JOYSTICK = 0; 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 0000000..d8d3aec --- /dev/null +++ b/src/lib/ecore_input/ecore_input_joystick.c @@ -0,0 +1,391 @@ +#include +#include +#include +#include +#include + +#include "Ecore.h" +#include "Ecore_Input.h" +#include "ecore_input_private.h" + +static const char joystickPrefix[] = "/dev/input/event"; + +static Eina_List *joystick_list; + +struct _Joystick_Info +{ + Ecore_Fd_Handler *fd_handler; + char *system_path; + int index; +}; +typedef struct _Joystick_Info Joystick_Info; + +static int _ecore_input_joystick_init_count = 0; +static struct udev_monitor *monitor = NULL; +static Ecore_Fd_Handler *monitor_handler = NULL; + +static void +_joystick_connected_event_add(int index, Eina_Bool connected) +{ + Ecore_Event_Joystick *e; + if (!(e = malloc(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_event_add(struct input_event *event, int index) +{ + Ecore_Event_Joystick *e; + + if ((event->type != EV_KEY) && (event->type != EV_ABS)) return; + if (!(e = malloc(sizeof(Ecore_Event_Joystick)))) return; + + if (event->type == EV_KEY) + { + e->type = ECORE_EVENT_JOYSTICK_EVENT_TYPE_BUTTON; + e->button.value = event->value; + } + else + { + e->type = ECORE_EVENT_JOYSTICK_EVENT_TYPE_AXIS; + e->axis.value = event->value; + } + + e->index = index; + e->timestamp = ((event->time.tv_sec * 1000) + (event->time.tv_usec / 1000)); + + switch (event->code) + { + case BTN_A: + e->button.index = ECORE_EVENT_JOYSTICK_BUTTON_FACE_0; + break; + + case BTN_B: + e->button.index = ECORE_EVENT_JOYSTICK_BUTTON_FACE_1; + break; + + case BTN_C: + /* TODO: */ + break; + + case BTN_X: + e->button.index = ECORE_EVENT_JOYSTICK_BUTTON_FACE_2; + break; + + case BTN_Y: + e->button.index = ECORE_EVENT_JOYSTICK_BUTTON_FACE_3; + break; + + case BTN_Z: + /* TODO: */ + break; + + case BTN_TL: + e->button.index = ECORE_EVENT_JOYSTICK_BUTTON_LEFT_SHOULDER; + break; + + case BTN_TR: + e->button.index = ECORE_EVENT_JOYSTICK_BUTTON_RIGHT_SHOULDER; + break; + + case BTN_SELECT: + e->button.index = ECORE_EVENT_JOYSTICK_BUTTON_SELECT; + break; + + case BTN_START: + e->button.index = ECORE_EVENT_JOYSTICK_BUTTON_START; + break; + + case BTN_THUMBL: + e->button.index = ECORE_EVENT_JOYSTICK_BUTTON_LEFT_ANALOG_STICK; + break; + + case BTN_THUMBR: + e->button.index = ECORE_EVENT_JOYSTICK_BUTTON_RIGHT_ANALOG_STICK; + break; + + case 0x13f: + /* TODO: button "PLAY" */ + break; + + case ABS_X: + e->axis.index = ECORE_EVENT_JOYSTICK_AXIS_LEFT_ANALOG_HOR; + e->axis.value = event->value / 32767.0f; + break; + + case ABS_Y: + e->axis.index = ECORE_EVENT_JOYSTICK_AXIS_LEFT_ANALOG_VER; + e->axis.value = event->value / 32767.0f; + break; + + case ABS_Z: + e->axis.index = ECORE_EVENT_JOYSTICK_AXIS_LEFT_SHOULDER; + break; + + case ABS_RX: + e->axis.index = ECORE_EVENT_JOYSTICK_AXIS_RIGHT_ANALOG_HOR; + e->axis.value = event->value / 32767.0f; + break; + + case ABS_RY: + e->axis.index = ECORE_EVENT_JOYSTICK_AXIS_RIGHT_ANALOG_HOR; + e->axis.value = event->value / 32767.0f; + break; + + case ABS_RZ: + e->axis.index = ECORE_EVENT_JOYSTICK_AXIS_RIGHT_SHOULDER; + break; + + case ABS_HAT0X: /* D-pad */ + e->axis.index = ECORE_EVENT_JOYSTICK_AXIS_HAT_X; + break; + + case ABS_HAT0Y: + e->axis.index = ECORE_EVENT_JOYSTICK_AXIS_HAT_Y; + break; + + default: + break; + } + + ecore_event_add(ECORE_EVENT_JOYSTICK, e, NULL, NULL); +} + +Eina_Bool _fd_handler_cb(void* userData, Ecore_Fd_Handler* fdHandler) +{ + int fd; + Joystick_Info *ji = userData; + struct input_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, code: %d, value: %d", + ji->index, event.type, event.code, event.value); + + _joystick_event_add(&event, ji->index); + + return ECORE_CALLBACK_RENEW; +} + +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 *dev, const char* syspath) +{ + int fd, index; + Joystick_Info *ji; + + if (!dev) return; + + index = _joystick_index_get(dev); + if (index == -1) + { + ERR("Invalid index value."); + return; + } + + ji = calloc(1, sizeof(Joystick_Info)); + if (!ji) + { + ERR("Cannot allocate memory."); + return; + } + + ji->index = index; + ji->system_path = strdup(syspath); + + fd = open(dev, 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); +} + +static void +_joystick_unregister(const char *syspath) +{ + int fd; + Eina_List *l; + Joystick_Info *ji; + + EINA_LIST_FOREACH(joystick_list, l, ji) + { + if (!strcmp(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); + free(ji->system_path); + free(ji); + } + } +} + +Eina_Bool _monitor_handler_cb(void* userData EINA_UNUSED, Ecore_Fd_Handler* fdHandler) +{ + struct udev_device *device; + const char *syspath, *action, *devnode; + + if (!ecore_main_fd_handler_active_get(fdHandler, ECORE_FD_READ)) + return ECORE_CALLBACK_RENEW; + + device = udev_monitor_receive_device(monitor); + if (!device) + { + ERR("Cannot get device from monitor."); + return ECORE_CALLBACK_RENEW; + } + + syspath = udev_device_get_syspath(device); + if (!syspath) + { + ERR("Cannot get syspath from device."); + return ECORE_CALLBACK_RENEW; + } + + action = udev_device_get_action(device); + if (!action) + { + ERR("Action value is NULL."); + return ECORE_CALLBACK_RENEW; + } + + if (!strcmp(action, "add")) + { + devnode = udev_device_get_devnode(device); + _joystick_register(devnode, syspath); + udev_device_unref(device); + } + else if (!strcmp(action, "remove")) + { + _joystick_unregister(syspath); + } + else + { + WRN("Unhandled action: %s", action); + } + + return ECORE_CALLBACK_RENEW; +} + +EAPI int +ecore_input_joystick_init(void) +{ + struct udev *udev; + struct udev_enumerate *en; + struct udev_list_entry *devs, *cur; + struct udev_device *device; + const char *syspath; + const char *devnode; + int fd; + + if (++_ecore_input_joystick_init_count != 1) + return _ecore_input_joystick_init_count; + + udev = udev_new(); + if (!udev) + { + ERR("Cannot create udev."); + return --_ecore_input_joystick_init_count; + } + + en = udev_enumerate_new(udev); + if (!en) + { + ERR("Cannot create udev enumerate."); + return --_ecore_input_joystick_init_count; + } + + udev_enumerate_add_match_subsystem(en, "input"); + udev_enumerate_add_match_property(en, "ID_INPUT_JOYSTICK", "1"); + + udev_enumerate_scan_devices(en); + devs = udev_enumerate_get_list_entry(en); + udev_list_entry_foreach(cur, devs) + { + syspath = udev_list_entry_get_name(cur); + device = udev_device_new_from_syspath(udev, syspath); + devnode = udev_device_get_devnode(device); + + if (devnode && eina_str_has_prefix(devnode, joystickPrefix)) + { + INF("syspath: %s, devnode: %s", syspath, devnode); + _joystick_register(devnode, syspath); + } + udev_device_unref(device); + } + + /* add monitor */ + monitor = udev_monitor_new_from_netlink(udev, "udev"); + if (!monitor) + { + ERR("Cannot create monitor."); + --_ecore_input_joystick_init_count; + goto end; + } + + udev_monitor_filter_add_match_subsystem_devtype(monitor, "input", NULL); + if (udev_monitor_enable_receiving(monitor)) + { + ERR("Cannot enable monitor."); + --_ecore_input_joystick_init_count; + goto end; + } + + fd = udev_monitor_get_fd(monitor); + monitor_handler = ecore_main_fd_handler_add(fd, ECORE_FD_READ, + _monitor_handler_cb, + NULL, 0, 0); +end: + udev_enumerate_unref(en); + return _ecore_input_joystick_init_count; +} + +EAPI int +ecore_input_joystick_shutdown(void) +{ + int fd; + + if (--_ecore_input_joystick_init_count != 0) + return _ecore_input_joystick_init_count; + + if (monitor) udev_monitor_unref(monitor); + if (monitor_handler) + { + fd = ecore_main_fd_handler_fd_get(monitor_handler); + close(fd); + ecore_main_fd_handler_del(monitor_handler); + } + + return _ecore_input_joystick_init_count; +} diff --git a/src/tests/ecore/ecore_test_ecore_input.c b/src/tests/ecore/ecore_test_ecore_input.c index ccb0c92..fce7f4b 100644 --- a/src/tests/ecore/ecore_test_ecore_input.c +++ b/src/tests/ecore/ecore_test_ecore_input.c @@ -31,7 +31,37 @@ START_TEST(ecore_test_ecore_input_init) } END_TEST +//TIZEN_ONLY(20160627) - Initial version of ecore joystick event +START_TEST(ecore_test_ecore_input_joystick_init) +{ + int ret, i, j; + + ecore_event_init(); + + for (i = 1; i <= MAX_ITER; i++) + { + ret = ecore_input_joystick_init(); + fprintf(stderr, "Created %d ecore input joystick instance.\n", i); + fail_if(ret != i); + } + + for (j = MAX_ITER - 1; j >= 0; j--) + { + ret = ecore_input_joystick_shutdown(); + fprintf(stderr, "Deleted %d ecore input joystick instance.\n", + MAX_ITER - j); + fail_if(ret != j); + } + + ecore_shutdown(); +} +END_TEST +// + void ecore_test_ecore_input(TCase *tc) { tcase_add_test(tc, ecore_test_ecore_input_init); +//TIZEN_ONLY(20160627) - Initial version of ecore joystick event + tcase_add_test(tc, ecore_test_ecore_input_joystick_init); +// } -- 2.7.4