forked from enlightenment/efl
752 lines
21 KiB
C
752 lines
21 KiB
C
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
|
|
/* copied from udev/extras/input_id/input_id.c */
|
|
/* we must use this kernel-compatible implementation */
|
|
#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(x))
|
|
#define LONG(x) ((x)/BITS_PER_LONG)
|
|
#define TEST_BIT(array, bit) ((array[LONG(bit)] >> OFF(bit)) & 1)
|
|
/* end copied */
|
|
|
|
#include "ecore_drm_private.h"
|
|
#include <sys/ioctl.h>
|
|
#include <linux/input.h>
|
|
#include <ctype.h>
|
|
|
|
/* local functions */
|
|
static void
|
|
_device_keyboard_setup(Ecore_Drm_Evdev *edev)
|
|
{
|
|
Ecore_Drm_Input *input;
|
|
|
|
if ((!edev) || (!edev->seat)) return;
|
|
if (!(input = edev->seat->input)) return;
|
|
if (!input->dev->xkb_ctx) return;
|
|
|
|
/* create keymap from xkb context */
|
|
edev->xkb.keymap = xkb_map_new_from_names(input->dev->xkb_ctx, NULL, 0);
|
|
if (!edev->xkb.keymap)
|
|
{
|
|
ERR("Failed to create keymap: %m");
|
|
return;
|
|
}
|
|
|
|
/* create xkb state */
|
|
if (!(edev->xkb.state = xkb_state_new(edev->xkb.keymap)))
|
|
{
|
|
ERR("Failed to create xkb state: %m");
|
|
return;
|
|
}
|
|
|
|
edev->xkb.ctrl_mask =
|
|
1 << xkb_map_mod_get_index(edev->xkb.keymap, XKB_MOD_NAME_CTRL);
|
|
edev->xkb.alt_mask =
|
|
1 << xkb_map_mod_get_index(edev->xkb.keymap, XKB_MOD_NAME_ALT);
|
|
edev->xkb.shift_mask =
|
|
1 << xkb_map_mod_get_index(edev->xkb.keymap, XKB_MOD_NAME_SHIFT);
|
|
edev->xkb.win_mask =
|
|
1 << xkb_map_mod_get_index(edev->xkb.keymap, XKB_MOD_NAME_LOGO);
|
|
edev->xkb.scroll_mask =
|
|
1 << xkb_map_mod_get_index(edev->xkb.keymap, XKB_LED_NAME_SCROLL);
|
|
edev->xkb.num_mask =
|
|
1 << xkb_map_mod_get_index(edev->xkb.keymap, XKB_LED_NAME_NUM);
|
|
edev->xkb.caps_mask =
|
|
1 << xkb_map_mod_get_index(edev->xkb.keymap, XKB_MOD_NAME_CAPS);
|
|
edev->xkb.altgr_mask =
|
|
1 << xkb_map_mod_get_index(edev->xkb.keymap, "ISO_Level3_Shift");
|
|
}
|
|
|
|
static Eina_Bool
|
|
_device_configure(Ecore_Drm_Evdev *edev)
|
|
{
|
|
Eina_Bool ret = EINA_FALSE;
|
|
|
|
if (!edev) return EINA_FALSE;
|
|
|
|
if ((edev->caps & (EVDEV_MOTION_ABS | EVDEV_MOTION_REL)) &&
|
|
(edev->caps & EVDEV_BUTTON))
|
|
{
|
|
DBG("Input device %s is a pointer", edev->name);
|
|
edev->seat_caps |= EVDEV_SEAT_POINTER;
|
|
|
|
/* FIXME: make this configurable */
|
|
edev->mouse.threshold = 0.25;
|
|
|
|
ret = EINA_TRUE;
|
|
}
|
|
|
|
if (edev->caps & EVDEV_KEYBOARD)
|
|
{
|
|
DBG("Input device %s is a keyboard", edev->name);
|
|
edev->seat_caps |= EVDEV_SEAT_KEYBOARD;
|
|
_device_keyboard_setup(edev);
|
|
ret = EINA_TRUE;
|
|
}
|
|
|
|
if (edev->caps & EVDEV_TOUCH)
|
|
{
|
|
DBG("Input device %s is a touchpad", edev->name);
|
|
edev->seat_caps |= EVDEV_SEAT_TOUCH;
|
|
ret = EINA_TRUE;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static Eina_Bool
|
|
_device_handle(Ecore_Drm_Evdev *edev)
|
|
{
|
|
struct input_absinfo absinfo;
|
|
unsigned long dev_bits[NBITS(EV_MAX)];
|
|
unsigned long abs_bits[NBITS(ABS_MAX)];
|
|
unsigned long rel_bits[NBITS(REL_MAX)];
|
|
unsigned long key_bits[NBITS(KEY_MAX)];
|
|
/* Eina_Bool have_key = EINA_FALSE; */
|
|
Eina_Bool have_abs = EINA_FALSE;
|
|
|
|
if (!edev) return EINA_FALSE;
|
|
|
|
ioctl(edev->fd, EVIOCGBIT(0, sizeof(dev_bits)), dev_bits);
|
|
if (TEST_BIT(dev_bits, EV_ABS))
|
|
{
|
|
have_abs = EINA_TRUE;
|
|
|
|
ioctl(edev->fd, EVIOCGBIT(EV_ABS, sizeof(abs_bits)), abs_bits);
|
|
|
|
if ((TEST_BIT(abs_bits, ABS_WHEEL)) ||
|
|
(TEST_BIT(abs_bits, ABS_GAS)) ||
|
|
(TEST_BIT(abs_bits, ABS_BRAKE)) ||
|
|
(TEST_BIT(abs_bits, ABS_HAT0X)))
|
|
{
|
|
/* ignore joystick */
|
|
return EINA_FALSE;
|
|
}
|
|
|
|
if (TEST_BIT(abs_bits, ABS_X))
|
|
{
|
|
ioctl(edev->fd, EVIOCGABS(ABS_X), &absinfo);
|
|
edev->abs.min_x = absinfo.minimum;
|
|
edev->abs.max_x = absinfo.maximum;
|
|
edev->abs.x[0] = edev->abs.x[1] = edev->abs.min_x - 1;
|
|
edev->mouse.x = -1;
|
|
edev->caps |= EVDEV_MOTION_ABS;
|
|
}
|
|
|
|
if (TEST_BIT(abs_bits, ABS_Y))
|
|
{
|
|
ioctl(edev->fd, EVIOCGABS(ABS_Y), &absinfo);
|
|
edev->abs.min_y = absinfo.minimum;
|
|
edev->abs.max_y = absinfo.maximum;
|
|
edev->abs.y[0] = edev->abs.y[1] = edev->abs.min_y - 1;
|
|
edev->mouse.y = -1;
|
|
edev->caps |= EVDEV_MOTION_ABS;
|
|
}
|
|
|
|
if ((TEST_BIT(abs_bits, ABS_MT_POSITION_X)) &&
|
|
(TEST_BIT(abs_bits, ABS_MT_POSITION_Y)))
|
|
{
|
|
DBG("Handle MultiTouch Device: %s", edev->path);
|
|
}
|
|
}
|
|
|
|
if (TEST_BIT(dev_bits, EV_REL))
|
|
{
|
|
ioctl(edev->fd, EVIOCGBIT(EV_REL, sizeof(rel_bits)), rel_bits);
|
|
|
|
if ((TEST_BIT(rel_bits, REL_X)) || (TEST_BIT(rel_bits, REL_Y)))
|
|
edev->caps |= EVDEV_MOTION_REL;
|
|
}
|
|
|
|
if (TEST_BIT(dev_bits, EV_KEY))
|
|
{
|
|
unsigned int i = 0;
|
|
|
|
/* have_key = EINA_TRUE; */
|
|
|
|
ioctl(edev->fd, EVIOCGBIT(EV_KEY, sizeof(key_bits)), key_bits);
|
|
|
|
if (have_abs)
|
|
{
|
|
if ((TEST_BIT(key_bits, BTN_TOOL_FINGER)) &&
|
|
(!TEST_BIT(key_bits, BTN_TOOL_PEN)))
|
|
{
|
|
DBG("Device Is Touchpad: %s", edev->path);
|
|
}
|
|
}
|
|
|
|
for (i = KEY_ESC; i < KEY_MAX; i++)
|
|
{
|
|
if ((i >= BTN_MISC) && (i < KEY_OK)) continue;
|
|
if (TEST_BIT(key_bits, i))
|
|
{
|
|
edev->caps |= EVDEV_KEYBOARD;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (TEST_BIT(key_bits, BTN_TOUCH))
|
|
edev->caps |= EVDEV_TOUCH;
|
|
|
|
for (i = BTN_MISC; i < BTN_JOYSTICK; i++)
|
|
{
|
|
if (TEST_BIT(key_bits, i))
|
|
{
|
|
edev->caps |= EVDEV_BUTTON;
|
|
edev->caps &= ~EVDEV_TOUCH;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (TEST_BIT(dev_bits, EV_LED)) edev->caps |= EVDEV_KEYBOARD;
|
|
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
static int
|
|
_device_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
|
|
_device_modifiers_update(Ecore_Drm_Evdev *edev)
|
|
{
|
|
xkb_mod_mask_t mask;
|
|
|
|
edev->xkb.modifiers = 0;
|
|
|
|
edev->xkb.depressed =
|
|
xkb_state_serialize_mods(edev->xkb.state, XKB_STATE_DEPRESSED);
|
|
edev->xkb.latched =
|
|
xkb_state_serialize_mods(edev->xkb.state, XKB_STATE_LATCHED);
|
|
edev->xkb.locked =
|
|
xkb_state_serialize_mods(edev->xkb.state, XKB_STATE_LOCKED);
|
|
edev->xkb.group =
|
|
xkb_state_serialize_mods(edev->xkb.state, XKB_STATE_EFFECTIVE);
|
|
|
|
mask = (edev->xkb.depressed | edev->xkb.latched);
|
|
|
|
if (mask & edev->xkb.ctrl_mask)
|
|
edev->xkb.modifiers |= ECORE_EVENT_MODIFIER_CTRL;
|
|
if (mask & edev->xkb.alt_mask)
|
|
edev->xkb.modifiers |= ECORE_EVENT_MODIFIER_ALT;
|
|
if (mask & edev->xkb.shift_mask)
|
|
edev->xkb.modifiers |= ECORE_EVENT_MODIFIER_SHIFT;
|
|
if (mask & edev->xkb.win_mask)
|
|
edev->xkb.modifiers |= ECORE_EVENT_MODIFIER_WIN;
|
|
if (mask & edev->xkb.scroll_mask)
|
|
edev->xkb.modifiers |= ECORE_EVENT_LOCK_SCROLL;
|
|
if (mask & edev->xkb.num_mask)
|
|
edev->xkb.modifiers |= ECORE_EVENT_LOCK_NUM;
|
|
if (mask & edev->xkb.caps_mask)
|
|
edev->xkb.modifiers |= ECORE_EVENT_LOCK_CAPS;
|
|
if (mask & edev->xkb.altgr_mask)
|
|
edev->xkb.modifiers |= ECORE_EVENT_MODIFIER_ALTGR;
|
|
}
|
|
|
|
static void
|
|
_device_notify_key(Ecore_Drm_Evdev *dev, struct input_event *event, unsigned int timestamp)
|
|
{
|
|
unsigned int code, nsyms;
|
|
unsigned int *keycode;
|
|
const xkb_keysym_t *syms;
|
|
xkb_keysym_t sym = XKB_KEY_NoSymbol;
|
|
char key[256], keyname[256], compose[256];
|
|
Ecore_Event_Key *e;
|
|
Ecore_Drm_Input *input;
|
|
int evtype;
|
|
|
|
if (!(input = dev->seat->input)) return;
|
|
|
|
/* DBG("Key Event"); */
|
|
/* DBG("\tCode: %d", event->code); */
|
|
/* DBG("\tValue: %d", event->value); */
|
|
|
|
/* xkb rules reflect X broken keycodes, so offset by 8 */
|
|
code = event->code + 8;
|
|
|
|
xkb_state_update_key(dev->xkb.state, code,
|
|
(event->value ? XKB_KEY_DOWN : XKB_KEY_UP));
|
|
|
|
/* get the keysym for this code */
|
|
nsyms = xkb_key_get_syms(dev->xkb.state, code, &syms);
|
|
if (nsyms == 1) sym = syms[0];
|
|
|
|
/* get the keyname for this sym */
|
|
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 shift is active, we need to transform the key to lower */
|
|
if (xkb_state_mod_index_is_active(dev->xkb.state,
|
|
xkb_map_mod_get_index(dev->xkb.keymap,
|
|
XKB_MOD_NAME_SHIFT),
|
|
XKB_STATE_MODS_EFFECTIVE))
|
|
{
|
|
if (keyname[0] != '\0')
|
|
keyname[0] = tolower(keyname[0]);
|
|
}
|
|
|
|
memset(compose, 0, sizeof(compose));
|
|
_device_keysym_translate(sym, dev->xkb.modifiers, compose, sizeof(compose));
|
|
|
|
e = malloc(sizeof(Ecore_Event_Key) + strlen(key) + strlen(keyname) +
|
|
((compose[0] != '\0') ? strlen(compose) : 0) + 3);
|
|
if (!e) return;
|
|
|
|
e->keyname = (char *)(e + 1);
|
|
e->key = e->keyname + strlen(keyname) + 1;
|
|
e->compose = strlen(compose) ? e->key + strlen(key) + 1 : NULL;
|
|
e->string = e->compose;
|
|
|
|
strcpy((char *)e->keyname, keyname);
|
|
strcpy((char *)e->key, key);
|
|
if (strlen(compose)) strcpy((char *)e->compose, compose);
|
|
|
|
e->window = (Ecore_Window)input->dev->window;
|
|
e->event_window = (Ecore_Window)input->dev->window;
|
|
e->root_window = (Ecore_Window)input->dev->window;
|
|
e->timestamp = timestamp;
|
|
e->same_screen = 1;
|
|
e->keycode = event->code;
|
|
e->data = NULL;
|
|
|
|
_device_modifiers_update(dev);
|
|
e->modifiers = dev->xkb.modifiers;
|
|
|
|
if (event->value)
|
|
evtype = ECORE_EVENT_KEY_DOWN;
|
|
else
|
|
evtype = ECORE_EVENT_KEY_UP;
|
|
|
|
ecore_event_add(evtype, e, NULL, NULL);
|
|
}
|
|
|
|
static void
|
|
_device_notify_motion(Ecore_Drm_Evdev *dev, unsigned int timestamp)
|
|
{
|
|
Ecore_Drm_Input *input;
|
|
Ecore_Event_Mouse_Move *ev;
|
|
|
|
if (!(input = dev->seat->input)) return;
|
|
if (!(ev = calloc(1, sizeof(Ecore_Event_Mouse_Move)))) return;
|
|
|
|
ev->window = (Ecore_Window)input->dev->window;
|
|
ev->event_window = (Ecore_Window)input->dev->window;
|
|
ev->root_window = (Ecore_Window)input->dev->window;
|
|
ev->timestamp = timestamp;
|
|
ev->same_screen = 1;
|
|
|
|
/* NB: Commented out. This borks mouse movement if no key has been
|
|
* pressed yet due to 'state' not being set */
|
|
// _device_modifiers_update(dev);
|
|
ev->modifiers = dev->xkb.modifiers;
|
|
|
|
ev->x = dev->mouse.x;
|
|
ev->y = dev->mouse.y;
|
|
ev->root.x = ev->x;
|
|
ev->root.y = ev->y;
|
|
|
|
ecore_event_add(ECORE_EVENT_MOUSE_MOVE, ev, NULL, NULL);
|
|
}
|
|
|
|
static void
|
|
_device_notify_wheel(Ecore_Drm_Evdev *dev, struct input_event *event, unsigned int timestamp)
|
|
{
|
|
Ecore_Drm_Input *input;
|
|
Ecore_Event_Mouse_Wheel *ev;
|
|
|
|
if (!(input = dev->seat->input)) return;
|
|
if (!(ev = calloc(1, sizeof(Ecore_Event_Mouse_Wheel)))) return;
|
|
|
|
ev->window = (Ecore_Window)input->dev->window;
|
|
ev->event_window = (Ecore_Window)input->dev->window;
|
|
ev->root_window = (Ecore_Window)input->dev->window;
|
|
ev->timestamp = timestamp;
|
|
ev->same_screen = 1;
|
|
|
|
/* NB: Commented out. This borks mouse wheel if no key has been
|
|
* pressed yet due to 'state' not being set */
|
|
// _device_modifiers_update(dev);
|
|
ev->modifiers = dev->xkb.modifiers;
|
|
|
|
ev->x = dev->mouse.x;
|
|
ev->y = dev->mouse.y;
|
|
ev->root.x = ev->x;
|
|
ev->root.y = ev->y;
|
|
if (event->value == REL_HWHEEL) ev->direction = 1;
|
|
ev->z = -event->value;
|
|
|
|
ecore_event_add(ECORE_EVENT_MOUSE_WHEEL, ev, NULL, NULL);
|
|
}
|
|
|
|
static void
|
|
_device_notify_button(Ecore_Drm_Evdev *dev, struct input_event *event, unsigned int timestamp)
|
|
{
|
|
Ecore_Drm_Input *input;
|
|
Ecore_Event_Mouse_Button *ev;
|
|
int button;
|
|
|
|
if (!(input = dev->seat->input)) return;
|
|
if (!(ev = calloc(1, sizeof(Ecore_Event_Mouse_Button)))) return;
|
|
|
|
ev->window = (Ecore_Window)input->dev->window;
|
|
ev->event_window = (Ecore_Window)input->dev->window;
|
|
ev->root_window = (Ecore_Window)input->dev->window;
|
|
ev->timestamp = timestamp;
|
|
ev->same_screen = 1;
|
|
|
|
/* NB: Commented out. This borks mouse button if no key has been
|
|
* pressed yet due to 'state' not being set */
|
|
// _device_modifiers_update(dev);
|
|
ev->modifiers = dev->xkb.modifiers;
|
|
|
|
ev->x = dev->mouse.x;
|
|
ev->y = dev->mouse.y;
|
|
ev->root.x = ev->x;
|
|
ev->root.y = ev->y;
|
|
|
|
button = ((event->code & 0x00F) + 1);
|
|
|
|
/* swap buttons 2 & 3 so behaviour is like X */
|
|
if (button == 3) button = 2;
|
|
else if (button == 2) button = 3;
|
|
|
|
if (event->value)
|
|
{
|
|
unsigned int current;
|
|
|
|
current = timestamp;
|
|
dev->mouse.did_double = EINA_FALSE;
|
|
dev->mouse.did_triple = EINA_FALSE;
|
|
|
|
if (((current - dev->mouse.prev) <= dev->mouse.threshold) &&
|
|
(button == dev->mouse.prev_button))
|
|
{
|
|
dev->mouse.did_double = EINA_TRUE;
|
|
if (((current - dev->mouse.last) <= (2 * dev->mouse.threshold)) &&
|
|
(button == dev->mouse.last_button))
|
|
{
|
|
dev->mouse.did_triple = EINA_TRUE;
|
|
dev->mouse.prev = 0;
|
|
dev->mouse.last = 0;
|
|
current = 0;
|
|
}
|
|
}
|
|
|
|
dev->mouse.last = dev->mouse.prev;
|
|
dev->mouse.prev = current;
|
|
dev->mouse.last_button = dev->mouse.prev_button;
|
|
dev->mouse.prev_button = button;
|
|
}
|
|
|
|
ev->buttons = button;
|
|
if (dev->mouse.did_double)
|
|
ev->double_click = 1;
|
|
if (dev->mouse.did_triple)
|
|
ev->triple_click = 1;
|
|
|
|
if (event->value)
|
|
ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, ev, NULL, NULL);
|
|
else
|
|
ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_UP, ev, NULL, NULL);
|
|
}
|
|
|
|
static void
|
|
_device_process_flush(Ecore_Drm_Evdev *dev, unsigned int timestamp)
|
|
{
|
|
switch (dev->pending_event)
|
|
{
|
|
case EVDEV_NONE:
|
|
return;
|
|
case EVDEV_RELATIVE_MOTION:
|
|
_device_notify_motion(dev, timestamp);
|
|
/* dev->mouse.x = 0; */
|
|
/* dev->mouse.y = 0; */
|
|
goto out;
|
|
break;
|
|
case EVDEV_ABSOLUTE_MT_DOWN:
|
|
goto out;
|
|
break;
|
|
case EVDEV_ABSOLUTE_MT_MOTION:
|
|
goto out;
|
|
break;
|
|
case EVDEV_ABSOLUTE_MT_UP:
|
|
goto out;
|
|
break;
|
|
case EVDEV_ABSOLUTE_TOUCH_DOWN:
|
|
goto out;
|
|
break;
|
|
case EVDEV_ABSOLUTE_MOTION:
|
|
/* FIXME what the actual fuck */
|
|
if ((dev->mouse.x == -1) && (dev->mouse.y == -1))
|
|
{
|
|
/* start first motion as centered I guess? */
|
|
dev->mouse.x = (dev->abs.min_x + dev->abs.max_x) / 2;
|
|
dev->mouse.y = (dev->abs.min_y + dev->abs.max_y) / 2;
|
|
}
|
|
|
|
dev->mouse.x += (dev->abs.x[0] - dev->abs.x[1]);
|
|
dev->mouse.y += (dev->abs.y[0] - dev->abs.y[1]);
|
|
dev->mouse.x = MAX(dev->abs.min_x, dev->mouse.x);
|
|
dev->mouse.y = MAX(dev->abs.min_y, dev->mouse.y);
|
|
dev->mouse.x = MIN(dev->abs.max_x, dev->mouse.x);
|
|
dev->mouse.y = MIN(dev->abs.max_y, dev->mouse.y);
|
|
_device_notify_motion(dev, timestamp);
|
|
break;
|
|
case EVDEV_ABSOLUTE_TOUCH_UP:
|
|
goto out;
|
|
break;
|
|
}
|
|
|
|
out:
|
|
dev->pending_event = EVDEV_NONE;
|
|
}
|
|
|
|
static void
|
|
_device_process_key(Ecore_Drm_Evdev *dev, struct input_event *event, unsigned int timestamp)
|
|
{
|
|
/* ignore key repeat */
|
|
if (event->value == 2) return;
|
|
|
|
_device_process_flush(dev, timestamp);
|
|
|
|
if ((event->code >= BTN_LEFT) && (event->code <= BTN_TASK))
|
|
_device_notify_button(dev, event, timestamp);
|
|
else if ((event->code >= KEY_ESC) && (event->code <= KEY_MICMUTE))
|
|
_device_notify_key(dev, event, timestamp);
|
|
else if ((event->code == BTN_TOUCH) && (dev->caps & EVDEV_MOTION_ABS))
|
|
{
|
|
dev->abs.down = event->value;
|
|
if (!dev->abs.down)
|
|
{
|
|
dev->abs.x[0] = dev->abs.x[1] = dev->abs.min_x - 1;
|
|
dev->abs.y[0] = dev->abs.y[1] = dev->abs.min_y - 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
_device_process_absolute(Ecore_Drm_Evdev *dev, struct input_event *event, unsigned int timestamp)
|
|
{
|
|
switch (event->code)
|
|
{
|
|
case ABS_X:
|
|
if (dev->pending_event != EVDEV_ABSOLUTE_MOTION)
|
|
_device_process_flush(dev, timestamp);
|
|
dev->abs.x[1] = dev->abs.x[0];
|
|
dev->abs.x[0] = event->value;
|
|
if (dev->abs.x[1] == dev->abs.min_x - 1)
|
|
dev->abs.x[1] = dev->abs.x[0];
|
|
dev->pending_event = EVDEV_ABSOLUTE_MOTION;
|
|
break;
|
|
case ABS_Y:
|
|
if (dev->pending_event != EVDEV_ABSOLUTE_MOTION)
|
|
_device_process_flush(dev, timestamp);
|
|
dev->abs.y[1] = dev->abs.y[0];
|
|
dev->abs.y[0] = event->value;
|
|
if (dev->abs.y[1] == dev->abs.min_y - 1)
|
|
dev->abs.y[1] = dev->abs.y[0];
|
|
dev->pending_event = EVDEV_ABSOLUTE_MOTION;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
_device_process_relative(Ecore_Drm_Evdev *dev, struct input_event *event, unsigned int timestamp)
|
|
{
|
|
switch (event->code)
|
|
{
|
|
case REL_X:
|
|
if (dev->pending_event != EVDEV_RELATIVE_MOTION)
|
|
_device_process_flush(dev, timestamp);
|
|
dev->mouse.x += event->value;
|
|
dev->pending_event = EVDEV_RELATIVE_MOTION;
|
|
break;
|
|
case REL_Y:
|
|
if (dev->pending_event != EVDEV_RELATIVE_MOTION)
|
|
_device_process_flush(dev, timestamp);
|
|
dev->mouse.y += event->value;
|
|
dev->pending_event = EVDEV_RELATIVE_MOTION;
|
|
break;
|
|
case REL_WHEEL:
|
|
case REL_HWHEEL:
|
|
_device_process_flush(dev, timestamp);
|
|
_device_notify_wheel(dev, event, timestamp);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
_device_process(Ecore_Drm_Evdev *dev, struct input_event *event, int count)
|
|
{
|
|
struct input_event *ev, *end;
|
|
unsigned int timestamp = 0;
|
|
|
|
ev = event;
|
|
end = ev + count;
|
|
for (ev = event; ev < end; ev++)
|
|
{
|
|
timestamp = (ev->time.tv_sec * 1000) + (ev->time.tv_usec / 1000);
|
|
|
|
switch (ev->type)
|
|
{
|
|
case EV_KEY:
|
|
_device_process_key(dev, ev, timestamp);
|
|
break;
|
|
case EV_REL:
|
|
_device_process_relative(dev, ev, timestamp);
|
|
break;
|
|
case EV_ABS:
|
|
_device_process_absolute(dev, ev, timestamp);
|
|
break;
|
|
case EV_SYN:
|
|
_device_process_flush(dev, timestamp);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static Eina_Bool
|
|
_cb_device_data(void *data, Ecore_Fd_Handler *hdlr EINA_UNUSED)
|
|
{
|
|
Ecore_Drm_Evdev *edev;
|
|
struct input_event ev[32];
|
|
int len = 0;
|
|
|
|
if (!(edev = data)) return EINA_TRUE;
|
|
|
|
do
|
|
{
|
|
len = read(edev->fd, &ev, sizeof(ev));
|
|
|
|
if ((len < 0) || ((len % sizeof(ev[0])) != 0))
|
|
{
|
|
if ((len < 0) && (errno != EAGAIN) && (errno != EINTR))
|
|
{
|
|
ERR("Device Died");
|
|
}
|
|
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
edev->event_process(edev, ev, (len / sizeof(ev[0])));
|
|
|
|
} while (len > 0);
|
|
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
/* external functions */
|
|
Ecore_Drm_Evdev *
|
|
_ecore_drm_evdev_device_create(Ecore_Drm_Seat *seat, const char *path, int fd)
|
|
{
|
|
Ecore_Drm_Evdev *edev;
|
|
char name[256] = "unknown";
|
|
|
|
if (!(edev = calloc(1, sizeof(Ecore_Drm_Evdev))))
|
|
return NULL;
|
|
|
|
edev->seat = seat;
|
|
edev->path = eina_stringshare_add(path);
|
|
edev->fd = fd;
|
|
|
|
if (ioctl(edev->fd, EVIOCGNAME(sizeof(name)), name) < 0)
|
|
DBG("Error getting device name: %m");
|
|
|
|
name[sizeof(name) - 1] = '\0';
|
|
edev->name = eina_stringshare_add(name);
|
|
|
|
if (!_device_handle(edev))
|
|
{
|
|
ERR("Unhandled Input Device: %s", name);
|
|
_ecore_drm_evdev_device_destroy(edev);
|
|
return NULL;
|
|
}
|
|
|
|
if (!_device_configure(edev))
|
|
{
|
|
_ecore_drm_evdev_device_destroy(edev);
|
|
return NULL;
|
|
}
|
|
|
|
edev->event_process = _device_process;
|
|
|
|
edev->hdlr =
|
|
ecore_main_fd_handler_add(edev->fd, ECORE_FD_READ,
|
|
_cb_device_data, edev, NULL, NULL);
|
|
if (!edev->hdlr)
|
|
{
|
|
ERR("Could not create fd handler");
|
|
_ecore_drm_evdev_device_destroy(edev);
|
|
return NULL;
|
|
}
|
|
|
|
return edev;
|
|
}
|
|
|
|
void
|
|
_ecore_drm_evdev_device_destroy(Ecore_Drm_Evdev *dev)
|
|
{
|
|
if (!dev) return;
|
|
|
|
if (dev->xkb.state) xkb_state_unref(dev->xkb.state);
|
|
if (dev->xkb.keymap) xkb_map_unref(dev->xkb.keymap);
|
|
|
|
if (dev->path) eina_stringshare_del(dev->path);
|
|
if (dev->name) eina_stringshare_del(dev->name);
|
|
if (dev->hdlr) ecore_main_fd_handler_del(dev->hdlr);
|
|
|
|
free(dev);
|
|
}
|