}
void
+evdev_pointer_notify_physical_button(struct evdev_device *device,
+ uint32_t time,
+ int button,
+ enum libinput_button_state state)
+{
+ if (evdev_middlebutton_filter_button(device,
+ time,
+ button,
+ state))
+ return;
+
+ evdev_pointer_notify_button(device, time, button, state);
+}
+
+void
evdev_pointer_notify_button(struct evdev_device *device,
uint32_t time,
int button,
(state == LIBINPUT_BUTTON_STATE_RELEASED && down_count == 0)) {
pointer_notify_button(&device->base, time, button, state);
- if (state == LIBINPUT_BUTTON_STATE_RELEASED &&
- device->left_handed.change_to_enabled)
- device->left_handed.change_to_enabled(device);
+ if (state == LIBINPUT_BUTTON_STATE_RELEASED) {
+ if (device->left_handed.change_to_enabled)
+ device->left_handed.change_to_enabled(device);
- if (state == LIBINPUT_BUTTON_STATE_RELEASED &&
- device->scroll.change_scroll_method)
- device->scroll.change_scroll_method(device);
+ if (device->scroll.change_scroll_method)
+ device->scroll.change_scroll_method(device);
+ }
}
}
const struct device_coords *delta,
struct normalized_coords *normalized)
{
- normalized->x = delta->x * (double)device->dpi / DEFAULT_MOUSE_DPI;
- normalized->y = delta->y * (double)device->dpi / DEFAULT_MOUSE_DPI;
+ normalized->x = delta->x * DEFAULT_MOUSE_DPI / (double)device->dpi;
+ normalized->y = delta->y * DEFAULT_MOUSE_DPI / (double)device->dpi;
}
static void
evdev_flush_pending_event(struct evdev_device *device, uint64_t time)
{
struct libinput *libinput = device->base.seat->libinput;
- struct motion_params motion;
- int32_t x, y;
int slot;
int seat_slot;
struct libinput_device *base = &device->base;
}
/* Apply pointer acceleration. */
- motion.dx = unaccel.x;
- motion.dy = unaccel.y;
- filter_dispatch(device->pointer.filter, &motion, device, time);
- accel.x = motion.dx;
- accel.y = motion.dy;
-
- if (accel.x == 0.0 && accel.y == 0.0 &&
- unaccel.x == 0.0 && unaccel.y == 0.0) {
+ accel = filter_dispatch(device->pointer.filter, &unaccel, device, time);
+
+ if (normalized_is_zero(accel) && normalized_is_zero(unaccel))
break;
- }
pointer_notify_motion(base, time, &accel, &unaccel);
break;
transform_absolute(device, &point);
touch_notify_touch_down(base, time, slot, seat_slot,
- point.x, point.y);
+ &point);
break;
case EVDEV_ABSOLUTE_MT_MOTION:
if (!(device->seat_caps & EVDEV_DEVICE_TOUCH))
transform_absolute(device, &point);
touch_notify_touch_motion(base, time, slot, seat_slot,
- point.x, point.y);
+ &point);
break;
case EVDEV_ABSOLUTE_MT_UP:
if (!(device->seat_caps & EVDEV_DEVICE_TOUCH))
point = device->abs.point;
transform_absolute(device, &point);
- touch_notify_touch_down(base, time, -1, seat_slot,
- point.x, point.y);
+ touch_notify_touch_down(base, time, -1, seat_slot, &point);
break;
case EVDEV_ABSOLUTE_MOTION:
point = device->abs.point;
transform_absolute(device, &point);
- x = point.x;
- y = point.y;
if (device->seat_caps & EVDEV_DEVICE_TOUCH) {
seat_slot = device->abs.seat_slot;
if (seat_slot == -1)
break;
- touch_notify_touch_motion(base, time, -1, seat_slot, x, y);
+ touch_notify_touch_motion(base, time, -1, seat_slot,
+ &point);
} else if (device->seat_caps & EVDEV_DEVICE_POINTER) {
pointer_notify_motion_absolute(base, time, &point);
}
} else {
/* If the button is released quickly enough emit the
* button press/release events. */
- evdev_pointer_notify_button(device, time,
+ evdev_pointer_notify_physical_button(device, time,
device->scroll.button,
LIBINPUT_BUTTON_STATE_PRESSED);
- evdev_pointer_notify_button(device, time,
+ evdev_pointer_notify_physical_button(device, time,
device->scroll.button,
LIBINPUT_BUTTON_STATE_RELEASED);
}
evdev_button_scroll_button(device, time, e->value);
break;
}
- evdev_pointer_notify_button(
+ evdev_pointer_notify_physical_button(
device,
time,
evdev_to_left_handed(device, e->code),
uint32_t axes,
enum libinput_pointer_axis_source source,
const struct normalized_coords *delta_in,
- double x_discrete, double y_discrete)
+ const struct discrete_coords *discrete_in)
{
struct normalized_coords delta = *delta_in;
+ struct discrete_coords discrete = *discrete_in;
if (device->scroll.natural_scrolling_enabled) {
delta.x *= -1;
delta.y *= -1;
- x_discrete *= -1;
- y_discrete *= -1;
+ discrete.x *= -1;
+ discrete.y *= -1;
}
pointer_notify_axis(&device->base,
axes,
source,
&delta,
- x_discrete, y_discrete);
+ &discrete);
}
static inline void
struct input_event *e, uint64_t time)
{
struct normalized_coords wheel_degrees = { 0.0, 0.0 };
+ struct discrete_coords discrete = { 0.0, 0.0 };
switch (e->code) {
case REL_X:
evdev_flush_pending_event(device, time);
wheel_degrees.y = -1 * e->value *
device->scroll.wheel_click_angle;
+ discrete.y = -1 * e->value;
evdev_notify_axis(
device,
time,
AS_MASK(LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL),
LIBINPUT_POINTER_AXIS_SOURCE_WHEEL,
&wheel_degrees,
- 0.0,
- -1 * e->value);
+ &discrete);
break;
case REL_HWHEEL:
evdev_flush_pending_event(device, time);
wheel_degrees.x = e->value * device->scroll.wheel_click_angle;
+ discrete.x = e->value;
evdev_notify_axis(
device,
time,
AS_MASK(LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL),
LIBINPUT_POINTER_AXIS_SOURCE_WHEEL,
&wheel_degrees,
- e->value,
- 0.0);
+ &discrete);
break;
}
}
evdev_init_calibration(evdev_device, dispatch);
evdev_init_sendevents(evdev_device, dispatch);
+ /* BTN_MIDDLE is set on mice even when it's not present. So
+ * we can only use the absense of BTN_MIDDLE to mean something, i.e.
+ * we enable it by default on anything that only has L&R.
+ * If we have L&R and no middle, we don't expose it as config
+ * option */
+ if (libevdev_has_event_code(evdev_device->evdev, EV_KEY, BTN_LEFT) &&
+ libevdev_has_event_code(evdev_device->evdev, EV_KEY, BTN_RIGHT)) {
+ bool has_middle = libevdev_has_event_code(evdev_device->evdev,
+ EV_KEY,
+ BTN_MIDDLE);
+ bool want_config = has_middle;
+ bool enable_by_default = !has_middle;
+
+ evdev_init_middlebutton(evdev_device,
+ enable_by_default,
+ want_config);
+ }
+
return dispatch;
}
struct evdev_dispatch *dispatch = device->dispatch;
uint64_t time = e->time.tv_sec * 1000ULL + e->time.tv_usec / 1000;
+#if 0
+ if (libevdev_event_is_code(e, EV_SYN, SYN_REPORT))
+ log_debug(device->base.seat->libinput,
+ "-------------- EV_SYN ------------\n");
+ else
+ log_debug(device->base.seat->libinput,
+ "%-7s %-16s %-20s %4d\n",
+ evdev_device_get_sysname(device),
+ libevdev_event_type_get_name(e->type),
+ libevdev_event_code_get_name(e->type, e->code),
+ e->value);
+#endif
+
dispatch->interface->process(dispatch, device, e, time);
}
}
int
-evdev_device_init_pointer_acceleration(struct evdev_device *device)
+evdev_device_init_pointer_acceleration(struct evdev_device *device,
+ accel_profile_func_t profile)
{
- device->pointer.filter =
- create_pointer_accelerator_filter(
- pointer_accel_profile_linear);
+ device->pointer.filter = create_pointer_accelerator_filter(profile);
if (!device->pointer.filter)
return -1;
return angle;
}
+
+static inline int
+evdev_get_trackpoint_dpi(struct evdev_device *device)
+{
+ struct libinput *libinput = device->base.seat->libinput;
+ const char *trackpoint_accel;
+ double accel = DEFAULT_TRACKPOINT_ACCEL;
+
+ trackpoint_accel = udev_device_get_property_value(
+ device->udev_device, "POINTINGSTICK_CONST_ACCEL");
+ if (trackpoint_accel) {
+ accel = parse_trackpoint_accel_property(trackpoint_accel);
+ if (accel == 0.0) {
+ log_error(libinput, "Trackpoint accel property for "
+ "'%s' is present but invalid, "
+ "using %.2f instead\n",
+ device->devname,
+ DEFAULT_TRACKPOINT_ACCEL);
+ accel = DEFAULT_TRACKPOINT_ACCEL;
+ }
+ }
+
+ return DEFAULT_MOUSE_DPI / accel;
+}
+
static inline int
evdev_read_dpi_prop(struct evdev_device *device)
{
const char *mouse_dpi;
int dpi = DEFAULT_MOUSE_DPI;
+ /*
+ * Trackpoints do not have dpi, instead hwdb may contain a
+ * POINTINGSTICK_CONST_ACCEL value to compensate for sensitivity
+ * differences between models, we translate this to a fake dpi.
+ */
+ if (libevdev_has_property(device->evdev, INPUT_PROP_POINTING_STICK))
+ return evdev_get_trackpoint_dpi(device);
+
mouse_dpi = udev_device_get_property_value(device->udev_device,
"MOUSE_DPI");
if (mouse_dpi) {
return dpi;
}
-static inline int
-evdev_fix_abs_resolution(struct libevdev *evdev,
- unsigned int code,
- const struct input_absinfo *absinfo)
+static inline enum evdev_device_model
+evdev_read_model(struct evdev_device *device)
+{
+ const struct model_map {
+ const char *property;
+ enum evdev_device_model model;
+ } model_map[] = {
+ { "LIBINPUT_MODEL_LENOVO_X230", EVDEV_MODEL_LENOVO_X230 },
+ { NULL, EVDEV_MODEL_DEFAULT },
+ };
+ const struct model_map *m = model_map;
+
+ while (m->property) {
+ if (!!udev_device_get_property_value(device->udev_device,
+ m->property))
+ break;
+ m++;
+ }
+
+ return m->model;
+}
+
+/* Return 1 if the given resolutions have been set, or 0 otherwise */
+inline int
+evdev_fix_abs_resolution(struct evdev_device *device,
+ unsigned int xcode,
+ unsigned int ycode,
+ int xresolution,
+ int yresolution)
{
+ struct libinput *libinput = device->base.seat->libinput;
+ struct libevdev *evdev = device->evdev;
+ const struct input_absinfo *absx, *absy;
struct input_absinfo fixed;
+ int rc = 0;
+
+ if (!(xcode == ABS_X && ycode == ABS_Y) &&
+ !(xcode == ABS_MT_POSITION_X && ycode == ABS_MT_POSITION_Y)) {
+ log_bug_libinput(libinput,
+ "Invalid x/y code combination %d/%d\n",
+ xcode, ycode);
+ return 0;
+ }
+
+ if (xresolution == 0 || yresolution == 0 ||
+ (xresolution == EVDEV_FAKE_RESOLUTION && xresolution != yresolution) ||
+ (yresolution == EVDEV_FAKE_RESOLUTION && xresolution != yresolution)) {
+ log_bug_libinput(libinput,
+ "Invalid x/y resolutions %d/%d\n",
+ xresolution, yresolution);
+ return 0;
+ }
+
+ absx = libevdev_get_abs_info(evdev, xcode);
+ absy = libevdev_get_abs_info(evdev, ycode);
- if (absinfo->resolution == 0) {
- fixed = *absinfo;
- fixed.resolution = 1;
+ if (absx->resolution == 0 || absx->resolution == EVDEV_FAKE_RESOLUTION) {
+ fixed = *absx;
+ fixed.resolution = xresolution;
/* libevdev_set_abs_info() changes the absinfo we already
have a pointer to, no need to fetch it again */
- libevdev_set_abs_info(evdev, code, &fixed);
- return 1;
- } else {
- return 0;
+ libevdev_set_abs_info(evdev, xcode, &fixed);
+ rc = 1;
}
+
+ if (absy->resolution == 0 || absy->resolution == EVDEV_FAKE_RESOLUTION) {
+ fixed = *absy;
+ fixed.resolution = yresolution;
+ /* libevdev_set_abs_info() changes the absinfo we already
+ have a pointer to, no need to fetch it again */
+ libevdev_set_abs_info(evdev, ycode, &fixed);
+ rc = 1;
+ }
+
+ return rc;
}
static enum evdev_device_udev_tags
return tags;
}
+/* Fake MT devices have the ABS_MT_SLOT bit set because of
+ the limited ABS_* range - they aren't MT devices, they
+ just have too many ABS_ axes */
+static inline bool
+evdev_is_fake_mt_device(struct evdev_device *device)
+{
+ struct libevdev *evdev = device->evdev;
+
+ return libevdev_has_event_code(evdev, EV_ABS, ABS_MT_SLOT) &&
+ libevdev_get_num_slots(evdev) == -1;
+}
+
+static inline void
+evdev_fix_android_mt(struct evdev_device *device)
+{
+ struct libevdev *evdev = device->evdev;
+
+ if (libevdev_has_event_code(evdev, EV_ABS, ABS_X) ||
+ libevdev_has_event_code(evdev, EV_ABS, ABS_Y))
+ return;
+
+ if (!libevdev_has_event_code(evdev, EV_ABS, ABS_MT_POSITION_X) ||
+ !libevdev_has_event_code(evdev, EV_ABS, ABS_MT_POSITION_Y) ||
+ evdev_is_fake_mt_device(device))
+ return;
+
+ libevdev_enable_event_code(evdev, EV_ABS, ABS_X,
+ libevdev_get_abs_info(evdev, ABS_MT_POSITION_X));
+ libevdev_enable_event_code(evdev, EV_ABS, ABS_Y,
+ libevdev_get_abs_info(evdev, ABS_MT_POSITION_Y));
+}
+
+static inline int
+evdev_check_min_max(struct evdev_device *device, unsigned int code)
+{
+ struct libevdev *evdev = device->evdev;
+ const struct input_absinfo *absinfo;
+
+ if (!libevdev_has_event_code(evdev, EV_ABS, code))
+ return 0;
+
+ absinfo = libevdev_get_abs_info(evdev, code);
+ if (absinfo->minimum == absinfo->maximum) {
+ /* Some devices have a sort-of legitimate min/max of 0 for
+ * ABS_MISC and above (e.g. Roccat Kone XTD). Don't ignore
+ * them, simply disable the axes so we won't get events,
+ * we don't know what to do with them anyway.
+ */
+ if (absinfo->minimum == 0 &&
+ code >= ABS_MISC && code < ABS_MT_SLOT) {
+ log_info(device->base.seat->libinput,
+ "Disabling EV_ABS %#x on device '%s' (min == max == 0)\n",
+ code,
+ device->devname);
+ libevdev_disable_event_code(device->evdev,
+ EV_ABS,
+ code);
+ } else {
+ log_bug_kernel(device->base.seat->libinput,
+ "Device '%s' has min == max on %s\n",
+ device->devname,
+ libevdev_event_code_get_name(EV_ABS, code));
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
static int
-evdev_configure_device(struct evdev_device *device)
+evdev_reject_device(struct evdev_device *device)
{
struct libinput *libinput = device->base.seat->libinput;
struct libevdev *evdev = device->evdev;
- const struct input_absinfo *absinfo;
+ unsigned int code;
+ const struct input_absinfo *absx, *absy;
+
+ if (libevdev_has_event_code(evdev, EV_ABS, ABS_X) ^
+ libevdev_has_event_code(evdev, EV_ABS, ABS_Y))
+ return -1;
+
+ if (libevdev_has_event_code(evdev, EV_ABS, ABS_MT_POSITION_X) ^
+ libevdev_has_event_code(evdev, EV_ABS, ABS_MT_POSITION_Y))
+ return -1;
+
+ if (libevdev_has_event_code(evdev, EV_ABS, ABS_X)) {
+ absx = libevdev_get_abs_info(evdev, ABS_X);
+ absy = libevdev_get_abs_info(evdev, ABS_Y);
+ if ((absx->resolution == 0 && absy->resolution != 0) ||
+ (absx->resolution != 0 && absy->resolution == 0)) {
+ log_bug_kernel(libinput,
+ "Kernel has only x or y resolution, not both.\n");
+ return -1;
+ }
+ }
+
+ if (!evdev_is_fake_mt_device(device) &&
+ libevdev_has_event_code(evdev, EV_ABS, ABS_MT_POSITION_X)) {
+ absx = libevdev_get_abs_info(evdev, ABS_MT_POSITION_X);
+ absy = libevdev_get_abs_info(evdev, ABS_MT_POSITION_Y);
+ if ((absx->resolution == 0 && absy->resolution != 0) ||
+ (absx->resolution != 0 && absy->resolution == 0)) {
+ log_bug_kernel(libinput,
+ "Kernel has only x or y MT resolution, not both.\n");
+ return -1;
+ }
+ }
+
+ for (code = 0; code < ABS_CNT; code++) {
+ switch (code) {
+ case ABS_MISC:
+ case ABS_MT_SLOT:
+ case ABS_MT_TOOL_TYPE:
+ break;
+ default:
+ if (evdev_check_min_max(device, code) == -1)
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int
+evdev_configure_mt_device(struct evdev_device *device)
+{
+ struct libevdev *evdev = device->evdev;
struct mt_slot *slots;
int num_slots;
int active_slot;
int slot;
+
+ if (!libevdev_has_event_code(evdev, EV_ABS, ABS_MT_POSITION_X) ||
+ !libevdev_has_event_code(evdev, EV_ABS, ABS_MT_POSITION_Y))
+ return 0;
+
+ if (evdev_fix_abs_resolution(device,
+ ABS_MT_POSITION_X,
+ ABS_MT_POSITION_Y,
+ EVDEV_FAKE_RESOLUTION,
+ EVDEV_FAKE_RESOLUTION))
+ device->abs.fake_resolution = 1;
+
+ device->abs.absinfo_x = libevdev_get_abs_info(evdev, ABS_MT_POSITION_X);
+ device->abs.absinfo_y = libevdev_get_abs_info(evdev, ABS_MT_POSITION_Y);
+ device->is_mt = 1;
+
+ /* We only handle the slotted Protocol B in libinput.
+ Devices with ABS_MT_POSITION_* but not ABS_MT_SLOT
+ require mtdev for conversion. */
+ if (evdev_need_mtdev(device)) {
+ device->mtdev = mtdev_new_open(device->fd);
+ if (!device->mtdev)
+ return -1;
+
+ /* pick 10 slots as default for type A
+ devices. */
+ num_slots = 10;
+ active_slot = device->mtdev->caps.slot.value;
+ } else {
+ 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].point.x = 0;
+ slots[slot].point.y = 0;
+ }
+ device->mt.slots = slots;
+ device->mt.slots_len = num_slots;
+ device->mt.slot = active_slot;
+
+ return 0;
+}
+
+static int
+evdev_configure_device(struct evdev_device *device)
+{
+ struct libinput *libinput = device->base.seat->libinput;
+ struct libevdev *evdev = device->evdev;
const char *devnode = udev_device_get_devnode(device->udev_device);
enum evdev_device_udev_tags udev_tags;
return -1;
}
- if (libevdev_has_event_type(evdev, EV_ABS)) {
-
- if ((absinfo = libevdev_get_abs_info(evdev, ABS_X))) {
- if (evdev_fix_abs_resolution(evdev,
- ABS_X,
- absinfo))
- device->abs.fake_resolution = 1;
- device->abs.absinfo_x = absinfo;
- }
- if ((absinfo = libevdev_get_abs_info(evdev, ABS_Y))) {
- if (evdev_fix_abs_resolution(evdev,
- ABS_Y,
- absinfo))
- device->abs.fake_resolution = 1;
- device->abs.absinfo_y = absinfo;
- }
+ if (evdev_reject_device(device) == -1) {
+ log_info(libinput,
+ "input device '%s', %s was rejected.\n",
+ device->devname, devnode);
+ return -1;
+ }
- /* Fake MT devices have the ABS_MT_SLOT bit set because of
- the limited ABS_* range - they aren't MT devices, they
- just have too many ABS_ axes */
- if (libevdev_has_event_code(evdev, EV_ABS, ABS_MT_SLOT) &&
- libevdev_get_num_slots(evdev) == -1) {
- udev_tags &= ~EVDEV_UDEV_TAG_TOUCHSCREEN;
- } else 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 (evdev_fix_abs_resolution(evdev,
- ABS_MT_POSITION_X,
- absinfo))
- device->abs.fake_resolution = 1;
- device->abs.absinfo_x = absinfo;
-
- absinfo = libevdev_get_abs_info(evdev, ABS_MT_POSITION_Y);
- if (evdev_fix_abs_resolution(evdev,
- ABS_MT_POSITION_Y,
- absinfo))
- device->abs.fake_resolution = 1;
- device->abs.absinfo_y = absinfo;
- device->is_mt = 1;
-
- /* We only handle the slotted Protocol B in libinput.
- Devices with ABS_MT_POSITION_* but not ABS_MT_SLOT
- require mtdev for conversion. */
- if (evdev_need_mtdev(device)) {
- device->mtdev = mtdev_new_open(device->fd);
- if (!device->mtdev)
- return -1;
-
- /* pick 10 slots as default for type A
- devices. */
- num_slots = 10;
- active_slot = device->mtdev->caps.slot.value;
- } else {
- num_slots = libevdev_get_num_slots(device->evdev);
- active_slot = libevdev_get_current_slot(evdev);
- }
+ if (!evdev_is_fake_mt_device(device))
+ evdev_fix_android_mt(device);
- slots = calloc(num_slots, sizeof(struct mt_slot));
- if (!slots)
- return -1;
+ if (libevdev_has_event_code(evdev, EV_ABS, ABS_X)) {
+ if (evdev_fix_abs_resolution(device,
+ ABS_X,
+ ABS_Y,
+ EVDEV_FAKE_RESOLUTION,
+ EVDEV_FAKE_RESOLUTION))
+ device->abs.fake_resolution = 1;
+ device->abs.absinfo_x = libevdev_get_abs_info(evdev, ABS_X);
+ device->abs.absinfo_y = libevdev_get_abs_info(evdev, ABS_Y);
- for (slot = 0; slot < num_slots; ++slot) {
- slots[slot].seat_slot = -1;
- slots[slot].point.x = 0;
- slots[slot].point.y = 0;
- }
- device->mt.slots = slots;
- device->mt.slots_len = num_slots;
- device->mt.slot = active_slot;
+ if (evdev_is_fake_mt_device(device)) {
+ udev_tags &= ~EVDEV_UDEV_TAG_TOUCHSCREEN;
+ } else if (evdev_configure_mt_device(device) == -1) {
+ return -1;
}
}
if (udev_tags & EVDEV_UDEV_TAG_MOUSE) {
if (!libevdev_has_event_code(evdev, EV_ABS, ABS_X) &&
!libevdev_has_event_code(evdev, EV_ABS, ABS_Y) &&
- evdev_device_init_pointer_acceleration(device) == -1)
+ evdev_device_init_pointer_acceleration(
+ device,
+ pointer_accel_profile_linear) == -1)
return -1;
device->seat_caps |= EVDEV_DEVICE_POINTER;
log_info(libinput,
"input device '%s', %s is a keyboard\n",
device->devname, devnode);
+
+ /* want natural-scroll config option */
+ if (libevdev_has_event_code(evdev, EV_REL, REL_WHEEL) ||
+ libevdev_has_event_code(evdev, EV_REL, REL_HWHEEL)) {
+ device->scroll.natural_scrolling_enabled = true;
+ device->seat_caps |= EVDEV_DEVICE_POINTER;
+ }
}
if (udev_tags & EVDEV_UDEV_TAG_TOUCHSCREEN) {
device->scroll.wheel_click_angle =
evdev_read_wheel_click_prop(device);
device->dpi = evdev_read_dpi_prop(device);
+ device->model = evdev_read_model(device);
/* at most 5 SYN_DROPPED log-messages per 30s */
ratelimit_init(&device->syn_drop_limit, 30ULL * 1000, 5);
return libevdev_has_event_code(device->evdev, EV_KEY, code);
}
+int
+evdev_device_has_key(struct evdev_device *device, uint32_t code)
+{
+ if (!(device->seat_caps & EVDEV_DEVICE_KEYBOARD))
+ return -1;
+
+ return libevdev_has_event_code(device->evdev, EV_KEY, code);
+}
+
static inline bool
evdev_is_scrolling(const struct evdev_device *device,
enum libinput_pointer_axis axis)
LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL))
event.x = 0.0;
- if (event.x != 0.0 || event.y != 0.0)
+ if (!normalized_is_zero(event)) {
+ const struct discrete_coords zero_discrete = { 0.0, 0.0 };
evdev_notify_axis(device,
time,
device->scroll.direction,
source,
&event,
- 0.0, 0.0);
+ &zero_discrete);
+ }
}
void
enum libinput_pointer_axis_source source)
{
const struct normalized_coords zero = { 0.0, 0.0 };
+ const struct discrete_coords zero_discrete = { 0.0, 0.0 };
/* terminate scrolling with a zero scroll event */
if (device->scroll.direction != 0)
device->scroll.direction,
source,
&zero,
- 0.0, 0.0);
+ &zero_discrete);
device->scroll.buildup.x = 0;
device->scroll.buildup.y = 0;
LIBINPUT_KEY_STATE_RELEASED);
break;
case EVDEV_KEY_TYPE_BUTTON:
- evdev_pointer_notify_button(
+ evdev_pointer_notify_physical_button(
device,
time,
evdev_to_left_handed(device, code),