efl/src/lib/elput/elput_evdev.c

1389 lines
34 KiB
C

#include "elput_private.h"
static void
_seat_caps_update(Elput_Seat *seat)
{
Elput_Event_Seat_Caps *ev;
ev = calloc(1, sizeof(Elput_Event_Seat_Caps));
if (!ev) return;
ev->pointer_count = seat->count.ptr;
ev->keyboard_count = seat->count.kbd;
ev->touch_count = seat->count.touch;
ev->seat = seat;
ecore_event_add(ELPUT_EVENT_SEAT_CAPS, ev, NULL, NULL);
}
static void
_seat_frame_send(Elput_Seat *seat)
{
Elput_Event_Seat_Frame *ev;
ev = calloc(1, sizeof(Elput_Event_Seat_Frame));
if (!ev) return;
ev->seat = seat;
ecore_event_add(ELPUT_EVENT_SEAT_FRAME, ev, NULL, NULL);
}
static void
_keyboard_modifiers_update(Elput_Keyboard *kbd, Elput_Seat *seat)
{
xkb_mod_mask_t mask;
kbd->mods.depressed =
xkb_state_serialize_mods(kbd->state, XKB_STATE_DEPRESSED);
kbd->mods.latched =
xkb_state_serialize_mods(kbd->state, XKB_STATE_LATCHED);
kbd->mods.locked =
xkb_state_serialize_mods(kbd->state, XKB_STATE_LOCKED);
kbd->mods.group =
xkb_state_serialize_mods(kbd->state, XKB_STATE_EFFECTIVE);
mask = (kbd->mods.depressed | kbd->mods.latched);
seat->modifiers = 0;
if (mask & kbd->info->mods.ctrl)
seat->modifiers |= ECORE_EVENT_MODIFIER_CTRL;
if (mask & kbd->info->mods.alt)
seat->modifiers |= ECORE_EVENT_MODIFIER_ALT;
if (mask & kbd->info->mods.shift)
seat->modifiers |= ECORE_EVENT_MODIFIER_SHIFT;
if (mask & kbd->info->mods.super)
seat->modifiers |= ECORE_EVENT_MODIFIER_WIN;
if (mask & kbd->info->mods.altgr)
seat->modifiers |= ECORE_EVENT_MODIFIER_ALTGR;
}
static int
_keyboard_fd_get(off_t size)
{
int fd = 0, blen = 0, len = 0;
const char *path;
char tmp[PATH_MAX];
long flags;
blen = sizeof(tmp) - 1;
if (!(path = getenv("XDG_RUNTIME_DIR")))
return -1;
len = strlen(path);
if (len < blen)
{
strcpy(tmp, path);
strcat(tmp, "/elput-keymap-XXXXXX");
}
else
return -1;
if ((fd = mkstemp(tmp)) < 0) return -1;
flags = fcntl(fd, F_GETFD);
if (flags < 0)
{
close(fd);
return -1;
}
if (fcntl(fd, F_SETFD, (flags | FD_CLOEXEC)) == -1)
{
close(fd);
return -1;
}
if (ftruncate(fd, size) < 0)
{
close(fd);
return -1;
}
unlink(tmp);
return fd;
}
static Elput_Keyboard_Info *
_keyboard_info_create(struct xkb_keymap *keymap, Eina_Bool external)
{
Elput_Keyboard_Info *info;
char *str;
info = calloc(1, sizeof(Elput_Keyboard_Info));
if (!info) return NULL;
info->keymap.map = xkb_keymap_ref(keymap);
info->refs = 1;
info->mods.super =
1 << xkb_keymap_mod_get_index(info->keymap.map, XKB_MOD_NAME_LOGO);
info->mods.shift =
1 << xkb_keymap_mod_get_index(info->keymap.map, XKB_MOD_NAME_SHIFT);
info->mods.caps =
1 << xkb_keymap_mod_get_index(info->keymap.map, XKB_MOD_NAME_CAPS);
info->mods.ctrl =
1 << xkb_keymap_mod_get_index(info->keymap.map, XKB_MOD_NAME_CTRL);
info->mods.alt =
1 << xkb_keymap_mod_get_index(info->keymap.map, XKB_MOD_NAME_ALT);
info->mods.altgr =
1 << xkb_keymap_mod_get_index(info->keymap.map, "ISO_Level3_Shift");
/* if we are using an external keymap then we do not need go further */
if (external) return info;
str = xkb_keymap_get_as_string(info->keymap.map, XKB_KEYMAP_FORMAT_TEXT_V1);
if (!str) goto err;
info->keymap.size = strlen(str) + 1;
info->keymap.fd = _keyboard_fd_get(info->keymap.size);
if (info->keymap.fd < 0) goto err_fd;
info->keymap.area =
mmap(NULL, info->keymap.size, PROT_READ | PROT_WRITE,
MAP_SHARED, info->keymap.fd, 0);
if (info->keymap.area == MAP_FAILED) goto err_map;
strcpy(info->keymap.area, str);
free(str);
return info;
err_map:
close(info->keymap.fd);
err_fd:
free(str);
err:
xkb_keymap_unref(info->keymap.map);
free(info);
return NULL;
}
static void
_keyboard_info_destroy(Elput_Keyboard_Info *info, Eina_Bool external)
{
if (--info->refs > 0) return;
if (!external)
{
xkb_keymap_unref(info->keymap.map);
if (info->keymap.area) munmap(info->keymap.area, info->keymap.size);
if (info->keymap.fd >= 0) close(info->keymap.fd);
}
free(info);
}
static Eina_Bool
_keyboard_global_build(Elput_Keyboard *kbd)
{
struct xkb_keymap *keymap;
kbd->context = xkb_context_new(0);
if (!kbd->context) return EINA_FALSE;
if (!kbd->names.rules) kbd->names.rules = strdup("evdev");
if (!kbd->names.model) kbd->names.model = strdup("pc105");
if (!kbd->names.layout) kbd->names.layout = strdup("us");
keymap = xkb_keymap_new_from_names(kbd->context, &kbd->names, 0);
if (!keymap) return EINA_FALSE;
kbd->info = _keyboard_info_create(keymap, EINA_FALSE);
xkb_keymap_unref(keymap);
if (!kbd->info) return EINA_FALSE;
return EINA_TRUE;
}
static Elput_Keyboard *
_keyboard_create(Elput_Seat *seat)
{
Elput_Keyboard *kbd;
kbd = calloc(1, sizeof(Elput_Keyboard));
if (!kbd) return NULL;
kbd->seat = seat;
return kbd;
}
static Eina_Bool
_keyboard_init(Elput_Seat *seat, struct xkb_keymap *keymap)
{
Elput_Keyboard *kbd;
if (seat->kbd)
{
seat->count.kbd += 1;
if (seat->count.kbd == 1)
{
_seat_caps_update(seat);
return EINA_TRUE;
}
}
kbd = _keyboard_create(seat);
if (!kbd) return EINA_FALSE;
if (keymap)
{
kbd->info = _keyboard_info_create(keymap, EINA_TRUE);
if (!kbd->info) goto err;
}
else
{
if (!_keyboard_global_build(kbd)) goto err;
kbd->info->refs++;
}
kbd->state = xkb_state_new(kbd->info->keymap.map);
if (!kbd->state) goto err;
seat->kbd = kbd;
seat->count.kbd = 1;
_seat_caps_update(seat);
return EINA_TRUE;
err:
if (kbd->info) _keyboard_info_destroy(kbd->info, kbd->external_map);
free(kbd);
return EINA_FALSE;
}
static void
_keyboard_state_reset(Elput_Keyboard *kbd)
{
struct xkb_state *state;
state = xkb_state_new(kbd->info->keymap.map);
if (!state) return;
xkb_state_unref(kbd->state);
kbd->state = state;
}
static void
_keyboard_release(Elput_Seat *seat)
{
seat->count.kbd--;
if (seat->count.kbd == 0)
{
_keyboard_state_reset(seat->kbd);
_seat_caps_update(seat);
}
}
static void
_keyboard_key_send(Elput_Device *dev, enum libinput_key_state state, const char *keyname, const char *key, const char *compose, unsigned int code, unsigned int timestamp)
{
Ecore_Event_Key *ev;
ev = calloc(1, sizeof(Ecore_Event_Key) + strlen(key) + strlen(keyname) +
((compose[0] != '\0') ? strlen(compose) : 0) + 3);
if (!ev) return;
ev->keyname = (char *)(ev + 1);
ev->key = ev->keyname + strlen(keyname) + 1;
ev->compose = strlen(compose) ? ev->key + strlen(key) + 1 : NULL;
ev->string = ev->compose;
strcpy((char *)ev->keyname, keyname);
strcpy((char *)ev->key, key);
if (strlen(compose)) strcpy((char *)ev->compose, compose);
ev->keycode = code;
ev->modifiers = dev->seat->modifiers;
ev->timestamp = timestamp;
ev->same_screen = 1;
ev->window = dev->window;
ev->event_window = dev->window;
ev->root_window = dev->window;
if (state == LIBINPUT_KEY_STATE_PRESSED)
ecore_event_add(ECORE_EVENT_KEY_DOWN, ev, NULL, NULL);
else
ecore_event_add(ECORE_EVENT_KEY_UP, ev, NULL, NULL);
}
static void
_keyboard_keymap_send(Elput_Keyboard_Info *info)
{
Elput_Event_Keymap_Send *ev;
ev = calloc(1, sizeof(Elput_Event_Keymap_Send));
if (!ev) return;
ev->fd = info->keymap.fd;
ev->size = info->keymap.size;
ev->format = XKB_KEYMAP_FORMAT_TEXT_V1;
ecore_event_add(ELPUT_EVENT_KEYMAP_SEND, ev, NULL, NULL);
}
static void
_keyboard_modifiers_send(Elput_Keyboard *kbd)
{
Elput_Event_Modifiers_Send *ev;
ev = calloc(1, sizeof(Elput_Event_Modifiers_Send));
if (!ev) return;
ev->depressed = kbd->mods.depressed;
ev->latched = kbd->mods.latched;
ev->locked = kbd->mods.locked;
ev->group = kbd->mods.group;
ecore_event_add(ELPUT_EVENT_MODIFIERS_SEND, ev, NULL, NULL);
}
static void
_keyboard_keymap_update(Elput_Seat *seat)
{
Elput_Keyboard *kbd;
Elput_Keyboard_Info *info;
struct xkb_state *state;
xkb_mod_mask_t latched, locked;
kbd = _evdev_keyboard_get(seat);
if (!kbd) return;
info = _keyboard_info_create(kbd->pending_map, kbd->external_map);
xkb_keymap_unref(kbd->pending_map);
kbd->pending_map = NULL;
if (!info) return;
state = xkb_state_new(info->keymap.map);
if (!state)
{
_keyboard_info_destroy(info, kbd->external_map);
return;
}
latched = xkb_state_serialize_mods(kbd->state, XKB_STATE_MODS_LATCHED);
locked = xkb_state_serialize_mods(kbd->state, XKB_STATE_MODS_LOCKED);
xkb_state_update_mask(state, 0, latched, locked, 0, 0, 0);
_keyboard_info_destroy(kbd->info, kbd->external_map);
kbd->info = info;
xkb_state_unref(kbd->state);
kbd->state = state;
_keyboard_modifiers_update(kbd, seat);
_keyboard_keymap_send(kbd->info);
if ((!latched) && (!locked)) return;
_keyboard_modifiers_send(kbd);
}
static int
_keyboard_keysym_translate(xkb_keysym_t keysym, unsigned int modifiers, char *buffer, int bytes)
{
unsigned long hbytes = 0;
unsigned char c;
if (!keysym) return 0;
hbytes = (keysym >> 8);
if (!(bytes &&
((hbytes == 0) ||
((hbytes == 0xFF) &&
(((keysym >= XKB_KEY_BackSpace) && (keysym <= XKB_KEY_Clear)) ||
(keysym == XKB_KEY_Return) || (keysym == XKB_KEY_Escape) ||
(keysym == XKB_KEY_KP_Space) || (keysym == XKB_KEY_KP_Tab) ||
(keysym == XKB_KEY_KP_Enter) ||
((keysym >= XKB_KEY_KP_Multiply) && (keysym <= XKB_KEY_KP_9)) ||
(keysym == XKB_KEY_KP_Equal) || (keysym == XKB_KEY_Delete))))))
return 0;
if (keysym == XKB_KEY_KP_Space)
c = (XKB_KEY_space & 0x7F);
else if (hbytes == 0xFF)
c = (keysym & 0x7F);
else
c = (keysym & 0xFF);
if (modifiers & ECORE_EVENT_MODIFIER_CTRL)
{
if (((c >= '@') && (c < '\177')) || c == ' ')
c &= 0x1F;
else if (c == '2')
c = '\000';
else if ((c >= '3') && (c <= '7'))
c -= ('3' - '\033');
else if (c == '8')
c = '\177';
else if (c == '/')
c = '_' & 0x1F;
}
buffer[0] = c;
return 1;
}
static void
_keyboard_key(struct libinput_device *idevice, struct libinput_event_keyboard *event)
{
Elput_Device *dev;
Elput_Keyboard *kbd;
enum libinput_key_state state;
xkb_keysym_t sym = XKB_KEY_NoSymbol;
const xkb_keysym_t *syms;
unsigned int code = 0;
unsigned int nsyms;
unsigned int timestamp;
char key[256], keyname[256], buffer[256];
char *tmp = NULL, *compose = NULL;
int count;
dev = libinput_device_get_user_data(idevice);
if (!dev) return;
kbd = _evdev_keyboard_get(dev->seat);
if (!kbd) return;
state = libinput_event_keyboard_get_key_state(event);
count = libinput_event_keyboard_get_seat_key_count(event);
/* Ignore key events that are not seat wide state changes. */
if (((state == LIBINPUT_KEY_STATE_PRESSED) && (count != 1)) ||
((state == LIBINPUT_KEY_STATE_RELEASED) && (count != 0)))
return;
code = libinput_event_keyboard_get_key(event) + 8;
timestamp = libinput_event_keyboard_get_time(event);
if (state == LIBINPUT_KEY_STATE_PRESSED)
xkb_state_update_key(kbd->state, code, XKB_KEY_DOWN);
else
xkb_state_update_key(kbd->state, code, XKB_KEY_UP);
nsyms = xkb_key_get_syms(kbd->state, code, &syms);
if (nsyms == 1) sym = syms[0];
memset(key, 0, sizeof(key));
xkb_keysym_get_name(sym, key, sizeof(key));
memset(keyname, 0, sizeof(keyname));
memcpy(keyname, key, sizeof(keyname));
if (keyname[0] == '\0')
snprintf(keyname, sizeof(keyname), "Keycode-%u", code);
if (xkb_state_mod_index_is_active(kbd->state, kbd->info->mods.shift,
XKB_STATE_MODS_EFFECTIVE))
{
if (keyname[0] != '\0')
keyname[0] = tolower(keyname[0]);
}
_keyboard_modifiers_update(kbd, dev->seat);
memset(buffer, 0, sizeof(buffer));
if (_keyboard_keysym_translate(sym, dev->seat->modifiers,
buffer, sizeof(buffer)))
{
compose = eina_str_convert("ISO8859-1", "UTF-8", buffer);
if (!compose)
{
ERR("Elput cannot convert input key string '%s' to UTF-8. "
"Is Eina built with iconv support?", buffer);
}
else
tmp = compose;
}
if (!compose) compose = buffer;
_keyboard_key_send(dev, state, keyname, key, compose, code, timestamp);
if (tmp) free(tmp);
if ((kbd->pending_map) && (count == 0))
_keyboard_keymap_update(dev->seat);
if (state == LIBINPUT_KEY_STATE_PRESSED)
{
kbd->grab.key = code;
kbd->grab.timestamp = timestamp;
}
}
static Elput_Pointer *
_pointer_create(Elput_Seat *seat)
{
Elput_Pointer *ptr;
ptr = calloc(1, sizeof(Elput_Pointer));
if (!ptr) return NULL;
ptr->seat = seat;
return ptr;
}
static Eina_Bool
_pointer_init(Elput_Seat *seat)
{
Elput_Pointer *ptr;
if (seat->ptr)
{
seat->count.ptr += 1;
if (seat->count.ptr == 1)
{
_seat_caps_update(seat);
return EINA_TRUE;
}
}
ptr = _pointer_create(seat);
if (!ptr) return EINA_FALSE;
seat->ptr = ptr;
seat->count.ptr = 1;
_seat_caps_update(seat);
return EINA_TRUE;
}
static void
_pointer_release(Elput_Seat *seat)
{
seat->count.ptr--;
if (seat->count.ptr == 0)
{
seat->ptr->buttons = 0;
_seat_caps_update(seat);
}
}
static Elput_Touch *
_touch_create(Elput_Seat *seat)
{
Elput_Touch *touch;
touch = calloc(1, sizeof(Elput_Touch));
if (!touch) return NULL;
touch->seat = seat;
return touch;
}
static Eina_Bool
_touch_init(Elput_Seat *seat)
{
Elput_Touch *touch;
if (seat->touch)
{
seat->count.touch += 1;
if (seat->count.touch == 1)
{
_seat_caps_update(seat);
return EINA_TRUE;
}
}
touch = _touch_create(seat);
if (!touch) return EINA_FALSE;
seat->touch = touch;
seat->count.touch = 1;
_seat_caps_update(seat);
return EINA_TRUE;
}
static void
_touch_release(Elput_Seat *seat)
{
seat->count.touch--;
if (seat->count.touch == 0)
{
seat->touch->points = 0;
_seat_caps_update(seat);
}
}
static void
_pointer_motion_send(Elput_Device *edev)
{
Elput_Pointer *ptr;
Elput_Keyboard *kbd;
Elput_Touch *touch;
Ecore_Event_Mouse_Move *ev;
double x, y;
ptr = _evdev_pointer_get(edev->seat);
if (!ptr) return;
ev = calloc(1, sizeof(Ecore_Event_Mouse_Move));
if (!ev) return;
x = ptr->x;
y = ptr->y;
if (x < ptr->minx)
x = ptr->minx;
else if (x >= ptr->minx + ptr->maxw)
x = ptr->minx + ptr->maxw - 1;
if (y < ptr->miny)
y = ptr->miny;
else if (y >= ptr->miny + ptr->maxh)
y = ptr->miny + ptr->maxh - 1;
ev->window = edev->window;
ev->event_window = edev->window;
ev->root_window = edev->window;
ev->timestamp = ptr->timestamp;
ev->same_screen = 1;
ev->x = x;
ev->y = y;
ev->root.x = x;
ev->root.y = y;
kbd = _evdev_keyboard_get(edev->seat);
if (kbd) _keyboard_modifiers_update(kbd, edev->seat);
ev->modifiers = edev->seat->modifiers;
touch = _evdev_touch_get(edev->seat);
if (touch) ev->multi.device = touch->slot;
ev->multi.radius = 1;
ev->multi.radius_x = 1;
ev->multi.radius_y = 1;
ev->multi.pressure = 1.0;
ev->multi.angle = 0.0;
ev->multi.x = ev->x;
ev->multi.y = ev->y;
ev->multi.root.x = ev->x;
ev->multi.root.y = ev->y;
ecore_event_add(ECORE_EVENT_MOUSE_MOVE, ev, NULL, NULL);
}
static Eina_Bool
_pointer_motion(struct libinput_device *idev, struct libinput_event_pointer *event)
{
Elput_Device *edev;
Elput_Pointer *ptr;
double x, y;
edev = libinput_device_get_user_data(idev);
if (!edev) return EINA_FALSE;
ptr = _evdev_pointer_get(edev->seat);
if (!ptr) return EINA_FALSE;
x = ptr->x + libinput_event_pointer_get_dx(event);
y = ptr->y + libinput_event_pointer_get_dy(event);
if (x < ptr->minx)
x = ptr->minx;
else if (x >= ptr->minx + ptr->maxw)
x = ptr->minx + ptr->maxw - 1;
if (y < ptr->miny)
y = ptr->miny;
else if (y >= ptr->miny + ptr->maxh)
y = ptr->miny + ptr->maxh - 1;
ptr->x = x;
ptr->y = y;
ptr->timestamp = libinput_event_pointer_get_time(event);
_pointer_motion_send(edev);
return EINA_TRUE;
}
static Eina_Bool
_pointer_motion_abs(struct libinput_device *idev, struct libinput_event_pointer *event)
{
Elput_Device *edev;
Elput_Pointer *ptr;
edev = libinput_device_get_user_data(idev);
if (!edev) return EINA_FALSE;
ptr = _evdev_pointer_get(edev->seat);
if (!ptr) return EINA_FALSE;
ptr->x = libinput_event_pointer_get_absolute_x_transformed(event, edev->ow);
ptr->y = libinput_event_pointer_get_absolute_y_transformed(event, edev->oh);
ptr->timestamp = libinput_event_pointer_get_time(event);
/* TODO: these needs to run a matrix transform based on output */
_pointer_motion_send(edev);
return EINA_TRUE;
}
static void
_pointer_button_send(Elput_Device *edev, enum libinput_button_state state)
{
Elput_Pointer *ptr;
Elput_Keyboard *kbd;
Elput_Touch *touch;
Ecore_Event_Mouse_Button *ev;
ptr = _evdev_pointer_get(edev->seat);
if (!ptr) return;
ev = calloc(1, sizeof(Ecore_Event_Mouse_Button));
if (!ev) return;
ev->window = edev->window;
ev->event_window = edev->window;
ev->root_window = edev->window;
ev->timestamp = ptr->timestamp;
ev->same_screen = 1;
ev->x = ptr->x;
ev->y = ptr->y;
ev->root.x = ptr->x;
ev->root.y = ptr->y;
touch = _evdev_touch_get(edev->seat);
if (touch) ev->multi.device = touch->slot;
ev->multi.radius = 1;
ev->multi.radius_x = 1;
ev->multi.radius_y = 1;
ev->multi.pressure = 1.0;
ev->multi.angle = 0.0;
ev->multi.x = ev->x;
ev->multi.y = ev->y;
ev->multi.root.x = ev->x;
ev->multi.root.y = ev->y;
ev->buttons = ptr->buttons;
ev->double_click = ptr->mouse.double_click;
ev->triple_click = ptr->mouse.triple_click;
kbd = _evdev_keyboard_get(edev->seat);
if (kbd)
_keyboard_modifiers_update(kbd, edev->seat);
ev->modifiers = edev->seat->modifiers;
if (state)
ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, ev, NULL, NULL);
else
ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_UP, ev, NULL, NULL);
}
static Eina_Bool
_pointer_button(struct libinput_device *idev, struct libinput_event_pointer *event)
{
Elput_Device *edev;
Elput_Pointer *ptr;
int count;
enum libinput_button_state state;
unsigned int btn;
edev = libinput_device_get_user_data(idev);
if (!edev) return EINA_FALSE;
ptr = _evdev_pointer_get(edev->seat);
if (!ptr) return EINA_FALSE;
state = libinput_event_pointer_get_button_state(event);
count = libinput_event_pointer_get_seat_button_count(event);
/* Ignore button events that are not seat wide state changes. */
if (((state == LIBINPUT_BUTTON_STATE_PRESSED) && (count != 1)) ||
((state == LIBINPUT_BUTTON_STATE_RELEASED) && (count != 0)))
return EINA_FALSE;
btn = libinput_event_pointer_get_button(event);
btn = ((btn & 0x00F) + 1);
if (btn == 3) btn = 2;
else if (btn == 2) btn = 3;
ptr->buttons = btn;
ptr->timestamp = libinput_event_pointer_get_time(event);
if (state)
{
unsigned int current;
current = ptr->timestamp;
ptr->mouse.double_click = EINA_FALSE;
ptr->mouse.triple_click = EINA_FALSE;
if (((current - ptr->mouse.prev_time) <= ptr->mouse.threshold) &&
(btn == ptr->mouse.prev_button))
{
ptr->mouse.double_click = EINA_TRUE;
if (((current - ptr->mouse.last_time) <=
(2 * ptr->mouse.threshold)) &&
(btn == ptr->mouse.last_button))
{
ptr->mouse.triple_click = EINA_TRUE;
ptr->mouse.prev_time = 0;
ptr->mouse.last_time = 0;
current = 0;
}
}
ptr->mouse.last_time = ptr->mouse.prev_time;
ptr->mouse.prev_time = current;
ptr->mouse.last_button = ptr->mouse.prev_button;
ptr->mouse.prev_button = ptr->buttons;
}
_pointer_button_send(edev, state);
return EINA_TRUE;
}
static void
_pointer_axis_send(Elput_Device *dev, int direction, int value)
{
Elput_Pointer *ptr;
Elput_Keyboard *kbd;
Ecore_Event_Mouse_Wheel *ev;
ptr = _evdev_pointer_get(dev->seat);
if (!ptr) return;
ev = calloc(1, sizeof(Ecore_Event_Mouse_Wheel));
if (!ev) return;
ev->window = dev->window;
ev->event_window = dev->window;
ev->root_window = dev->window;
ev->timestamp = ptr->timestamp;
ev->same_screen = 1;
ev->x = ptr->x;
ev->y = ptr->y;
ev->root.x = ptr->x;
ev->root.y = ptr->y;
ev->z = value;
ev->direction = direction;
kbd = _evdev_keyboard_get(dev->seat);
if (kbd) _keyboard_modifiers_update(kbd, dev->seat);
ev->modifiers = dev->seat->modifiers;
ecore_event_add(ECORE_EVENT_MOUSE_WHEEL, ev, NULL, NULL);
}
static double
_pointer_axis_value(struct libinput_event_pointer *event, enum libinput_pointer_axis axis)
{
enum libinput_pointer_axis_source source;
double val = 0.0;
source = libinput_event_pointer_get_axis_source(event);
switch (source)
{
case LIBINPUT_POINTER_AXIS_SOURCE_WHEEL:
val = 10 * libinput_event_pointer_get_axis_value_discrete(event, axis);
break;
case LIBINPUT_POINTER_AXIS_SOURCE_FINGER:
case LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS:
val = libinput_event_pointer_get_axis_value(event, axis);
break;
}
return val;
}
static Eina_Bool
_pointer_axis(struct libinput_device *idevice, struct libinput_event_pointer *event)
{
Elput_Device *dev;
Elput_Pointer *ptr;
enum libinput_pointer_axis axis;
Eina_Bool vert = EINA_FALSE, horiz = EINA_FALSE;
int dir = 0, val = 0;
dev = libinput_device_get_user_data(idevice);
if (!dev) return EINA_FALSE;
ptr = _evdev_pointer_get(dev->seat);
if (!ptr) return EINA_FALSE;
#ifdef LIBINPUT_HIGHER_08
vert =
libinput_event_pointer_has_axis(event,
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL);
horiz =
libinput_event_pointer_has_axis(event,
LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL);
if ((!vert) && (!horiz)) return EINA_FALSE;
if (vert)
{
axis = LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL;
val = _pointer_axis_value(event, axis);
}
if (horiz)
{
axis = LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL;
val = _pointer_axis_value(event, axis);
dir = 1;
}
#else
axis = libinput_event_pointer_get_axis(event);
if (axis == LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL) dir = 1;
val = libinput_event_pointer_get_axis_value(event);
#endif
ptr->timestamp = libinput_event_pointer_get_time(event);
_pointer_axis_send(dev, dir, val);
return EINA_TRUE;
}
static void
_touch_event_send(Elput_Device *dev, struct libinput_event_touch *event, int type)
{
Elput_Touch *touch;
Ecore_Event_Mouse_Button *ev;
unsigned int btn = 0;
touch = _evdev_touch_get(dev->seat);
if (!touch) return;
ev = calloc(1, sizeof(Ecore_Event_Mouse_Button));
if (!ev) return;
ev->window = dev->window;
ev->event_window = dev->window;
ev->root_window = dev->window;
ev->timestamp = libinput_event_touch_get_time(event);
ev->same_screen = 1;
ev->x = touch->x;
ev->y = touch->y;
ev->root.x = touch->x;
ev->root.y = touch->y;
ev->modifiers = dev->seat->modifiers;
ev->multi.device = touch->slot;
ev->multi.radius = 1;
ev->multi.radius_x = 1;
ev->multi.radius_y = 1;
ev->multi.pressure = 1.0;
ev->multi.angle = 0.0;
ev->multi.x = ev->x;
ev->multi.y = ev->y;
ev->multi.root.x = ev->x;
ev->multi.root.y = ev->y;
btn = ((btn & 0x00F) + 1);
if (btn == 3) btn = 2;
else if (btn == 2) btn = 3;
ev->buttons = btn;
ecore_event_add(type, ev, NULL, NULL);
}
static void
_touch_down(struct libinput_device *idevice, struct libinput_event_touch *event)
{
Elput_Device *dev;
Elput_Touch *touch;
unsigned int timestamp;
int slot;
dev = libinput_device_get_user_data(idevice);
if (!dev) return;
touch = _evdev_touch_get(dev->seat);
if (!touch) return;
slot = libinput_event_touch_get_seat_slot(event);
timestamp = libinput_event_touch_get_time(event);
touch->x = libinput_event_touch_get_x_transformed(event, dev->ow);
touch->y = libinput_event_touch_get_y_transformed(event, dev->oh);
/* TODO: these needs to run a matrix transform based on output */
/* _ecore_drm2_output_coordinate_transform(dev->output, */
/* touch->x, touch->y, */
/* &touch->x, &touch->y); */
if (slot == touch->grab.id)
{
touch->grab.x = touch->x;
touch->grab.y = touch->y;
}
touch->slot = slot;
touch->points++;
_touch_event_send(dev, event, ECORE_EVENT_MOUSE_BUTTON_DOWN);
if (touch->points == 1)
{
touch->grab.id = slot;
touch->grab.x = touch->x;
touch->grab.y = touch->y;
touch->grab.timestamp = timestamp;
}
}
static void
_touch_up(struct libinput_device *idevice, struct libinput_event_touch *event)
{
Elput_Device *dev;
Elput_Touch *touch;
dev = libinput_device_get_user_data(idevice);
if (!dev) return;
touch = _evdev_touch_get(dev->seat);
if (!touch) return;
touch->points--;
touch->slot = libinput_event_touch_get_seat_slot(event);
_touch_event_send(dev, event, ECORE_EVENT_MOUSE_BUTTON_UP);
}
static void
_touch_motion_send(Elput_Device *dev, struct libinput_event_touch *event)
{
Elput_Touch *touch;
Ecore_Event_Mouse_Move *ev;
touch = _evdev_touch_get(dev->seat);
if (!touch) return;
ev = calloc(1, sizeof(Ecore_Event_Mouse_Move));
if (!ev) return;
ev->window = dev->window;
ev->event_window = dev->window;
ev->root_window = dev->window;
ev->timestamp = libinput_event_touch_get_time(event);
ev->same_screen = 1;
ev->x = touch->x;
ev->y = touch->y;
ev->root.x = touch->x;
ev->root.y = touch->y;
ev->modifiers = dev->seat->modifiers;
ev->multi.device = touch->slot;
ev->multi.radius = 1;
ev->multi.radius_x = 1;
ev->multi.radius_y = 1;
ev->multi.pressure = 1.0;
ev->multi.angle = 0.0;
ev->multi.x = ev->x;
ev->multi.y = ev->y;
ev->multi.root.x = ev->x;
ev->multi.root.y = ev->y;
ecore_event_add(ECORE_EVENT_MOUSE_MOVE, ev, NULL, NULL);
}
static void
_touch_motion(struct libinput_device *idevice, struct libinput_event_touch *event)
{
Elput_Device *dev;
Elput_Touch *touch;
dev = libinput_device_get_user_data(idevice);
if (!dev) return;
touch = _evdev_touch_get(dev->seat);
if (!touch) return;
touch->x = libinput_event_touch_get_x_transformed(event, dev->ow);
touch->y = libinput_event_touch_get_y_transformed(event, dev->oh);
/* TODO: these needs to run a matrix transform based on output */
/* _ecore_drm2_output_coordinate_transform(dev->output, */
/* touch->x, touch->y, */
/* &touch->x, &touch->y); */
touch->slot = libinput_event_touch_get_seat_slot(event);
_touch_motion_send(dev, event);
}
static void
_evdev_device_calibrate(Elput_Device *dev)
{
float cal[6];
const char *vals;
const char *sysname;
const char *device;
Eina_List *devices;
int w = 0, h = 0;
enum libinput_config_status status;
w = dev->ow;
h = dev->oh;
if ((w == 0) || (h == 0)) return;
if ((!libinput_device_config_calibration_has_matrix(dev->device)) ||
(libinput_device_config_calibration_get_default_matrix(dev->device, cal)))
return;
sysname = libinput_device_get_sysname(dev->device);
devices = eeze_udev_find_by_subsystem_sysname("input", sysname);
EINA_LIST_FREE(devices, device)
{
vals = eeze_udev_syspath_get_property(device, "WL_CALIBRATION");
if ((!vals) ||
(sscanf(vals, "%f %f %f %f %f %f",
&cal[0], &cal[1], &cal[2], &cal[3], &cal[4], &cal[5]) != 6))
goto cont;
cal[2] /= w;
cal[5] /= h;
status =
libinput_device_config_calibration_set_matrix(dev->device, cal);
if (status != LIBINPUT_CONFIG_STATUS_SUCCESS)
WRN("Failed to apply device calibration");
cont:
eina_stringshare_del(device);
}
}
int
_evdev_event_process(struct libinput_event *event)
{
struct libinput_device *idev;
int ret = 1;
Eina_Bool frame = EINA_FALSE;
idev = libinput_event_get_device(event);
switch (libinput_event_get_type(event))
{
case LIBINPUT_EVENT_KEYBOARD_KEY:
_keyboard_key(idev, libinput_event_get_keyboard_event(event));
break;
case LIBINPUT_EVENT_POINTER_MOTION:
frame =
_pointer_motion(idev, libinput_event_get_pointer_event(event));
break;
case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
frame =
_pointer_motion_abs(idev, libinput_event_get_pointer_event(event));
break;
case LIBINPUT_EVENT_POINTER_BUTTON:
frame =
_pointer_button(idev, libinput_event_get_pointer_event(event));
break;
case LIBINPUT_EVENT_POINTER_AXIS:
frame =
_pointer_axis(idev, libinput_event_get_pointer_event(event));
break;
case LIBINPUT_EVENT_TOUCH_DOWN:
_touch_down(idev, libinput_event_get_touch_event(event));
break;
case LIBINPUT_EVENT_TOUCH_MOTION:
_touch_motion(idev, libinput_event_get_touch_event(event));
break;
case LIBINPUT_EVENT_TOUCH_UP:
_touch_up(idev, libinput_event_get_touch_event(event));
break;
case LIBINPUT_EVENT_TOUCH_FRAME:
default:
ret = 0;
break;
}
if (frame)
{
Elput_Device *edev;
edev = libinput_device_get_user_data(idev);
if (edev) _seat_frame_send(edev->seat);
}
return ret;
}
Elput_Device *
_evdev_device_create(Elput_Seat *seat, struct libinput_device *device)
{
Elput_Device *edev;
edev = calloc(1, sizeof(Elput_Device));
if (!edev) return NULL;
edev->seat = seat;
edev->device = device;
if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_KEYBOARD))
{
_keyboard_init(seat, NULL);
edev->caps |= EVDEV_SEAT_KEYBOARD;
}
if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_POINTER))
{
_pointer_init(seat);
edev->caps |= EVDEV_SEAT_POINTER;
}
if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_TOUCH))
{
_touch_init(seat);
edev->caps |= EVDEV_SEAT_TOUCH;
}
libinput_device_set_user_data(device, edev);
libinput_device_ref(edev->device);
if (libinput_device_config_tap_get_finger_count(edev->device) > 0)
{
Eina_Bool enable = EINA_FALSE;
enable = libinput_device_config_tap_get_default_enabled(edev->device);
libinput_device_config_tap_set_enabled(edev->device, enable);
}
/* FIXME: Normally we would do a device calibration set here however
* that requires Output support. Since this is just an input library, we
* may need to add external facing APIs to do calibration. Then a user of
* elput would handle outputs, and make calls to calibrate */
return edev;
}
void
_evdev_device_destroy(Elput_Device *edev)
{
if (!edev) return;
if (edev->caps & EVDEV_SEAT_POINTER)
_pointer_release(edev->seat);
if (edev->caps & EVDEV_SEAT_KEYBOARD)
_keyboard_release(edev->seat);
if (edev->caps & EVDEV_SEAT_TOUCH)
_touch_release(edev->seat);
libinput_device_unref(edev->device);
eina_stringshare_del(edev->output_name);
free(edev);
}
void
_evdev_keyboard_destroy(Elput_Keyboard *kbd)
{
free((char *)kbd->names.rules);
free((char *)kbd->names.model);
free((char *)kbd->names.layout);
free((char *)kbd->names.variant);
free((char *)kbd->names.options);
if (kbd->state) xkb_state_unref(kbd->state);
if (kbd->info) _keyboard_info_destroy(kbd->info, kbd->external_map);
xkb_context_unref(kbd->context);
xkb_keymap_unref(kbd->pending_map);
free(kbd);
}
void
_evdev_pointer_destroy(Elput_Pointer *ptr)
{
/* FIXME: destroy any resources inside pointer structure */
free(ptr);
}
void
_evdev_touch_destroy(Elput_Touch *touch)
{
/* FIXME: destroy any resources inside touch structure */
free(touch);
}
void
_evdev_pointer_motion_send(Elput_Device *edev)
{
_pointer_motion_send(edev);
}
Elput_Pointer *
_evdev_pointer_get(Elput_Seat *seat)
{
if (!seat) return NULL;
if (seat->count.ptr) return seat->ptr;
return NULL;
}
Elput_Keyboard *
_evdev_keyboard_get(Elput_Seat *seat)
{
if (!seat) return NULL;
if (seat->count.kbd) return seat->kbd;
return NULL;
}
Elput_Touch *
_evdev_touch_get(Elput_Seat *seat)
{
if (!seat) return NULL;
if (seat->count.touch) return seat->touch;
return NULL;
}
EAPI void
elput_device_window_set(Elput_Device *device, unsigned int window)
{
EINA_SAFETY_ON_NULL_RETURN(device);
device->window = window;
}
EAPI void
elput_device_output_size_set(Elput_Device *device, int w, int h)
{
EINA_SAFETY_ON_NULL_RETURN(device);
device->ow = w;
device->oh = h;
if (libinput_device_has_capability(device->device,
LIBINPUT_DEVICE_CAP_POINTER))
{
Elput_Pointer *ptr;
ptr = _evdev_pointer_get(device->seat);
if (ptr)
{
ptr->x = device->ow / 2;
ptr->y = device->oh / 2;
}
}
_evdev_device_calibrate(device);
}