/** * @file libinput_multi.c * */ /********************* * INCLUDES *********************/ #include "libinput_multi.h" #if USE_LIBINPUT || USE_BSD_LIBINPUT #include #include #include #include #include #include #include #include #if USE_BSD_LIBINPUT #include #else #include #endif #include "libinput_keymap.h" /********************* * DEFINES *********************/ /********************** * TYPEDEFS **********************/ /********************** * STATIC PROTOTYPES **********************/ static int open_restricted(const char *path, int flags, void *user_data); static void close_restricted(int fd, void *user_data); typedef struct { int button; int libinput_key_val; struct libinput_device *device; int libinput_fd; struct libinput *libinput_context; struct pollfd fds[1]; } libinput_multi_state; /********************** * STATIC VARIABLES **********************/ static const int timeout = 0; // do not block static const nfds_t nfds = 1; static lv_point_t most_recent_touch_point = { .x = 0, .y = 0}; static bool shift_down = false; static const struct libinput_interface interface = { .open_restricted = open_restricted, .close_restricted = close_restricted, }; /********************** * MACROS **********************/ /********************** * GLOBAL FUNCTIONS **********************/ /** * reconfigure the device file for libinput * @param indev_drv driver object (must be initialised) * @param dev_name set the libinput device filename * @return true: the device file set complete * false: the device file doesn't exist current system */ bool libinput_multi_set_file(lv_indev_drv_t * indev_drv, char* dev_name) { libinput_multi_state *state = (libinput_multi_state *)indev_drv->user_data; if (!state) { perror("unable to read state from driver:"); return false; } // This check *should* not be necessary, yet applications crashes even on NULL handles. // citing libinput.h:libinput_path_remove_device: // > If no matching device exists, this function does nothing. if (state->device) { state->device = libinput_device_unref(state->device); libinput_path_remove_device(state->device); } state->device = libinput_path_add_device(state->libinput_context, dev_name); if(!state->device) { perror("unable to add device to libinput context:"); return false; } state->device = libinput_device_ref(state->device); if(!state->device) { perror("unable to reference device within libinput context:"); return false; } state->button = LV_INDEV_STATE_REL; state->libinput_key_val = 0; return true; } /** * initialise a driver with fresh state data * @param indev_drv driver object */ void libinput_multi_init_driver(lv_indev_drv_t * indev_drv) { libinput_multi_state *state = (libinput_multi_state *)malloc(sizeof(libinput_multi_state)); state->device = NULL; state->libinput_context = libinput_path_create_context(&interface, NULL); state->libinput_fd = libinput_get_fd(state->libinput_context); /* prepare poll */ state->fds[0].fd = state->libinput_fd; state->fds[0].events = POLLIN; state->fds[0].revents = 0; indev_drv->user_data = (void *)state; } /** * destroy any existing state data on a driver * @param indev_drv driver object */ void libinput_multi_deinit_driver(lv_indev_drv_t * indev_drv) { if (indev_drv->user_data) { libinput_multi_state *state = (libinput_multi_state *)indev_drv->user_data; struct libinput_device *device = libinput_device_unref(state->device); libinput_path_remove_device(device); libinput_unref(state->libinput_context); free(indev_drv->user_data); indev_drv->user_data = NULL; } } /** * Get the current position and state of the libinput * @param indev_drv driver object itself * @param data store the libinput data here * @return false: because the points are not buffered, so no more data to be read */ bool libinput_multi_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) { libinput_multi_state *state = (libinput_multi_state *)indev_drv->user_data; if (!state) { perror("unable to read state from driver:"); return false; } struct libinput_event *event; struct libinput_event_touch *touch_event = NULL; struct libinput_event_pointer *pointer_event = NULL; struct libinput_event_keyboard *keyboard_event = NULL; int rc = 0; rc = poll(state->fds, nfds, timeout); switch (rc){ case -1: perror(NULL); case 0: goto report_most_recent_state; default: break; } libinput_dispatch(state->libinput_context); while((event = libinput_get_event(state->libinput_context)) != NULL) { enum libinput_event_type type = libinput_event_get_type(event); switch (type) { case LIBINPUT_EVENT_TOUCH_MOTION: case LIBINPUT_EVENT_TOUCH_DOWN: touch_event = libinput_event_get_touch_event(event); most_recent_touch_point.x = libinput_event_touch_get_x_transformed(touch_event, LV_HOR_RES); most_recent_touch_point.y = libinput_event_touch_get_y_transformed(touch_event, LV_VER_RES); state->button = LV_INDEV_STATE_PR; break; case LIBINPUT_EVENT_TOUCH_UP: state->button = LV_INDEV_STATE_REL; break; case LIBINPUT_EVENT_POINTER_MOTION: pointer_event = libinput_event_get_pointer_event(event); most_recent_touch_point.x += libinput_event_pointer_get_dx(pointer_event); most_recent_touch_point.y += libinput_event_pointer_get_dy(pointer_event); most_recent_touch_point.x = most_recent_touch_point.x < 0 ? 0 : most_recent_touch_point.x; most_recent_touch_point.x = most_recent_touch_point.x > LV_HOR_RES - 1 ? LV_HOR_RES - 1 : most_recent_touch_point.x; most_recent_touch_point.y = most_recent_touch_point.y < 0 ? 0 : most_recent_touch_point.y; most_recent_touch_point.y = most_recent_touch_point.y > LV_VER_RES - 1 ? LV_VER_RES - 1 : most_recent_touch_point.y; break; case LIBINPUT_EVENT_POINTER_BUTTON: pointer_event = libinput_event_get_pointer_event(event); enum libinput_button_state button_state = libinput_event_pointer_get_button_state(pointer_event); state->button = button_state == LIBINPUT_BUTTON_STATE_RELEASED ? LV_INDEV_STATE_REL : LV_INDEV_STATE_PR; break; case LIBINPUT_EVENT_KEYBOARD_KEY: keyboard_event = libinput_event_get_keyboard_event(event); enum libinput_key_state key_state = libinput_event_keyboard_get_key_state(keyboard_event); uint32_t code = libinput_event_keyboard_get_key(keyboard_event); if (code == KEY_LEFTSHIFT || code == KEY_RIGHTSHIFT) { shift_down = key_state == LIBINPUT_KEY_STATE_PRESSED; break; } state->button = (key_state == LIBINPUT_KEY_STATE_RELEASED) ? LV_INDEV_STATE_REL : LV_INDEV_STATE_PR; switch(code) { case KEY_BACKSPACE: state->libinput_key_val = LV_KEY_BACKSPACE; break; case KEY_ENTER: state->libinput_key_val = LV_KEY_ENTER; break; case KEY_PREVIOUS: state->libinput_key_val = LV_KEY_PREV; break; case KEY_NEXT: state->libinput_key_val = LV_KEY_NEXT; break; case KEY_UP: state->libinput_key_val = LV_KEY_UP; break; case KEY_LEFT: state->libinput_key_val = LV_KEY_LEFT; break; case KEY_RIGHT: state->libinput_key_val = LV_KEY_RIGHT; break; case KEY_DOWN: state->libinput_key_val = LV_KEY_DOWN; break; default: if (code < LV_NUM_KEYS && mapped_keys[code] != LV_MAPPED_KEY_NONE) { state->libinput_key_val = (shift_down ? keymap_upper : keymap_lower)[mapped_keys[code]]; } else { state->libinput_key_val = 0; } break; } break; default: break; } libinput_event_destroy(event); } report_most_recent_state: data->point.x = most_recent_touch_point.x; data->point.y = most_recent_touch_point.y; data->state = state->button; data->key = state->libinput_key_val; return false; } /********************** * STATIC FUNCTIONS **********************/ static int open_restricted(const char *path, int flags, void *user_data) { int fd = open(path, flags); return fd < 0 ? -errno : fd; } static void close_restricted(int fd, void *user_data) { close(fd); } #endif /* USE_LIBINPUT || USE_BSD_LIBINPUT */