X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fevdev.c;h=63eaa4dfaa32a0500af21a7815b5b31f009bec43;hb=967911791f9988be63b8a2c1ffb608eb2871889b;hp=7168bc08bba7ad5c65fa2a416ab293a435a43cce;hpb=bc06973c2efacdc2cb7840706733581897efb9f3;p=platform%2Fupstream%2Flibinput.git diff --git a/src/evdev.c b/src/evdev.c index 7168bc0..63eaa4d 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -26,18 +26,20 @@ #include #include #include -#include +#include "linux/input.h" #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) @@ -87,30 +89,39 @@ transform_absolute(struct evdev_device *device, int32_t *x, int32_t *y) } } -li_fixed_t +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, - li_fixed_t x, + double x, uint32_t width) { - return ((uint64_t)x - li_fixed_from_int(device->abs.min_x)) * width / - (device->abs.max_x - device->abs.min_x + 1); + return scale_axis(device->abs.absinfo_x, x, width); } -li_fixed_t +double evdev_device_transform_y(struct evdev_device *device, - li_fixed_t y, + double y, uint32_t height) { - return ((uint64_t)y - li_fixed_from_int(device->abs.min_y)) * height / - (device->abs.max_y - device->abs.min_y + 1); + 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; @@ -118,82 +129,119 @@ 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; + + /* 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: if (!(device->seat_caps & EVDEV_DEVICE_TOUCH)) break; - 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); + 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: if (!(device->seat_caps & EVDEV_DEVICE_TOUCH)) break; - 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); + 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: if (!(device->seat_caps & EVDEV_DEVICE_TOUCH)) break; - touch_notify_touch(base, - time, - slot, - 0, 0, - LIBINPUT_TOUCH_TYPE_UP); + 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, - -1, - li_fixed_from_int(cx), - li_fixed_from_int(cy), - LIBINPUT_TOUCH_TYPE_DOWN); + + 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, - -1, - li_fixed_from_int(cx), - li_fixed_from_int(cy), - LIBINPUT_TOUCH_TYPE_DOWN); + 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, - li_fixed_from_int(cx), - li_fixed_from_int(cy)); + pointer_notify_motion_absolute(base, time, x, y); } break; case EVDEV_ABSOLUTE_TOUCH_UP: if (!(device->seat_caps & EVDEV_DEVICE_TOUCH)) break; - touch_notify_touch(base, - time, - -1, - 0, 0, - LIBINPUT_TOUCH_TYPE_UP); + seat_slot = device->abs.seat_slot; + device->abs.seat_slot = -1; + + 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"); @@ -204,7 +252,8 @@ evdev_flush_pending_event(struct evdev_device *device, uint32_t time) } 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) @@ -216,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); @@ -243,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; } } @@ -261,7 +319,7 @@ 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) { switch (e->code) { case ABS_MT_SLOT: @@ -310,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; @@ -318,13 +376,13 @@ 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: @@ -332,7 +390,7 @@ evdev_process_relative(struct evdev_device *device, pointer_notify_axis( base, time, - LIBINPUT_POINTER_AXIS_VERTICAL_SCROLL, + LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, -1 * e->value * DEFAULT_AXIS_STEP_DISTANCE); break; case REL_HWHEEL: @@ -345,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: @@ -358,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); @@ -393,7 +451,7 @@ 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; @@ -443,7 +501,7 @@ static inline void evdev_process_event(struct evdev_device *device, struct input_event *e) { struct evdev_dispatch *dispatch = device->dispatch; - uint32_t time = e->time.tv_sec * 1000 + e->time.tv_usec / 1000; + uint64_t time = e->time.tv_sec * 1000ULL + e->time.tv_usec / 1000; dispatch->interface->process(dispatch, device, e, time); } @@ -519,11 +577,29 @@ evdev_device_dispatch(void *data) } 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 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_rel = 0; @@ -533,79 +609,138 @@ evdev_configure_device(struct evdev_device *device) has_keyboard = 0; has_touch = 0; - if (libevdev_has_event_type(device->evdev, EV_ABS)) { + if (libevdev_has_event_type(evdev, EV_ABS)) { - if ((absinfo = libevdev_get_abs_info(device->evdev, ABS_X))) { - 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 ((absinfo = libevdev_get_abs_info(device->evdev, ABS_Y))) { - 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 (libevdev_has_event_code(device->evdev, EV_ABS, ABS_MT_POSITION_X) && - libevdev_has_event_code(device->evdev, EV_ABS, ABS_MT_POSITION_Y)) { - absinfo = libevdev_get_abs_info(device->evdev, ABS_MT_POSITION_X); - device->abs.min_x = absinfo->minimum; - device->abs.max_x = absinfo->maximum; - absinfo = libevdev_get_abs_info(device->evdev, ABS_MT_POSITION_Y); - 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 (!libevdev_has_event_code(device->evdev, EV_ABS, 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 -1; - device->mt.slot = device->mtdev->caps.slot.value; + + 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 { - device->mt.slot = libevdev_get_current_slot(device->evdev); + 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 (libevdev_has_event_code(device->evdev, EV_REL, REL_X) || - libevdev_has_event_code(device->evdev, EV_REL, REL_Y)) - has_rel = 1; - - if (libevdev_has_event_type(device->evdev, EV_KEY)) { - if (libevdev_has_event_code(device->evdev, EV_KEY, BTN_TOOL_FINGER) && - !libevdev_has_event_code(device->evdev, EV_KEY, 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 (libevdev_has_event_code(device->evdev, EV_KEY, i)) { + if (libevdev_has_event_code(evdev, EV_KEY, i)) { has_keyboard = 1; break; } } - if (libevdev_has_event_code(device->evdev, EV_KEY, BTN_TOUCH)) + if (libevdev_has_event_code(evdev, EV_KEY, BTN_TOUCH)) has_touch = 1; for (i = BTN_MISC; i < BTN_JOYSTICK; i++) { - if (libevdev_has_event_code(device->evdev, EV_KEY, i)) { + if (libevdev_has_event_code(evdev, EV_KEY, i)) { has_button = 1; break; } } } - if (libevdev_has_event_type(device->evdev, EV_LED)) + if (libevdev_has_event_type(evdev, EV_LED)) has_keyboard = 1; - if ((has_abs || has_rel) && has_button) + if ((has_abs || has_rel) && has_button) { + if (configure_pointer_acceleration(device) == -1) + return -1; + device->seat_caps |= EVDEV_DEVICE_POINTER; - if (has_keyboard) + + 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 (has_keyboard) { device->seat_caps |= EVDEV_DEVICE_KEYBOARD; - if (has_touch && !has_button) + log_info("input device '%s', %s is a keyboard\n", + device->devname, device->devnode); + } + 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; } @@ -648,9 +783,9 @@ evdev_device_create(struct libinput_seat *seat, 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; @@ -693,8 +828,12 @@ err: 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 * @@ -732,6 +871,25 @@ 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) { @@ -758,8 +916,10 @@ evdev_device_destroy(struct evdev_device *device) if (dispatch) dispatch->interface->destroy(dispatch); + 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);