X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fevdev.c;h=63eaa4dfaa32a0500af21a7815b5b31f009bec43;hb=967911791f9988be63b8a2c1ffb608eb2871889b;hp=adaaa8138fd4f9e92959f7deeb16c62cca62c19c;hpb=6eebf356535ed0f98e0b06fc8100175d599342d6;p=platform%2Fupstream%2Flibinput.git diff --git a/src/evdev.c b/src/evdev.c index adaaa81..63eaa4d 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -26,17 +26,20 @@ #include #include #include -#include +#include "linux/input.h" #include #include -#include +#include #include +#include +#include #include "libinput.h" #include "evdev.h" +#include "filter.h" #include "libinput-private.h" -#define DEFAULT_AXIS_STEP_DISTANCE li_fixed_from_int(10) +#define DEFAULT_AXIS_STEP_DISTANCE 10 void evdev_device_led_update(struct evdev_device *device, enum libinput_led leds) @@ -86,12 +89,39 @@ transform_absolute(struct evdev_device *device, int32_t *x, int32_t *y) } } +static inline double +scale_axis(const struct input_absinfo *absinfo, double val, double to_range) +{ + return (val - absinfo->minimum) * to_range / + (absinfo->maximum - absinfo->minimum + 1); +} + +double +evdev_device_transform_x(struct evdev_device *device, + double x, + uint32_t width) +{ + return scale_axis(device->abs.absinfo_x, x, width); +} + +double +evdev_device_transform_y(struct evdev_device *device, + double y, + uint32_t height) +{ + return scale_axis(device->abs.absinfo_y, y, height); +} + static void -evdev_flush_pending_event(struct evdev_device *device, uint32_t time) +evdev_flush_pending_event(struct evdev_device *device, uint64_t time) { + struct motion_params motion; int32_t cx, cy; + double x, y; int slot; + int seat_slot; struct libinput_device *base = &device->base; + struct libinput_seat *seat = base->seat; slot = device->mt.slot; @@ -99,76 +129,131 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) case EVDEV_NONE: return; case EVDEV_RELATIVE_MOTION: - pointer_notify_motion(base, - time, - device->rel.dx, - device->rel.dy); + motion.dx = device->rel.dx; + motion.dy = device->rel.dy; device->rel.dx = 0; device->rel.dy = 0; - goto handled; + + /* Apply pointer acceleration. */ + filter_dispatch(device->pointer.filter, &motion, device, time); + + if (motion.dx == 0.0 && motion.dy == 0.0) + break; + + pointer_notify_motion(base, time, motion.dx, motion.dy); + break; case EVDEV_ABSOLUTE_MT_DOWN: - touch_notify_touch(base, - time, - slot, - li_fixed_from_int(device->mt.slots[slot].x), - li_fixed_from_int(device->mt.slots[slot].y), - LIBINPUT_TOUCH_TYPE_DOWN); - goto handled; + if (!(device->seat_caps & EVDEV_DEVICE_TOUCH)) + break; + + if (device->mt.slots[slot].seat_slot != -1) { + log_bug_kernel("%s: Driver sent multiple touch down for the " + "same slot", device->devnode); + break; + } + + seat_slot = ffs(~seat->slot_map) - 1; + device->mt.slots[slot].seat_slot = seat_slot; + + if (seat_slot == -1) + break; + + seat->slot_map |= 1 << seat_slot; + x = device->mt.slots[slot].x; + y = device->mt.slots[slot].y; + + touch_notify_touch_down(base, time, slot, seat_slot, x, y); + break; case EVDEV_ABSOLUTE_MT_MOTION: - touch_notify_touch(base, - time, - slot, - li_fixed_from_int(device->mt.slots[slot].x), - li_fixed_from_int(device->mt.slots[slot].y), - LIBINPUT_TOUCH_TYPE_MOTION); - goto handled; + if (!(device->seat_caps & EVDEV_DEVICE_TOUCH)) + break; + + seat_slot = device->mt.slots[slot].seat_slot; + x = device->mt.slots[slot].x; + y = device->mt.slots[slot].y; + + if (seat_slot == -1) + break; + + touch_notify_touch_motion(base, time, slot, seat_slot, x, y); + break; case EVDEV_ABSOLUTE_MT_UP: - touch_notify_touch(base, - time, - slot, - 0, 0, - LIBINPUT_TOUCH_TYPE_UP); - goto handled; + if (!(device->seat_caps & EVDEV_DEVICE_TOUCH)) + break; + + seat_slot = device->mt.slots[slot].seat_slot; + device->mt.slots[slot].seat_slot = -1; + + if (seat_slot == -1) + break; + + seat->slot_map &= ~(1 << seat_slot); + + touch_notify_touch_up(base, time, slot, seat_slot); + break; case EVDEV_ABSOLUTE_TOUCH_DOWN: + if (!(device->seat_caps & EVDEV_DEVICE_TOUCH)) + break; + + if (device->abs.seat_slot != -1) { + log_bug_kernel("%s: Driver sent multiple touch down for the " + "same slot", device->devnode); + break; + } + + seat_slot = ffs(~seat->slot_map) - 1; + device->abs.seat_slot = seat_slot; + + if (seat_slot == -1) + break; + + seat->slot_map |= 1 << seat_slot; + transform_absolute(device, &cx, &cy); - touch_notify_touch(base, - time, - slot, - li_fixed_from_int(cx), - li_fixed_from_int(cy), - LIBINPUT_TOUCH_TYPE_DOWN); - goto handled; + + touch_notify_touch_down(base, time, -1, seat_slot, cx, cy); + break; case EVDEV_ABSOLUTE_MOTION: transform_absolute(device, &cx, &cy); + x = cx; + y = cy; + if (device->seat_caps & EVDEV_DEVICE_TOUCH) { - touch_notify_touch(base, - time, - slot, - li_fixed_from_int(cx), - li_fixed_from_int(cy), - LIBINPUT_TOUCH_TYPE_DOWN); - } else { - pointer_notify_motion_absolute(base, - time, - li_fixed_from_int(cx), - li_fixed_from_int(cy)); + seat_slot = device->abs.seat_slot; + + if (seat_slot == -1) + break; + + touch_notify_touch_motion(base, time, -1, seat_slot, x, y); + } else if (device->seat_caps & EVDEV_DEVICE_POINTER) { + pointer_notify_motion_absolute(base, time, x, y); } - goto handled; + break; case EVDEV_ABSOLUTE_TOUCH_UP: - touch_notify_touch(base, - time, - 0, 0, 0, LIBINPUT_TOUCH_TYPE_UP); - goto handled; - } + if (!(device->seat_caps & EVDEV_DEVICE_TOUCH)) + break; + + seat_slot = device->abs.seat_slot; + device->abs.seat_slot = -1; - assert(0 && "Unknown pending event type"); + if (seat_slot == -1) + break; + + seat->slot_map &= ~(1 << seat_slot); + + touch_notify_touch_up(base, time, -1, seat_slot); + break; + default: + assert(0 && "Unknown pending event type"); + break; + } -handled: device->pending_event = EVDEV_NONE; } static void -evdev_process_touch_button(struct evdev_device *device, int time, int value) +evdev_process_touch_button(struct evdev_device *device, + uint64_t time, int value) { if (device->pending_event != EVDEV_NONE && device->pending_event != EVDEV_ABSOLUTE_MOTION) @@ -180,12 +265,16 @@ evdev_process_touch_button(struct evdev_device *device, int time, int value) } static inline void -evdev_process_key(struct evdev_device *device, struct input_event *e, int time) +evdev_process_key(struct evdev_device *device, + struct input_event *e, uint64_t time) { /* ignore kernel key repeat */ if (e->value == 2) return; + if (e->code > KEY_MAX) + return; + if (e->code == BTN_TOUCH) { if (!device->is_mt) evdev_process_touch_button(device, time, e->value); @@ -207,17 +296,22 @@ evdev_process_key(struct evdev_device *device, struct input_event *e, int time) &device->base, time, e->code, - e->value ? LIBINPUT_POINTER_BUTTON_STATE_PRESSED : - LIBINPUT_POINTER_BUTTON_STATE_RELEASED); + e->value ? LIBINPUT_BUTTON_STATE_PRESSED : + LIBINPUT_BUTTON_STATE_RELEASED); break; default: + /* Only let KEY_* codes pass through. */ + if (!(e->code <= KEY_MICMUTE || + (e->code >= KEY_OK && e->code <= KEY_LIGHTS_TOGGLE))) + break; + keyboard_notify_key( &device->base, time, e->code, - e->value ? LIBINPUT_KEYBOARD_KEY_STATE_PRESSED : - LIBINPUT_KEYBOARD_KEY_STATE_RELEASED); + e->value ? LIBINPUT_KEY_STATE_PRESSED : + LIBINPUT_KEY_STATE_RELEASED); break; } } @@ -225,18 +319,8 @@ evdev_process_key(struct evdev_device *device, struct input_event *e, int time) static void evdev_process_touch(struct evdev_device *device, struct input_event *e, - uint32_t time) + uint64_t time) { - struct libinput *libinput = device->base.seat->libinput; - int screen_width; - int screen_height; - - libinput->interface->get_current_screen_dimensions( - &device->base, - &screen_width, - &screen_height, - libinput->user_data); - switch (e->code) { case ABS_MT_SLOT: evdev_flush_pending_event(device, time); @@ -252,16 +336,12 @@ evdev_process_touch(struct evdev_device *device, device->pending_event = EVDEV_ABSOLUTE_MT_UP; break; case ABS_MT_POSITION_X: - device->mt.slots[device->mt.slot].x = - (e->value - device->abs.min_x) * screen_width / - (device->abs.max_x - device->abs.min_x); + device->mt.slots[device->mt.slot].x = e->value; if (device->pending_event == EVDEV_NONE) device->pending_event = EVDEV_ABSOLUTE_MT_MOTION; break; case ABS_MT_POSITION_Y: - device->mt.slots[device->mt.slot].y = - (e->value - device->abs.min_y) * screen_height / - (device->abs.max_y - device->abs.min_y); + device->mt.slots[device->mt.slot].y = e->value; if (device->pending_event == EVDEV_NONE) device->pending_event = EVDEV_ABSOLUTE_MT_MOTION; break; @@ -272,28 +352,14 @@ static inline void evdev_process_absolute_motion(struct evdev_device *device, struct input_event *e) { - struct libinput *libinput = device->base.seat->libinput; - int screen_width; - int screen_height; - - libinput->interface->get_current_screen_dimensions( - &device->base, - &screen_width, - &screen_height, - libinput->user_data); - switch (e->code) { case ABS_X: - device->abs.x = - (e->value - device->abs.min_x) * screen_width / - (device->abs.max_x - device->abs.min_x); + device->abs.x = e->value; if (device->pending_event == EVDEV_NONE) device->pending_event = EVDEV_ABSOLUTE_MOTION; break; case ABS_Y: - device->abs.y = - (e->value - device->abs.min_y) * screen_height / - (device->abs.max_y - device->abs.min_y); + device->abs.y = e->value; if (device->pending_event == EVDEV_NONE) device->pending_event = EVDEV_ABSOLUTE_MOTION; break; @@ -302,7 +368,7 @@ evdev_process_absolute_motion(struct evdev_device *device, static inline void evdev_process_relative(struct evdev_device *device, - struct input_event *e, uint32_t time) + struct input_event *e, uint64_t time) { struct libinput_device *base = &device->base; @@ -310,31 +376,22 @@ evdev_process_relative(struct evdev_device *device, case REL_X: if (device->pending_event != EVDEV_RELATIVE_MOTION) evdev_flush_pending_event(device, time); - device->rel.dx += li_fixed_from_int(e->value); + device->rel.dx += e->value; device->pending_event = EVDEV_RELATIVE_MOTION; break; case REL_Y: if (device->pending_event != EVDEV_RELATIVE_MOTION) evdev_flush_pending_event(device, time); - device->rel.dy += li_fixed_from_int(e->value); + device->rel.dy += e->value; device->pending_event = EVDEV_RELATIVE_MOTION; break; case REL_WHEEL: evdev_flush_pending_event(device, time); - switch (e->value) { - case -1: - /* Scroll down */ - case 1: - /* Scroll up */ - pointer_notify_axis( - base, - time, - LIBINPUT_POINTER_AXIS_VERTICAL_SCROLL, - -1 * e->value * DEFAULT_AXIS_STEP_DISTANCE); - break; - default: - break; - } + pointer_notify_axis( + base, + time, + LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, + -1 * e->value * DEFAULT_AXIS_STEP_DISTANCE); break; case REL_HWHEEL: evdev_flush_pending_event(device, time); @@ -346,7 +403,7 @@ evdev_process_relative(struct evdev_device *device, pointer_notify_axis( base, time, - LIBINPUT_POINTER_AXIS_HORIZONTAL_SCROLL, + LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, e->value * DEFAULT_AXIS_STEP_DISTANCE); break; default: @@ -359,7 +416,7 @@ evdev_process_relative(struct evdev_device *device, static inline void evdev_process_absolute(struct evdev_device *device, struct input_event *e, - uint32_t time) + uint64_t time) { if (device->is_mt) { evdev_process_touch(device, e, time); @@ -368,12 +425,36 @@ evdev_process_absolute(struct evdev_device *device, } } +static inline int +evdev_need_touch_frame(struct evdev_device *device) +{ + if (!(device->seat_caps & EVDEV_DEVICE_TOUCH)) + return 0; + + switch (device->pending_event) { + case EVDEV_NONE: + case EVDEV_RELATIVE_MOTION: + break; + case EVDEV_ABSOLUTE_MT_DOWN: + case EVDEV_ABSOLUTE_MT_MOTION: + case EVDEV_ABSOLUTE_MT_UP: + case EVDEV_ABSOLUTE_TOUCH_DOWN: + case EVDEV_ABSOLUTE_TOUCH_UP: + case EVDEV_ABSOLUTE_MOTION: + return 1; + } + + return 0; +} + static void fallback_process(struct evdev_dispatch *dispatch, struct evdev_device *device, struct input_event *event, - uint32_t time) + uint64_t time) { + int need_frame = 0; + switch (event->type) { case EV_REL: evdev_process_relative(device, event, time); @@ -385,7 +466,10 @@ fallback_process(struct evdev_dispatch *dispatch, evdev_process_key(device, event, time); break; case EV_SYN: + need_frame = evdev_need_touch_frame(device); evdev_flush_pending_event(device, time); + if (need_frame) + touch_notify_frame(&device->base, time); break; } } @@ -413,71 +497,111 @@ fallback_dispatch_create(void) return dispatch; } -static void -evdev_process_events(struct evdev_device *device, - struct input_event *ev, int count) +static inline void +evdev_process_event(struct evdev_device *device, struct input_event *e) { struct evdev_dispatch *dispatch = device->dispatch; - struct input_event *e, *end; - uint32_t time = 0; + uint64_t time = e->time.tv_sec * 1000ULL + e->time.tv_usec / 1000; - e = ev; - end = e + count; - for (e = ev; e < end; e++) { - time = e->time.tv_sec * 1000 + e->time.tv_usec / 1000; + dispatch->interface->process(dispatch, device, e, time); +} - dispatch->interface->process(dispatch, device, e, time); +static inline void +evdev_device_dispatch_one(struct evdev_device *device, + struct input_event *ev) +{ + if (!device->mtdev) { + evdev_process_event(device, ev); + } else { + mtdev_put_event(device->mtdev, ev); + if (libevdev_event_is_code(ev, EV_SYN, SYN_REPORT)) { + while (!mtdev_empty(device->mtdev)) { + struct input_event e; + mtdev_get_event(device->mtdev, &e); + evdev_process_event(device, &e); + } + } } } +static int +evdev_sync_device(struct evdev_device *device) +{ + struct input_event ev; + int rc; + + do { + rc = libevdev_next_event(device->evdev, + LIBEVDEV_READ_FLAG_SYNC, &ev); + if (rc < 0) + break; + evdev_device_dispatch_one(device, &ev); + } while (rc == LIBEVDEV_READ_STATUS_SYNC); + + return rc == -EAGAIN ? 0 : rc; +} + static void evdev_device_dispatch(void *data) { struct evdev_device *device = data; struct libinput *libinput = device->base.seat->libinput; - int fd = device->fd; - struct input_event ev[32]; - int len; + struct input_event ev; + int rc; /* If the compositor is repainting, this function is called only once * per frame and we have to process all the events available on the * fd, otherwise there will be input lag. */ do { - if (device->mtdev) - len = mtdev_get(device->mtdev, fd, ev, - ARRAY_LENGTH(ev)) * - sizeof (struct input_event); - else - len = read(fd, &ev, sizeof ev); - - if (len < 0 || len % sizeof ev[0] != 0) { - if (len < 0 && errno != EAGAIN && errno != EINTR) { - libinput_remove_source(libinput, - device->source); - device->source = NULL; - } - - return; + rc = libevdev_next_event(device->evdev, + LIBEVDEV_READ_FLAG_NORMAL, &ev); + if (rc == LIBEVDEV_READ_STATUS_SYNC) { + /* send one more sync event so we handle all + currently pending events before we sync up + to the current state */ + ev.code = SYN_REPORT; + evdev_device_dispatch_one(device, &ev); + + rc = evdev_sync_device(device); + if (rc == 0) + rc = LIBEVDEV_READ_STATUS_SUCCESS; + } else if (rc == LIBEVDEV_READ_STATUS_SUCCESS) { + evdev_device_dispatch_one(device, &ev); } + } while (rc == LIBEVDEV_READ_STATUS_SUCCESS); - evdev_process_events(device, ev, len / sizeof ev[0]); + if (rc != -EAGAIN && rc != -EINTR) { + libinput_remove_source(libinput, device->source); + device->source = NULL; + } +} - } while (len > 0); +static int +configure_pointer_acceleration(struct evdev_device *device) +{ + device->pointer.filter = + create_pointer_accelator_filter( + pointer_accel_profile_smooth_simple); + if (!device->pointer.filter) + return -1; + + return 0; } static int evdev_configure_device(struct evdev_device *device) { - struct input_absinfo absinfo; - unsigned long ev_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)]; - int has_key, has_abs, has_rel, has_mt; + struct libevdev *evdev = device->evdev; + const struct input_absinfo *absinfo; + struct input_absinfo fixed; + int has_abs, has_rel, has_mt; int has_button, has_keyboard, has_touch; + struct mt_slot *slots; + int num_slots; + int active_slot; + int slot; unsigned int i; - has_key = 0; has_rel = 0; has_abs = 0; has_mt = 0; @@ -485,137 +609,162 @@ evdev_configure_device(struct evdev_device *device) has_keyboard = 0; has_touch = 0; - ioctl(device->fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits); - if (TEST_BIT(ev_bits, EV_ABS)) { - ioctl(device->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)) { - /* Device %s is a joystick, ignoring. */ - return 0; - } + if (libevdev_has_event_type(evdev, EV_ABS)) { - if (TEST_BIT(abs_bits, ABS_X)) { - ioctl(device->fd, EVIOCGABS(ABS_X), &absinfo); - device->abs.min_x = absinfo.minimum; - device->abs.max_x = absinfo.maximum; + if ((absinfo = libevdev_get_abs_info(evdev, ABS_X))) { + if (absinfo->resolution == 0) { + fixed = *absinfo; + fixed.resolution = 1; + libevdev_set_abs_info(evdev, ABS_X, &fixed); + } + device->abs.absinfo_x = absinfo; has_abs = 1; } - if (TEST_BIT(abs_bits, ABS_Y)) { - ioctl(device->fd, EVIOCGABS(ABS_Y), &absinfo); - device->abs.min_y = absinfo.minimum; - device->abs.max_y = absinfo.maximum; + if ((absinfo = libevdev_get_abs_info(evdev, ABS_Y))) { + if (absinfo->resolution == 0) { + fixed = *absinfo; + fixed.resolution = 1; + libevdev_set_abs_info(evdev, ABS_Y, &fixed); + } + device->abs.absinfo_y = absinfo; has_abs = 1; } /* We only handle the slotted Protocol B in weston. Devices with ABS_MT_POSITION_* but not ABS_MT_SLOT require mtdev for conversion. */ - if (TEST_BIT(abs_bits, ABS_MT_POSITION_X) && - TEST_BIT(abs_bits, ABS_MT_POSITION_Y)) { - ioctl(device->fd, EVIOCGABS(ABS_MT_POSITION_X), - &absinfo); - device->abs.min_x = absinfo.minimum; - device->abs.max_x = absinfo.maximum; - ioctl(device->fd, EVIOCGABS(ABS_MT_POSITION_Y), - &absinfo); - device->abs.min_y = absinfo.minimum; - device->abs.max_y = absinfo.maximum; + if (libevdev_has_event_code(evdev, EV_ABS, ABS_MT_POSITION_X) && + libevdev_has_event_code(evdev, EV_ABS, ABS_MT_POSITION_Y)) { + absinfo = libevdev_get_abs_info(evdev, ABS_MT_POSITION_X); + if (absinfo->resolution == 0) { + fixed = *absinfo; + fixed.resolution = 1; + libevdev_set_abs_info(evdev, + ABS_MT_POSITION_X, + &fixed); + } + device->abs.absinfo_x = absinfo; + absinfo = libevdev_get_abs_info(evdev, ABS_MT_POSITION_Y); + if (absinfo->resolution == 0) { + fixed = *absinfo; + fixed.resolution = 1; + libevdev_set_abs_info(evdev, + ABS_MT_POSITION_Y, + &fixed); + } + device->abs.absinfo_y = absinfo; device->is_mt = 1; has_touch = 1; has_mt = 1; - if (!TEST_BIT(abs_bits, ABS_MT_SLOT)) { + if (!libevdev_has_event_code(evdev, + EV_ABS, ABS_MT_SLOT)) { device->mtdev = mtdev_new_open(device->fd); if (!device->mtdev) - return 0; - device->mt.slot = device->mtdev->caps.slot.value; + return -1; + + num_slots = device->mtdev->caps.slot.maximum; + if (device->mtdev->caps.slot.minimum < 0 || + num_slots <= 0) + return -1; + active_slot = device->mtdev->caps.slot.value; } else { - ioctl(device->fd, EVIOCGABS(ABS_MT_SLOT), - &absinfo); - device->mt.slot = absinfo.value; + num_slots = libevdev_get_num_slots(device->evdev); + active_slot = libevdev_get_current_slot(evdev); } + + slots = calloc(num_slots, sizeof(struct mt_slot)); + if (!slots) + return -1; + + for (slot = 0; slot < num_slots; ++slot) { + slots[slot].seat_slot = -1; + slots[slot].x = 0; + slots[slot].y = 0; + } + device->mt.slots = slots; + device->mt.slots_len = num_slots; + device->mt.slot = active_slot; } } - if (TEST_BIT(ev_bits, EV_REL)) { - ioctl(device->fd, EVIOCGBIT(EV_REL, sizeof(rel_bits)), - rel_bits); - if (TEST_BIT(rel_bits, REL_X) || TEST_BIT(rel_bits, REL_Y)) - has_rel = 1; - } - if (TEST_BIT(ev_bits, EV_KEY)) { - has_key = 1; - ioctl(device->fd, EVIOCGBIT(EV_KEY, sizeof(key_bits)), - key_bits); - if (TEST_BIT(key_bits, BTN_TOOL_FINGER) && - !TEST_BIT(key_bits, BTN_TOOL_PEN) && + if (libevdev_has_event_code(evdev, EV_REL, REL_X) || + libevdev_has_event_code(evdev, EV_REL, REL_Y)) + has_rel = 1; + + if (libevdev_has_event_type(evdev, EV_KEY)) { + if (!libevdev_has_property(evdev, INPUT_PROP_DIRECT) && + libevdev_has_event_code(evdev, EV_KEY, BTN_TOOL_FINGER) && + !libevdev_has_event_code(evdev, EV_KEY, BTN_TOOL_PEN) && (has_abs || has_mt)) { - device->dispatch = evdev_touchpad_create(device); + device->dispatch = evdev_mt_touchpad_create(device); + log_info("input device '%s', %s is a touchpad\n", + device->devname, device->devnode); } for (i = KEY_ESC; i < KEY_MAX; i++) { if (i >= BTN_MISC && i < KEY_OK) continue; - if (TEST_BIT(key_bits, i)) { + if (libevdev_has_event_code(evdev, EV_KEY, i)) { has_keyboard = 1; break; } } - if (TEST_BIT(key_bits, BTN_TOUCH)) + if (libevdev_has_event_code(evdev, EV_KEY, BTN_TOUCH)) has_touch = 1; for (i = BTN_MISC; i < BTN_JOYSTICK; i++) { - if (TEST_BIT(key_bits, i)) { + if (libevdev_has_event_code(evdev, EV_KEY, i)) { has_button = 1; break; } } } - if (TEST_BIT(ev_bits, EV_LED)) + if (libevdev_has_event_type(evdev, EV_LED)) has_keyboard = 1; - /* This rule tries to catch accelerometer devices and opt out. We may - * want to adjust the protocol later adding a proper event for dealing - * with accelerometers and implement here accordingly */ - if (has_abs && !has_key && !device->is_mt) - return 0; + if ((has_abs || has_rel) && has_button) { + if (configure_pointer_acceleration(device) == -1) + return -1; - if ((has_abs || has_rel) && has_button) device->seat_caps |= EVDEV_DEVICE_POINTER; - if (has_keyboard) - device->seat_caps |= EVDEV_DEVICE_KEYBOARD; - if (has_touch) - device->seat_caps |= EVDEV_DEVICE_TOUCH; - return 0; -} - -static void -register_device_capabilities(struct evdev_device *device) -{ - if (device->seat_caps & EVDEV_DEVICE_POINTER) { - device_register_capability(&device->base, - LIBINPUT_DEVICE_CAP_POINTER); + log_info("input device '%s', %s is a pointer caps =%s%s%s\n", + device->devname, device->devnode, + has_abs ? " absolute-motion" : "", + has_rel ? " relative-motion": "", + has_button ? " button" : ""); } - if (device->seat_caps & EVDEV_DEVICE_KEYBOARD) { - device_register_capability(&device->base, - LIBINPUT_DEVICE_CAP_KEYBOARD); + if (has_keyboard) { + device->seat_caps |= EVDEV_DEVICE_KEYBOARD; + log_info("input device '%s', %s is a keyboard\n", + device->devname, device->devnode); } - if (device->seat_caps & EVDEV_DEVICE_TOUCH) { - device_register_capability(&device->base, - LIBINPUT_DEVICE_CAP_TOUCH); + if (has_touch && !has_button) { + device->seat_caps |= EVDEV_DEVICE_TOUCH; + log_info("input device '%s', %s is a touch device\n", + device->devname, device->devnode); } + + return 0; } struct evdev_device * evdev_device_create(struct libinput_seat *seat, const char *devnode, - const char *sysname, - int fd) + const char *sysname) { struct libinput *libinput = seat->libinput; struct evdev_device *device; - char devname[256] = "unknown"; + int rc; + int fd; + int unhandled_device = 0; + + /* Use non-blocking mode so that we can loop on read on + * evdev_device_data() until all events on the fd are + * read. mtdev_get() also expects this. */ + fd = open_restricted(libinput, devnode, O_RDWR | O_NONBLOCK); + if (fd < 0) { + log_info("opening input device '%s' failed (%s).\n", + devnode, strerror(-fd)); + return NULL; + } device = zalloc(sizeof *device); if (device == NULL) @@ -623,28 +772,33 @@ evdev_device_create(struct libinput_seat *seat, libinput_device_init(&device->base, seat); + rc = libevdev_new_from_fd(fd, &device->evdev); + if (rc != 0) + return NULL; + + libevdev_set_clock_id(device->evdev, CLOCK_MONOTONIC); + device->seat_caps = 0; device->is_mt = 0; device->mtdev = NULL; device->devnode = strdup(devnode); device->sysname = strdup(sysname); - device->mt.slot = -1; device->rel.dx = 0; device->rel.dy = 0; + device->abs.seat_slot = -1; device->dispatch = NULL; device->fd = fd; device->pending_event = EVDEV_NONE; + device->devname = libevdev_get_name(device->evdev); - ioctl(device->fd, EVIOCGNAME(sizeof(devname)), devname); - devname[sizeof(devname) - 1] = '\0'; - device->devname = strdup(devname); + libinput_seat_ref(seat); if (evdev_configure_device(device) == -1) goto err; if (device->seat_caps == 0) { - evdev_device_destroy(device); - return NULL; + unhandled_device = 1; + goto err; } /* If the dispatch was not set up use the fallback. */ @@ -660,20 +814,26 @@ evdev_device_create(struct libinput_seat *seat, list_insert(seat->devices_list.prev, &device->base.link); notify_added_device(&device->base); - register_device_capabilities(device); return device; err: + if (fd >= 0) + close_restricted(libinput, fd); evdev_device_destroy(device); - return NULL; + + return unhandled_device ? EVDEV_UNHANDLED_DEVICE : NULL; } int evdev_device_get_keys(struct evdev_device *device, char *keys, size_t size) { + int len; + memset(keys, 0, size); - return ioctl(device->fd, EVIOCGKEY(size), keys); + len = ioctl(device->fd, EVIOCGKEY(size), keys); + + return (len == -1) ? -errno : len; } const char * @@ -711,29 +871,36 @@ evdev_device_has_capability(struct evdev_device *device, } } +int +evdev_device_get_size(struct evdev_device *device, + double *width, + double *height) +{ + const struct input_absinfo *x, *y; + + x = libevdev_get_abs_info(device->evdev, ABS_X); + y = libevdev_get_abs_info(device->evdev, ABS_Y); + + if (!x || !y || !x->resolution || !y->resolution) + return -1; + + *width = evdev_convert_to_mm(x, x->maximum); + *height = evdev_convert_to_mm(y, y->maximum); + + return 0; +} + void evdev_device_remove(struct evdev_device *device) { - if (device->seat_caps & EVDEV_DEVICE_POINTER) { - device_unregister_capability(&device->base, - LIBINPUT_DEVICE_CAP_POINTER); - } - if (device->seat_caps & EVDEV_DEVICE_KEYBOARD) { - device_unregister_capability(&device->base, - LIBINPUT_DEVICE_CAP_KEYBOARD); - } - if (device->seat_caps & EVDEV_DEVICE_TOUCH) { - device_unregister_capability(&device->base, - LIBINPUT_DEVICE_CAP_TOUCH); - } - if (device->source) libinput_remove_source(device->base.seat->libinput, device->source); if (device->mtdev) mtdev_close_delete(device->mtdev); - close(device->fd); + close_restricted(device->base.seat->libinput, device->fd); + device->fd = -1; list_remove(&device->base.link); notify_removed_device(&device->base); @@ -749,7 +916,10 @@ evdev_device_destroy(struct evdev_device *device) if (dispatch) dispatch->interface->destroy(dispatch); - free(device->devname); + motion_filter_destroy(device->pointer.filter); + libinput_seat_unref(device->base.seat); + libevdev_free(device->evdev); + free(device->mt.slots); free(device->devnode); free(device->sysname); free(device);