#include "e.h" #include "e_mod_main.h" #define E_EVDEV_ABSOLUTE_MOTION (1 << 0) #define E_EVDEV_ABSOLUTE_MT_DOWN (1 << 1) #define E_EVDEV_ABSOLUTE_MT_MOTION (1 << 2) #define E_EVDEV_ABSOLUTE_MT_UP (1 << 3) #define E_EVDEV_RELATIVE_MOTION (1 << 4) #define BITS_PER_LONG (sizeof(unsigned long) * 8) #define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1) #define OFF(x) ((x)%BITS_PER_LONG) #define BIT(x) (1UL<> OFF(bit)) & 1) #define MODIFIER_CTRL (1 << 8) #define MODIFIER_ALT (1 << 9) #define MODIFIER_SUPER (1 << 10) /* local function prototypes */ static Eina_Bool _e_evdev_config_udev_monitor(struct udev *udev, E_Evdev_Input *master); static E_Evdev_Input_Device *_e_evdev_input_device_create(E_Evdev_Input *master, struct wl_display *display __UNUSED__, const char *path); static Eina_Bool _e_evdev_configure_device(E_Evdev_Input_Device *dev); static Eina_Bool _e_evdev_is_motion_event(struct input_event *e); static void _e_evdev_flush_motion(E_Evdev_Input_Device *dev, unsigned int timestamp); static void _e_evdev_process_touch(E_Evdev_Input_Device *device, struct input_event *e); static void _e_evdev_process_events(E_Evdev_Input_Device *device, struct input_event *ev, int count); static int _e_evdev_cb_udev(int fd __UNUSED__, unsigned int mask __UNUSED__, void *data); static void _e_evdev_cb_device_added(struct udev_device *dev, E_Evdev_Input *master); static void _e_evdev_cb_device_removed(struct udev_device *dev, E_Evdev_Input *master); static int _e_evdev_cb_device_data(int fd, unsigned int mask __UNUSED__, void *data); /* local variables */ /* wayland interfaces */ /* external variables */ EINTERN void e_evdev_add_devices(struct udev *udev, E_Input_Device *base) { E_Evdev_Input *input; struct udev_enumerate *ue; struct udev_list_entry *entry; struct udev_device *device; const char *path = NULL; DLOGFN(__FILE__, __LINE__, __FUNCTION__); input = (E_Evdev_Input *)base; ue = udev_enumerate_new(udev); udev_enumerate_add_match_subsystem(ue, "input"); udev_enumerate_scan_devices(ue); udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(ue)) { path = udev_list_entry_get_name(entry); device = udev_device_new_from_syspath(udev, path); if (strncmp("event", udev_device_get_sysname(device), 5) != 0) continue; _e_evdev_cb_device_added(device, input); udev_device_unref(device); } udev_enumerate_unref(ue); if (wl_list_empty(&input->devices)) printf("No Input Devices Found\n"); } EINTERN void e_evdev_remove_devices(E_Input_Device *base) { E_Evdev_Input *input; E_Evdev_Input_Device *device, *next; DLOGFN(__FILE__, __LINE__, __FUNCTION__); input = (E_Evdev_Input *)base; wl_list_for_each_safe(device, next, &input->devices, link) { wl_event_source_remove(device->source); wl_list_remove(&device->link); if (device->mtdev) mtdev_close_delete(device->mtdev); close(device->fd); free(device->devnode); free(device); } } EINTERN void e_evdev_input_create(E_Compositor *comp, struct udev *udev, const char *seat) { E_Evdev_Input *input; DLOGFN(__FILE__, __LINE__, __FUNCTION__); if (!(input = malloc(sizeof(E_Evdev_Input)))) return; memset(input, 0, sizeof(E_Evdev_Input)); e_input_device_init(&input->base, comp); wl_list_init(&input->devices); input->seat = strdup(seat); if (!_e_evdev_config_udev_monitor(udev, input)) { free(input->seat); free(input); return; } e_evdev_add_devices(udev, &input->base); comp->input_device = &input->base.input_device; } EINTERN void e_evdev_input_destroy(E_Input_Device *base) { E_Evdev_Input *input; DLOGFN(__FILE__, __LINE__, __FUNCTION__); input = (E_Evdev_Input *)base; e_evdev_remove_devices(base); wl_list_remove(&input->base.link); free(input->seat); free(input); } /* local functions */ static Eina_Bool _e_evdev_config_udev_monitor(struct udev *udev, E_Evdev_Input *master) { struct wl_event_loop *loop; E_Compositor *comp; DLOGFN(__FILE__, __LINE__, __FUNCTION__); comp = master->base.compositor; if (!(master->monitor = udev_monitor_new_from_netlink(udev, "udev"))) return EINA_FALSE; udev_monitor_filter_add_match_subsystem_devtype(master->monitor, "input", NULL); if (udev_monitor_enable_receiving(master->monitor)) return EINA_FALSE; loop = wl_display_get_event_loop(comp->display); wl_event_loop_add_fd(loop, udev_monitor_get_fd(master->monitor), WL_EVENT_READABLE, _e_evdev_cb_udev, master); return EINA_TRUE; } static E_Evdev_Input_Device * _e_evdev_input_device_create(E_Evdev_Input *master, struct wl_display *display __UNUSED__, const char *path) { E_Evdev_Input_Device *device; E_Compositor *comp; DLOGFN(__FILE__, __LINE__, __FUNCTION__); if (!(device = malloc(sizeof(E_Evdev_Input_Device)))) return NULL; comp = master->base.compositor; device->output = container_of(comp->outputs.next, E_Output, link); device->master = master; device->is_pad = EINA_FALSE; device->is_mt = EINA_FALSE; device->mtdev = NULL; device->devnode = strdup(path); device->mt.slot = -1; device->rel.dx = 0; device->rel.dy = 0; device->fd = open(path, O_RDONLY | O_NONBLOCK); if (device->fd < 0) goto err0; if (!_e_evdev_configure_device(device)) goto err1; if (device->is_mt) { if (!(device->mtdev = mtdev_new_open(device->fd))) printf("mtdev Failed to open device: %s\n", path); } device->source = wl_event_loop_add_fd(comp->input_loop, device->fd, WL_EVENT_READABLE, _e_evdev_cb_device_data, device); if (!device->source) goto err1; wl_list_insert(master->devices.prev, &device->link); return device; err1: close(device->fd); err0: free(device->devnode); free(device); return NULL; } static Eina_Bool _e_evdev_configure_device(E_Evdev_Input_Device *dev) { struct input_absinfo absinfo; unsigned long ebits[NBITS(EV_MAX)]; unsigned long abits[NBITS(ABS_MAX)]; unsigned long kbits[NBITS(KEY_MAX)]; Eina_Bool has_key = EINA_FALSE, has_abs = EINA_FALSE; DLOGFN(__FILE__, __LINE__, __FUNCTION__); ioctl(dev->fd, EVIOCGBIT(0, sizeof(ebits)), ebits); if (TEST_BIT(ebits, EV_ABS)) { has_abs = EINA_TRUE; ioctl(dev->fd, EVIOCGBIT(EV_ABS, sizeof(abits)), abits); if (TEST_BIT(abits, ABS_X)) { ioctl(dev->fd, EVIOCGABS(ABS_X), &absinfo); dev->absolute.min_x = absinfo.minimum; dev->absolute.max_x = absinfo.maximum; } if (TEST_BIT(abits, ABS_Y)) { ioctl(dev->fd, EVIOCGABS(ABS_Y), &absinfo); dev->absolute.min_y = absinfo.minimum; dev->absolute.max_y = absinfo.maximum; } if (TEST_BIT(abits, ABS_MT_SLOT)) { dev->is_mt = EINA_TRUE; dev->mt.slot = 0; } } if (TEST_BIT(ebits, EV_KEY)) { has_key = EINA_TRUE; ioctl(dev->fd, EVIOCGBIT(EV_KEY, sizeof(kbits)), kbits); if ((TEST_BIT(kbits, BTN_TOOL_FINGER)) && (!TEST_BIT(kbits, BTN_TOOL_PEN))) dev->is_pad = EINA_TRUE; } if ((has_abs) && (!has_key)) return EINA_FALSE; return EINA_TRUE; } static Eina_Bool _e_evdev_is_motion_event(struct input_event *e) { DLOGFN(__FILE__, __LINE__, __FUNCTION__); switch (e->type) { case EV_REL: switch (e->code) { case REL_X: case REL_Y: return EINA_TRUE; } case EV_ABS: switch (e->code) { case ABS_X: case ABS_Y: case ABS_MT_POSITION_X: case ABS_MT_POSITION_Y: return EINA_TRUE; } } return EINA_FALSE; } static void _e_evdev_flush_motion(E_Evdev_Input_Device *dev, unsigned int timestamp) { struct wl_input_device *master; DLOGFN(__FILE__, __LINE__, __FUNCTION__); if (!dev->type) return; master = &dev->master->base.input_device; if (dev->type & E_EVDEV_RELATIVE_MOTION) { e_input_notify_motion(master, timestamp, master->x + dev->rel.dx, master->y + dev->rel.dy); dev->type &= ~E_EVDEV_RELATIVE_MOTION; dev->rel.dx = 0; dev->rel.dy = 0; } if (dev->type & E_EVDEV_ABSOLUTE_MT_DOWN) { e_input_notify_touch(master, timestamp, dev->mt.slot, dev->mt.x[dev->mt.slot], dev->mt.y[dev->mt.slot], WL_INPUT_DEVICE_TOUCH_DOWN); dev->type &= ~E_EVDEV_ABSOLUTE_MT_DOWN; dev->type &= ~E_EVDEV_ABSOLUTE_MT_MOTION; } if (dev->type & E_EVDEV_ABSOLUTE_MT_MOTION) { e_input_notify_touch(master, timestamp, dev->mt.slot, dev->mt.x[dev->mt.slot], dev->mt.y[dev->mt.slot], WL_INPUT_DEVICE_TOUCH_MOTION); dev->type &= ~E_EVDEV_ABSOLUTE_MT_DOWN; dev->type &= ~E_EVDEV_ABSOLUTE_MT_MOTION; } if (dev->type & E_EVDEV_ABSOLUTE_MT_UP) { e_input_notify_touch(master, timestamp, dev->mt.slot, 0, 0, WL_INPUT_DEVICE_TOUCH_UP); dev->type &= ~E_EVDEV_ABSOLUTE_MT_UP; } if (dev->type & E_EVDEV_ABSOLUTE_MOTION) { e_input_notify_motion(master, timestamp, dev->absolute.x, dev->absolute.y); dev->type &= ~E_EVDEV_ABSOLUTE_MOTION; } } static inline void _e_evdev_process_key(E_Evdev_Input_Device *device, struct input_event *e, int timestamp) { DLOGFN(__FILE__, __LINE__, __FUNCTION__); if (e->value == 2) return; switch (e->code) { case BTN_TOOL_PEN: case BTN_TOOL_RUBBER: case BTN_TOOL_BRUSH: case BTN_TOOL_PENCIL: case BTN_TOOL_AIRBRUSH: case BTN_TOOL_FINGER: case BTN_TOOL_MOUSE: case BTN_TOOL_LENS: if (device->is_pad) { device->absolute.rx = 1; device->absolute.ry = 1; } break; case BTN_TOUCH: if (device->is_mt) break; e->code = BTN_LEFT; case BTN_LEFT: case BTN_RIGHT: case BTN_MIDDLE: case BTN_SIDE: case BTN_EXTRA: case BTN_FORWARD: case BTN_BACK: case BTN_TASK: e_input_notify_button(&device->master->base.input_device, timestamp, e->code, e->value); break; default: e_input_notify_key(&device->master->base.input_device, timestamp, e->code, e->value); break; } } static inline void _e_evdev_process_absolute_motion(E_Evdev_Input_Device *device, struct input_event *e) { int sw, sh; DLOGFN(__FILE__, __LINE__, __FUNCTION__); sw = device->output->current->w; sh = device->output->current->h; switch (e->code) { case ABS_X: device->absolute.x = (e->value - device->absolute.min_x) * sw / (device->absolute.max_x - device->absolute.min_x) + device->output->x; device->type |= E_EVDEV_ABSOLUTE_MOTION; break; case ABS_Y: device->absolute.y = (e->value - device->absolute.min_y) * sh / (device->absolute.max_y - device->absolute.min_y) + device->output->y; device->type |= E_EVDEV_ABSOLUTE_MOTION; break; } } static inline void _e_evdev_process_absolute_motion_touchpad(E_Evdev_Input_Device *device, struct input_event *e) { /* FIXME: Make this configurable. */ const int touchpad_speed = 700; switch (e->code) { case ABS_X: e->value -= device->absolute.min_x; if (device->absolute.rx) device->absolute.rx = 0; else { device->rel.dx = (e->value - device->absolute.ox) * touchpad_speed / (device->absolute.max_x - device->absolute.min_x); } device->absolute.ox = e->value; device->type |= E_EVDEV_RELATIVE_MOTION; break; case ABS_Y: e->value -= device->absolute.min_y; if (device->absolute.ry) device->absolute.ry = 0; else { device->rel.dy = (e->value - device->absolute.oy) * touchpad_speed / (device->absolute.max_y - device->absolute.min_y); } device->absolute.oy = e->value; device->type |= E_EVDEV_RELATIVE_MOTION; break; } } static inline void _e_evdev_process_relative(E_Evdev_Input_Device *device, struct input_event *e, unsigned int timestamp) { DLOGFN(__FILE__, __LINE__, __FUNCTION__); switch (e->code) { case REL_X: device->rel.dx += e->value; device->type |= E_EVDEV_RELATIVE_MOTION; break; case REL_Y: device->rel.dy += e->value; device->type |= E_EVDEV_RELATIVE_MOTION; break; case REL_WHEEL: e_input_notify_axis(&device->master->base.input_device, timestamp, WL_INPUT_DEVICE_AXIS_VERTICAL_SCROLL, e->value); break; case REL_HWHEEL: e_input_notify_axis(&device->master->base.input_device, timestamp, WL_INPUT_DEVICE_AXIS_HORIZONTAL_SCROLL, e->value); break; } } static inline void _e_evdev_process_absolute(E_Evdev_Input_Device *device, struct input_event *e) { DLOGFN(__FILE__, __LINE__, __FUNCTION__); if (device->is_pad) _e_evdev_process_absolute_motion_touchpad(device, e); else if (device->is_mt) _e_evdev_process_touch(device, e); else _e_evdev_process_absolute_motion(device, e); } static void _e_evdev_process_touch(E_Evdev_Input_Device *device, struct input_event *e) { int sw, sh; DLOGFN(__FILE__, __LINE__, __FUNCTION__); sw = device->output->current->w; sh = device->output->current->h; switch (e->code) { case ABS_MT_SLOT: device->mt.slot = e->value; break; case ABS_MT_TRACKING_ID: if (e->value >= 0) device->type |= E_EVDEV_ABSOLUTE_MT_DOWN; else device->type |= E_EVDEV_ABSOLUTE_MT_UP; break; case ABS_MT_POSITION_X: device->mt.x[device->mt.slot] = (e->value - device->absolute.min_x) * sw / (device->absolute.max_x - device->absolute.min_x) + device->output->x; device->type |= E_EVDEV_ABSOLUTE_MT_MOTION; break; case ABS_MT_POSITION_Y: device->mt.y[device->mt.slot] = (e->value - device->absolute.min_y) * sh / (device->absolute.max_y - device->absolute.min_y) + device->output->y; device->type |= E_EVDEV_ABSOLUTE_MT_MOTION; break; } } static void _e_evdev_process_events(E_Evdev_Input_Device *device, struct input_event *ev, int count) { struct input_event *e, *end; unsigned int timestamp = 0; DLOGFN(__FILE__, __LINE__, __FUNCTION__); device->type = 0; e = ev; end = e + count; for (e = ev; e < end; e++) { timestamp = e->time.tv_sec * 1000 + e->time.tv_usec / 1000; if (!_e_evdev_is_motion_event(e)) _e_evdev_flush_motion(device, timestamp); switch (e->type) { case EV_REL: _e_evdev_process_relative(device, e, timestamp); break; case EV_ABS: _e_evdev_process_absolute(device, e); break; case EV_KEY: _e_evdev_process_key(device, e, timestamp); break; } } _e_evdev_flush_motion(device, timestamp); } static int _e_evdev_cb_udev(int fd __UNUSED__, unsigned int mask __UNUSED__, void *data) { E_Evdev_Input *master; struct udev_device *dev; const char *action; DLOGFN(__FILE__, __LINE__, __FUNCTION__); if (!(master = data)) return 1; if (!(dev = udev_monitor_receive_device(master->monitor))) return 1; if ((action = udev_device_get_action(dev))) { if (strncmp("event", udev_device_get_sysname(dev), 5) != 0) return 0; if (!strcmp(action, "add")) _e_evdev_cb_device_added(dev, master); else if (!strcmp(action, "remove")) _e_evdev_cb_device_removed(dev, master); } udev_device_unref(dev); return 0; } static void _e_evdev_cb_device_added(struct udev_device *dev, E_Evdev_Input *master) { E_Compositor *comp; const char *node, *seat; DLOGFN(__FILE__, __LINE__, __FUNCTION__); if (!(seat = udev_device_get_property_value(dev, "ID_SEAT"))) seat = "seat0"; if (strcmp(seat, master->seat)) return; comp = master->base.compositor; node = udev_device_get_devnode(dev); _e_evdev_input_device_create(master, comp->display, node); } static void _e_evdev_cb_device_removed(struct udev_device *dev, E_Evdev_Input *master) { const char *node; E_Evdev_Input_Device *device, *next; DLOGFN(__FILE__, __LINE__, __FUNCTION__); node = udev_device_get_devnode(dev); wl_list_for_each_safe(device, next, &master->devices, link) { if (!strcmp(device->devnode, node)) { wl_event_source_remove(device->source); wl_list_remove(&device->link); if (device->mtdev) mtdev_close_delete(device->mtdev); close(device->fd); free(device->devnode); free(device); break; } } } static int _e_evdev_cb_device_data(int fd, unsigned int mask __UNUSED__, void *data) { E_Compositor *comp; E_Evdev_Input_Device *device; struct input_event ev[32]; int len = 0; DLOGFN(__FILE__, __LINE__, __FUNCTION__); device = data; comp = device->master->base.compositor; if (!comp->focus) return 1; do { if (device->mtdev) len = mtdev_get(device->mtdev, fd, ev, (sizeof(ev) / sizeof(ev)[0]) * sizeof(struct input_event)); else len = read(fd, &ev, sizeof(ev)); if ((len < 0) || (len % sizeof(ev[0]) != 0)) return 1; printf("Process Input Events Len: %d\n", len); _e_evdev_process_events(device, ev, (len / sizeof(ev[0]))); } while (len > 0); /* len = read(fd, &ev, sizeof(ev)); */ /* device->type = 0; */ /* e = ev; */ /* end = (void *)ev + len; */ /* for (e = ev; e < end; e++) */ /* { */ /* timestamp = (e->time.tv_sec * 1000 + e->time.tv_usec / 1000); */ /* if (!_e_evdev_is_motion_event(e)) */ /* _e_evdev_flush_motion(device, timestamp); */ /* switch (e->type) */ /* { */ /* case EV_REL: */ /* _e_evdev_process_relative_motion(device, e); */ /* break; */ /* case EV_ABS: */ /* _e_evdev_process_absolute(device, e); */ /* break; */ /* case EV_KEY: */ /* _e_evdev_process_key(device, e, timestamp); */ /* break; */ /* } */ /* } */ /* _e_evdev_flush_motion(device, timestamp); */ return 1; }