summaryrefslogtreecommitdiff
path: root/src/modules/gesture_recognition/e_mod_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/modules/gesture_recognition/e_mod_main.c')
-rw-r--r--src/modules/gesture_recognition/e_mod_main.c287
1 files changed, 287 insertions, 0 deletions
diff --git a/src/modules/gesture_recognition/e_mod_main.c b/src/modules/gesture_recognition/e_mod_main.c
new file mode 100644
index 0000000000..2ebbebecc1
--- /dev/null
+++ b/src/modules/gesture_recognition/e_mod_main.c
@@ -0,0 +1,287 @@
+#include <e.h>
+#include <Eina.h>
+#include <libinput.h>
+#include <grp.h>
+#include <sys/types.h>
+#include <pwd.h>
+
+E_API E_Module_Api e_modapi =
+ {
+ E_MODULE_API_VERSION,
+ "Gesture Recognition"
+ };
+
+static struct libinput *gesture_recognition_ctx;
+static Ecore_Fd_Handler *fd_listener;
+
+static int open_restricted(const char *path, int flags, void *user_data EINA_UNUSED)
+{
+ int fd = open(path, flags);
+ return fd < 0 ? -errno : fd;
+}
+
+static void close_restricted(int fd, void *user_data EINA_UNUSED)
+{
+ close(fd);
+}
+
+static const struct libinput_interface interface = {
+ .open_restricted = open_restricted,
+ .close_restricted = close_restricted,
+};
+
+static void
+_find_all_touch_input_devices(const char *path, struct libinput *li)
+{
+ Eina_File_Direct_Info *info;
+ Eina_Iterator *input_devies = eina_file_direct_ls(path);
+
+ EINA_ITERATOR_FOREACH(input_devies, info)
+ {
+ struct libinput_device *dev = libinput_path_add_device(li, info->path);
+
+ if (!dev) continue;
+
+ if (!libinput_device_has_capability(dev, LIBINPUT_DEVICE_CAP_GESTURE))
+ {
+ libinput_path_remove_device(dev);
+ }
+ }
+}
+
+static Eina_Hash *active_gestures;
+
+typedef struct {
+ Eina_Vector2 pos;
+ unsigned int fingers;
+ struct {
+ Evas_Object *visuals, *win;
+ } visuals;
+} Swipe_Stats;
+
+
+static Swipe_Stats*
+_find_swipe_gesture_recognizition(struct libinput_device *dev)
+{
+ Swipe_Stats *stats = eina_hash_find(active_gestures, dev);
+
+ return stats;
+}
+
+static Swipe_Stats*
+_start_swipe_gesture_recognizition(struct libinput_device *dev)
+{
+ Swipe_Stats *stats = _find_swipe_gesture_recognizition(dev);
+
+ if (stats)
+ eina_hash_del_by_key(active_gestures, dev);
+
+ stats = calloc(1, sizeof(Swipe_Stats));
+ EINA_SAFETY_ON_NULL_RETURN_VAL(stats, NULL);
+
+ if (e_bindings_swipe_available())
+ {
+ stats->visuals.win = elm_notify_add(e_comp->elm);
+ elm_notify_align_set(stats->visuals.win, 0.5, 0.5);
+ elm_object_tree_focus_allow_set(stats->visuals.win, EINA_FALSE);
+ evas_object_layer_set(stats->visuals.win, E_LAYER_CLIENT_PRIO);
+ evas_object_show(stats->visuals.win);
+
+ stats->visuals.visuals = elm_progressbar_add(stats->visuals.win);
+ elm_object_text_set(stats->visuals.visuals, "Progress of visuals");
+ evas_object_size_hint_min_set(stats->visuals.visuals, 300, 50);
+ evas_object_show(stats->visuals.visuals);
+ elm_object_content_set(stats->visuals.win, stats->visuals.visuals);
+ }
+
+
+ eina_hash_add(active_gestures, dev, stats);
+
+ return stats;
+}
+
+static void
+_end_swipe_gesture_recognizition(struct libinput_device *dev)
+{
+ eina_hash_del_by_key(active_gestures, dev);
+}
+
+static double
+_config_angle(Eina_Vector2 pos)
+{
+ double res = atan(pos.y/pos.x);
+
+ if (res < 0) res += M_PI;
+ if (pos.y < 0) res += M_PI;
+ return res;
+}
+
+static Eina_Bool
+_cb_input_dispatch(void *data, Ecore_Fd_Handler *hdlr EINA_UNUSED)
+{
+ struct libinput *li = data;
+ struct libinput_event *event;
+
+ if (libinput_dispatch(li) != 0)
+ printf("Failed to dispatch libinput events");
+
+ while((event = libinput_get_event(li)))
+ {
+ E_Bindings_Swipe_Live_Update live_update = e_bindings_swipe_live_update_hook_get();
+
+ enum libinput_event_type type = libinput_event_get_type(event);
+ struct libinput_device *dev = libinput_event_get_device(event);
+ if (type == LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN)
+ {
+ struct libinput_event_gesture *gesture = libinput_event_get_gesture_event(event);
+
+ Swipe_Stats *stats = _start_swipe_gesture_recognizition(dev);
+ stats->fingers = libinput_event_gesture_get_finger_count(gesture);
+ stats->pos.x = stats->pos.y = 0;
+ }
+ else if (type == LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE)
+ {
+ struct libinput_event_gesture *gesture = libinput_event_get_gesture_event(event);
+ Swipe_Stats *stats = _find_swipe_gesture_recognizition(dev);
+
+ stats->pos.x += libinput_event_gesture_get_dx(gesture);
+ stats->pos.y += libinput_event_gesture_get_dy(gesture);
+ if (live_update)
+ {
+ live_update(e_bindings_swipe_live_update_hook_data_get(), EINA_FALSE, _config_angle(stats->pos), eina_vector2_length_get(&stats->pos), 0.8, stats->fingers);
+ }
+ else if (stats->visuals.win)
+ {
+ Eina_Inarray *res = e_bindings_swipe_find_candidates(E_BINDING_CONTEXT_NONE, _config_angle (stats->pos), eina_vector2_length_get(&stats->pos), stats->fingers);
+ E_Binding_Swipe_Candidate *itr;
+ double total = 0.0f;
+ unsigned int len = 0;
+
+ EINA_INARRAY_FOREACH(res, itr)
+ {
+ total += itr->acceptance;
+ len ++;
+ }
+
+ if (len > 0)
+ {
+ char text_buffer[1000];
+
+ snprintf(text_buffer, sizeof(text_buffer), "%d gestures possible", len);
+ elm_progressbar_value_set(stats->visuals.visuals, total/len);
+ elm_object_text_set(stats->visuals.visuals, text_buffer);
+ }
+ else
+ {
+ elm_progressbar_value_set(stats->visuals.visuals, 0.0f);
+ elm_object_text_set(stats->visuals.visuals, "No gesture found");
+ }
+
+ eina_inarray_free(res);
+ }
+ }
+ else if (type == LIBINPUT_EVENT_GESTURE_SWIPE_END)
+ {
+ Swipe_Stats *stats = _find_swipe_gesture_recognizition(dev);
+
+ if (live_update)
+ live_update(e_bindings_swipe_live_update_hook_data_get(), EINA_TRUE, _config_angle(stats->pos), eina_vector2_length_get(&stats->pos), 0.8, stats->fingers);
+ else
+ e_bindings_swipe_handle(E_BINDING_CONTEXT_NONE, NULL, _config_angle(stats->pos), eina_vector2_length_get(&stats->pos), stats->fingers);
+
+ _end_swipe_gesture_recognizition(dev);
+ }
+ libinput_event_destroy(event);
+ }
+ return EINA_TRUE;
+}
+
+static void
+_setup_libinput(void)
+{
+ gesture_recognition_ctx = libinput_path_create_context(&interface, NULL);
+
+ _find_all_touch_input_devices("/dev/input/", gesture_recognition_ctx);
+
+ fd_listener = ecore_main_fd_handler_add(libinput_get_fd(gesture_recognition_ctx), ECORE_FD_READ, _cb_input_dispatch, gesture_recognition_ctx, NULL, NULL);
+}
+
+
+static void
+_tear_down_libinput(void)
+{
+ ecore_main_fd_handler_del(fd_listener);
+ libinput_unref(gesture_recognition_ctx);
+}
+
+static Eina_Bool
+_user_part_of_input(void)
+{
+ uid_t user = getuid();
+ struct passwd *user_pw = getpwuid(user);
+ gid_t *gids = NULL;
+ int number_of_groups = 0;
+ struct group *input_group = getgrnam("input");
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(user_pw, EINA_FALSE);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(input_group, EINA_FALSE);
+
+ if (getgrouplist(user_pw->pw_name, getgid(), NULL, &number_of_groups) != -1)
+ {
+ ERR("Failed to enumerate groups of user");
+ return EINA_FALSE;
+ }
+ number_of_groups ++;
+ gids = alloca((number_of_groups) * sizeof(gid_t));
+ if (getgrouplist(user_pw->pw_name, getgid(), gids, &number_of_groups) == -1)
+ {
+ ERR("Failed to get groups of user");
+ return EINA_FALSE;
+ }
+
+ for (int i = 0; i < number_of_groups; ++i)
+ {
+ if (gids[i] == input_group->gr_gid)
+ return EINA_TRUE;
+ }
+ return EINA_FALSE;
+}
+
+static void
+_stats_free(void *ptr)
+{
+ Swipe_Stats *stats = ptr;
+
+ evas_object_del(stats->visuals.win);
+ free(stats);
+}
+
+E_API int
+e_modapi_init(E_Module *m EINA_UNUSED)
+{
+ if (!_user_part_of_input())
+ {
+ e_module_dialog_show(m, "Gesture Recognition", "Your user is not part of the input group, libinput cannot be used.");
+
+ return 0;
+ }
+ active_gestures = eina_hash_pointer_new(_stats_free);
+ _setup_libinput();
+
+ return 1;
+}
+
+E_API int
+e_modapi_shutdown(E_Module *m EINA_UNUSED)
+{
+ _tear_down_libinput();
+ return 1;
+}
+
+E_API int
+e_modapi_save(E_Module *m EINA_UNUSED)
+{
+
+ return 1;
+}
+