Skip to content
Commits on Source (32)
......@@ -22,7 +22,7 @@
#
# All jobs must follow the naming scheme of
# <distribution>:<version>@activity:
# e.g. fedora:28@build-default
# e.g. fedora:29@build-default
stages:
- docker_check # check if the current docker images are up to date
......@@ -132,7 +132,7 @@ variables:
# cp $buildmnt1/go/src/skopeo/skopeo $buildmnt2/usr/bin/skopeo
#
# buildah unmount $buildcntr2
# buildah commit $buildcntr2 registry.freedesktop.org/libinput/libinput/skopeo:latest
# buildah commit $buildcntr2 docker://registry.freedesktop.org/libinput/libinput/skopeo:latest
#
# #clean up build
#
......@@ -177,10 +177,10 @@ fedora:28@docker-check:
CURRENT_DOCKER_IMAGE: $FEDORA_DOCKER_IMAGE:latest
<<: *docker_check
fedora:27@docker-check:
fedora:29@docker-check:
variables:
GIT_STRATEGY: none
FEDORA_VERSION: 27
FEDORA_VERSION: 29
CURRENT_DOCKER_IMAGE: $FEDORA_DOCKER_IMAGE:latest
<<: *docker_check
......@@ -223,6 +223,7 @@ freebsd:11.2@docker-check:
#
.fedora@docker-prep: &fedora_docker_prep
stage: docker_prep
image: docker:stable
services:
- docker:dind
script:
......@@ -254,18 +255,19 @@ fedora:28@docker-prep:
# Note: we can not use $FEDORA_VERSION here
- fedora:28@docker-check
fedora:27@docker-prep:
fedora:29@docker-prep:
variables:
GIT_STRATEGY: none
FEDORA_VERSION: 27
FEDORA_VERSION: 29
<<: *fedora_docker_prep
dependencies:
# Note: we can not use $FEDORA_VERSION here
- fedora:27@docker-check
- fedora:29@docker-check
# FIXME: we should clean up the apt cache between each run
.ubuntu@docker-prep: &ubuntu_docker_prep
stage: docker_prep
image: docker:stable
services:
- docker:dind
script:
......@@ -311,6 +313,7 @@ ubuntu:18.04@docker-prep:
.arch@docker-prep: &arch_docker_prep
stage: docker_prep
image: docker:stable
services:
- docker:dind
script:
......@@ -342,6 +345,7 @@ arch:rolling@docker-prep:
.freebsd@docker-prep: &freebsd_docker_prep
stage: docker_prep
image: docker:stable
services:
- docker:dind
script:
......@@ -384,10 +388,10 @@ fedora:28@force-docker-prep:
when: manual
dependencies: []
fedora:27@force-docker-prep:
fedora:29@force-docker-prep:
variables:
GIT_STRATEGY: none
FEDORA_VERSION: 27
FEDORA_VERSION: 29
<<: *fedora_docker_prep
when: manual
dependencies: []
......@@ -491,10 +495,10 @@ fedora:28@docker-clean:
CURRENT_DOCKER_IMAGE: $FEDORA_DOCKER_IMAGE
<<: *docker_clean
fedora:27@docker-clean:
fedora:29@docker-clean:
variables:
GIT_STRATEGY: none
FEDORA_VERSION: 27
FEDORA_VERSION: 29
CURRENT_DOCKER_IMAGE: $FEDORA_DOCKER_IMAGE
<<: *docker_clean
......@@ -540,34 +544,34 @@ freebsd:11.2@docker-clean:
<<: *default_artifacts
dependencies: []
fedora:27@default-build:
fedora:28@default-build:
variables:
FEDORA_VERSION: 27
FEDORA_VERSION: 28
<<: *fedora_template
<<: *default_build
.fedora:28@template: &fedora_28_template
.fedora:29@template: &fedora_29_template
variables:
FEDORA_VERSION: 28
FEDORA_VERSION: 29
<<: *fedora_template
fedora:28@default-build:
<<: *fedora_28_template
fedora:29@default-build:
<<: *fedora_29_template
<<: *default_build
fedora:28@default-build-release:
<<: *fedora_28_template
fedora:29@default-build-release:
<<: *fedora_29_template
<<: *default_build
variables:
FEDORA_VERSION: 28
FEDORA_VERSION: 29
MESON_ARGS: "-Dbuildtype=release"
CFLAGS: "-Werror"
fedora:28@scan-build:
<<: *fedora_28_template
fedora:29@scan-build:
<<: *fedora_29_template
<<: *default_build
variables:
FEDORA_VERSION: 28
FEDORA_VERSION: 29
NINJA_ARGS: scan-build
before_script:
- dnf install -y clang-analyzer findutils
......@@ -581,74 +585,74 @@ fedora:28@scan-build:
# run them on one image, they shouldn't fail on one distro
# when they succeed on another.
fedora:28@build-no-libwacom:
<<: *fedora_28_template
fedora:29@build-no-libwacom:
<<: *fedora_29_template
<<: *default_build
variables:
FEDORA_VERSION: 28
FEDORA_VERSION: 29
MESON_ARGS: "-Dlibwacom=false"
fedora:28@build-no-libwacom-nodeps:
<<: *fedora_28_template
fedora:29@build-no-libwacom-nodeps:
<<: *fedora_29_template
<<: *default_build
variables:
FEDORA_VERSION: 28
FEDORA_VERSION: 29
MESON_ARGS: "-Dlibwacom=false"
before_script:
- dnf remove -y libwacom libwacom-devel
fedora:28@build-no-docs:
<<: *fedora_28_template
fedora:29@build-no-docs:
<<: *fedora_29_template
<<: *default_build
variables:
FEDORA_VERSION: 28
FEDORA_VERSION: 29
MESON_ARGS: "-Ddocumentation=false"
fedora:28@build-no-docs-nodeps:
<<: *fedora_28_template
fedora:29@build-no-docs-nodeps:
<<: *fedora_29_template
<<: *default_build
variables:
FEDORA_VERSION: 28
FEDORA_VERSION: 29
MESON_ARGS: "-Ddocumentation=false"
before_script:
- dnf remove -y doxygen graphviz
fedora:28@build-no-debuggui:
<<: *fedora_28_template
fedora:29@build-no-debuggui:
<<: *fedora_29_template
<<: *default_build
variables:
FEDORA_VERSION: 28
FEDORA_VERSION: 29
MESON_ARGS: "-Ddebug-gui=false"
fedora:28@build-no-debuggui-nodeps:
<<: *fedora_28_template
fedora:29@build-no-debuggui-nodeps:
<<: *fedora_29_template
<<: *default_build
variables:
FEDORA_VERSION: 28
FEDORA_VERSION: 29
MESON_ARGS: "-Ddebug-gui=false"
before_script:
- dnf remove -y gtk3-devel
fedora:28@build-no-tests:
<<: *fedora_28_template
fedora:29@build-no-tests:
<<: *fedora_29_template
<<: *default_build
variables:
FEDORA_VERSION: 28
FEDORA_VERSION: 29
MESON_ARGS: "-Dtests=false"
fedora:28@build-no-tests-nodeps:
<<: *fedora_28_template
fedora:29@build-no-tests-nodeps:
<<: *fedora_29_template
<<: *default_build
variables:
FEDORA_VERSION: 28
FEDORA_VERSION: 29
MESON_ARGS: "-Dtests=false"
before_script:
- dnf remove -y check-devel
fedora:28@valgrind:
<<: *fedora_28_template
fedora:29@valgrind:
<<: *fedora_29_template
variables:
FEDORA_VERSION: 28
FEDORA_VERSION: 29
script:
- rm -rf "$MESON_BUILDDIR"
- meson "$MESON_BUILDDIR" $MESON_ARGS
......
......@@ -177,3 +177,7 @@ AttrTPKComboLayout=below
Indicates the position of the touchpad on an external touchpad+keyboard
combination device. This is a string enum. Don't specify it unless the
touchpad is below.
AttrEventCodeDisable=EV_ABS;BTN_STYLUS;EV_KEY:0x123;
Disables the evdev event type/code tuples on the device. Entries may be
a named event type, or a named event code, or a named event type with a
hexadecimal event code, separated by a single colon.
......@@ -288,7 +288,7 @@ My bug was closed as fixed, what now?
------------------------------------------------------------------------------
libinput's policy on closing bugs is: once the fix for a given bug is on git
master, the bug is considered fixed and the bugzilla entry will be closed
master, the bug is considered fixed and the gitlab issue will be closed
accordingly.
Of course, unless you actually run git master, the bug will continue to
......
project('libinput', 'c', 'cpp',
version : '1.12.1',
version : '1.12.4',
license : 'MIT/Expat',
default_options : [ 'c_std=gnu99', 'warning_level=2' ],
meson_version : '>= 0.41.0')
......@@ -217,7 +217,7 @@ src_libinput_util = [
]
libinput_util = static_library('libinput-util',
src_libinput_util,
dependencies : dep_udev,
dependencies : [dep_udev, dep_libevdev],
include_directories : includes_include)
dep_libinput_util = declare_dependency(link_with : libinput_util)
......@@ -261,6 +261,7 @@ quirks_data = [
'quirks/30-vendor-razer.quirks',
'quirks/30-vendor-synaptics.quirks',
'quirks/30-vendor-wacom.quirks',
'quirks/30-vendor-vmware.quirks',
'quirks/50-system-acer.quirks',
'quirks/50-system-apple.quirks',
'quirks/50-system-asus.quirks',
......
......@@ -4,4 +4,4 @@
MatchUdevType=tablet
MatchBus=usb
MatchVendor=0x08CA
ModelTabletNoTilt=1
AttrEventCodeDisable=ABS_TILT_X;ABS_TILT_Y;
# Kensington Orbit claims to have a middle button, same for
[Kensington Orbit Scroll Wheel]
MatchBus=usb
MatchVendor=0x047d
MatchProduct=0x2048
ModelKensingtonOrbit=1
ModelTrackball=1
AttrEventCodeDisable=BTN_MIDDLE
......@@ -4,12 +4,13 @@
MatchName=*Logitech M570*
ModelTrackball=1
# Logitech Marble Mouse claims to have a middle button
[Logitech Marble Mouse Trackball]
MatchUdevType=mouse
MatchBus=usb
MatchVendor=0x46D
MatchProduct=0xC408
ModelLogitechMarbleMouse=1
AttrEventCodeDisable=BTN_MIDDLE
[Logitech K400]
MatchUdevType=mouse
......
# Do not edit this file, it will be overwritten on update
[VMWare Virtual PS/2 Mouse]
MatchName=*VirtualPS/2 VMware VMMouse*
ModelBouncingKeys=1
[VMware VMware Virtual USB Mouse]
MatchName=*VMware VMware Virtual USB Mouse*
ModelBouncingKeys=1
......@@ -11,4 +11,4 @@ MatchUdevType=touchpad
MatchBus=usb
MatchVendor=0x056A
MatchProduct=0x0357
AttrPalmSizeThreshold=1
AttrPalmSizeThreshold=5
......@@ -19,12 +19,15 @@ ModelAppleTouchpad=1
MatchName=*Apple Inc. Apple Internal Keyboard*
AttrKeyboardIntegration=internal
# The Apple MagicMouse has a touchpad built-in but the kernel still
# emulates a full 2/3 button mouse for us. Ignore anything from the
# ABS interface
[Apple MagicMouse]
MatchUdevType=mouse
MatchBus=bluetooth
MatchVendor=0x05AC
MatchProduct=0x030D
ModelAppleMagicMouse=1
AttrEventCodeDisable=EV_ABS
[Apple Magic Trackpad v1 (2010, clickpad)]
MatchUdevType=touchpad
......@@ -49,3 +52,10 @@ MatchBus=usb
MatchVendor=0x05AC
MatchProduct=0x0237
AttrPalmSizeThreshold=1000
[Apple Laptop Touchpad (MacBookPro11,2 among others)]
MatchUdevType=touchpad
MatchBus=usb
MatchVendor=0x5AC
MatchProduct=0x0262
AttrPalmSizeThreshold=1600
......@@ -10,7 +10,10 @@ MatchName=*ETPS/2 Elantech Touchpad*
MatchDMIModalias=dmi:*svnASUSTeKComputerInc.:pnUX21E:*
AttrPressureRange=24:10
# Asus UX302LA touchpad doesn't update the pressure values once two
# fingers are down. So let's just pretend it doesn't have pressure
# at all. https://gitlab.freedesktop.org/libinput/libinput/issues/145
[Asus UX302LA]
MatchName=*ETPS/2 Elantech Touchpad*
MatchDMIModalias=dmi:*svnASUSTeKCOMPUTERINC.:pnUX302LA:*
ModelAsusUX302LATouchpad=1
AttrEventCodeDisable=ABS_MT_PRESSURE;ABS_PRESSURE;
# Do not edit this file, it will be overwritten on update
# The Cyborg RAT has a mode button that cycles through event codes.
# On press, we get a release for the current mode and a press for the
# next mode:
# E: 0.000001 0004 0004 589833 # EV_MSC / MSC_SCAN 589833
# E: 0.000001 0001 0118 0000 # EV_KEY / (null) 0
# E: 0.000001 0004 0004 589834 # EV_MSC / MSC_SCAN 589834
# E: 0.000001 0001 0119 0001 # EV_KEY / (null) 1
# E: 0.000001 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +0ms
# E: 0.705000 0004 0004 589834 # EV_MSC / MSC_SCAN 589834
# E: 0.705000 0001 0119 0000 # EV_KEY / (null) 0
# E: 0.705000 0004 0004 589835 # EV_MSC / MSC_SCAN 589835
# E: 0.705000 0001 011a 0001 # EV_KEY / (null) 1
# E: 0.705000 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +705ms
# E: 1.496995 0004 0004 589833 # EV_MSC / MSC_SCAN 589833
# E: 1.496995 0001 0118 0001 # EV_KEY / (null) 1
# E: 1.496995 0004 0004 589835 # EV_MSC / MSC_SCAN 589835
# E: 1.496995 0001 011a 0000 # EV_KEY / (null) 0
# E: 1.496995 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +791ms
#
# https://bugs.freedesktop.org/show_bug.cgi?id=92127
#
# Disable the event codes to avoid stuck buttons.
[Saitek Cyborg RAT5]
MatchUdevType=mouse
MatchBus=usb
MatchVendor=0x06A3
MatchProduct=0x0CD5
ModelCyborgRat=1
# EV_KEY 0x118, 0x119, 0x11a
AttrEventCodeDisable=EV_KEY:0x118;EV_KEY:0x119;EV_KEY:0x11a
# Do not edit this file, it will be overwritten on update
#
# Claims to have double/tripletap but doesn't actually send it
# https://bugs.freedesktop.org/show_bug.cgi?id=98538
[HP Compaq 6910p]
MatchName=*SynPS/2 Synaptics TouchPad
MatchDMIModalias=dmi:*svnHewlett-Packard:*pnHPCompaq6910p*
ModelHP6910Touchpad=1
AttrEventCodeDisable=BTN_TOOL_DOUBLETAP;BTN_TOOL_TRIPLETAP;
# Claims to have double/tripletap but doesn't actually send it
# https://bugzilla.redhat.com/show_bug.cgi?id=1351285 and
[HP Compaq 8510w]
MatchName=*SynPS/2 Synaptics TouchPad
MatchDMIModalias=dmi:*svnHewlett-Packard:*pnHPCompaq8510w*
ModelHP8510Touchpad=1
AttrEventCodeDisable=BTN_TOOL_DOUBLETAP;BTN_TOOL_TRIPLETAP;
[HP Pavillion dmi4]
MatchName=*SynPS/2 Synaptics TouchPad
......@@ -29,3 +33,11 @@ ModelHPZBookStudioG3=1
MatchName=*Cypress APA Trackpad *cyapa*
MatchDMIModalias=dmi:*svnHewlett-Packard*:pnFalco*
AttrPressureRange=12:8
[HP Spectre x360 Convertable 15-bl1xx]
MatchUdevType=touchpad
MatchName=*SynPS/2 Synaptics TouchPad
MatchDMIModalias=dmi:*svnHP:pnHPSpectrex360Convertible15-bl1XX:*
AttrPressureRange=55:40
AttrThumbPressureThreshold=90
AttrPalmPressureThreshold=100
......@@ -20,6 +20,11 @@ MatchName=Synaptics tm2964-001
MatchDMIModalias=dmi:*svnLENOVO:*:pvrThinkPadT440p*
ModelLenovoT450Touchpad=1
[Lenovo T480s Touchpad]
MatchName=Elan Touchpad
MatchDMIModalias=dmi:*svnLENOVO:*:pvrThinkPadT480s*
ModelLenovoT480sTouchpad=1
[Lenovo X200 Trackpoint]
MatchName=*TPPS/2 IBM TrackPoint
MatchDMIModalias=dmi:*svnLENOVO:*pvrThinkPadX20?:*
......@@ -70,17 +75,38 @@ MatchName=AT Translated Set 2 keyboard
MatchDMIModalias=dmi:*svnLENOVO:*pvrThinkPad*Yoga*:*
ModelTabletModeNoSuspend=1
# Lenovo Carbon X1 6th gen (RMI4 only, PS/2 is broken on this device)
# Lenovo Carbon X1 6th gen (RMI4 only, PS/2 is broken on this device,
# sends bogus ABS_MT_TOOL_TYPE events for MT_TOOL_PALM
[Lenovo Carbon X1 6th gen]
MatchName=Synaptics TM3288-011
MatchDMIModalias=dmi:*svnLenovo:*pvrThinkPadX1Carbon6th:*
ModelLenovoCarbonX16th=1
AttrEventCodeDisable=ABS_MT_TOOL_TYPE
[Lenovo X41 Tablet]
MatchName=AT Translated Set 2 keyboard
MatchDMIModalias=dmi:*svnIBM:*pvrThinkPadX41Tablet:*
ModelTabletModeNoSuspend=1
[Lenovo X60 Tablet]
MatchName=AT Translated Set 2 keyboard
MatchDMIModalias=dmi:*svnLENOVO:*pvrThinkPadX60Tablet:*
ModelTabletModeNoSuspend=1
# Lenovo X220 Tablet special bezel buttons are associated to the
# keyboard and would therefore mistakenly be deactivated as well.
# See https://gitlab.freedesktop.org/libinput/libinput/issues/154
[Lenovo X220 Tablet]
MatchName=AT Translated Set 2 keyboard
MatchDMIModalias=dmi:*svnLENOVO:*pvrThinkPadX220Tablet:*
ModelTabletModeNoSuspend=1
# Special bezel button deactivation with
# keyboard also applies to X230 Tablet
[Lenovo X230 Tablet]
MatchName=AT Translated Set 2 keyboard
MatchDMIModalias=dmi:*svnLENOVO:*pvrThinkPadX230Tablet:*
ModelTabletModeNoSuspend=1
# Lenovo MIIX 720 comes with a detachable keyboard. We must not disable
# the keyboard because some keys are still accessible on the screen and
# volume rocker. See
......
......@@ -251,6 +251,36 @@ tp_button_area_handle_event(struct tp_dispatch *tp,
}
}
/**
* Release any button in the bottom area, provided it started within a
* threshold around start_time (i.e. simultaneously with the other touch
* that triggered this call).
*/
static inline void
tp_button_release_other_bottom_touches(struct tp_dispatch *tp,
uint64_t other_start_time)
{
struct tp_touch *t;
tp_for_each_touch(tp, t) {
uint64_t tdelta;
if (t->button.state != BUTTON_STATE_BOTTOM ||
t->button.has_moved)
continue;
if (other_start_time > t->button.initial_time)
tdelta = other_start_time - t->button.initial_time;
else
tdelta = t->button.initial_time - other_start_time;
if (tdelta > ms2us(80))
continue;
t->button.has_moved = true;
}
}
static void
tp_button_bottom_handle_event(struct tp_dispatch *tp,
struct tp_touch *t,
......@@ -271,6 +301,14 @@ tp_button_bottom_handle_event(struct tp_dispatch *tp,
case BUTTON_EVENT_IN_TOP_L:
case BUTTON_EVENT_IN_AREA:
tp_button_set_state(tp, t, BUTTON_STATE_AREA, event);
/* We just transitioned one finger from BOTTOM to AREA,
* if there are other fingers in BOTTOM that started
* simultaneously with this finger, release those fingers
* because they're part of a gesture.
*/
tp_button_release_other_bottom_touches(tp,
t->button.initial_time);
break;
case BUTTON_EVENT_UP:
tp_button_set_state(tp, t, BUTTON_STATE_NONE, event);
......@@ -450,7 +488,7 @@ tp_button_handle_event(struct tp_dispatch *tp,
if (current != t->button.state)
evdev_log_debug(tp->device,
"button state: touch %d from %s, event %s to %s\n",
"button state: touch %d from %-20s event %-24s to %-20s\n",
t->index,
button_state_to_str(current),
button_event_to_str(event),
......@@ -464,6 +502,9 @@ tp_button_check_for_movement(struct tp_dispatch *tp, struct tp_touch *t)
struct phys_coords mm;
double vector_length;
if (t->button.has_moved)
return;
switch (t->button.state) {
case BUTTON_STATE_NONE:
case BUTTON_STATE_AREA:
......@@ -482,8 +523,12 @@ tp_button_check_for_movement(struct tp_dispatch *tp, struct tp_touch *t)
mm = evdev_device_unit_delta_to_mm(tp->device, &delta);
vector_length = hypot(mm.x, mm.y);
if (vector_length > 5.0 /* mm */)
if (vector_length > 5.0 /* mm */) {
t->button.has_moved = true;
tp_button_release_other_bottom_touches(tp,
t->button.initial_time);
}
}
void
......@@ -497,6 +542,7 @@ tp_button_handle_state(struct tp_dispatch *tp, uint64_t time)
if (t->state == TOUCH_BEGIN) {
t->button.initial = t->point;
t->button.initial_time = time;
t->button.has_moved = false;
}
......
......@@ -305,6 +305,18 @@ tp_new_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
t->state == TOUCH_HOVERING)
return;
/* Bug #161: touch ends in the same event frame where it restarts
again. That's a kernel bug, so let's complain. */
if (t->state == TOUCH_MAYBE_END) {
evdev_log_bug_kernel(tp->device,
"touch %d ended and began in in same frame.\n",
t->index);
tp->nfingers_down++;
t->state = TOUCH_UPDATE;
t->has_ended = false;
return;
}
/* we begin the touch as hovering because until BTN_TOUCH happens we
* don't know if it's a touch down or not. And BTN_TOUCH may happen
* after ABS_MT_TRACKING_ID */
......@@ -1143,6 +1155,28 @@ tp_thumb_detect(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
}
}
/* If the finger is below the upper thumb line and we have another
* finger in the same area, neither finger is a thumb (unless we've
* already labeled it as such).
*/
if (t->point.y > tp->thumb.upper_thumb_line &&
tp->nfingers_down > 1) {
struct tp_touch *other;
tp_for_each_touch(tp, other) {
if (other->state != TOUCH_BEGIN &&
other->state != TOUCH_UPDATE)
continue;
if (other->point.y > tp->thumb.upper_thumb_line) {
t->thumb.state = THUMB_STATE_NO;
if (other->thumb.state == THUMB_STATE_MAYBE)
other->thumb.state = THUMB_STATE_NO;
break;
}
}
}
/* Note: a thumb at the edge of the touchpad won't trigger the
* threshold, the surface area is usually too small. So we have a
* two-stage detection: pressure and time within the area.
......@@ -1904,6 +1938,7 @@ tp_debug_touch_state(struct tp_dispatch *tp,
t->pressure,
tp_touch_active(tp, t) ? "" : "inactive");
}
if (buf[0] != '\0')
evdev_log_debug(device, "touch state: %s\n", buf);
}
......
......@@ -209,6 +209,7 @@ struct tp_touch {
struct libinput_timer timer;
struct device_coords initial;
bool has_moved; /* has moved more than threshold */
uint64_t initial_time;
} button;
struct {
......
......@@ -1144,20 +1144,22 @@ static inline struct wheel_angle
evdev_read_wheel_click_props(struct evdev_device *device)
{
struct wheel_angle angles;
const char *wheel_count = "MOUSE_WHEEL_CLICK_COUNT";
const char *wheel_angle = "MOUSE_WHEEL_CLICK_ANGLE";
const char *hwheel_count = "MOUSE_WHEEL_CLICK_COUNT_HORIZONTAL";
const char *hwheel_angle = "MOUSE_WHEEL_CLICK_ANGLE_HORIZONTAL";
/* CLICK_COUNT overrides CLICK_ANGLE */
if (!evdev_read_wheel_click_count_prop(device,
"MOUSE_WHEEL_CLICK_COUNT",
&angles.y))
evdev_read_wheel_click_prop(device,
"MOUSE_WHEEL_CLICK_ANGLE",
&angles.y);
if (!evdev_read_wheel_click_count_prop(device,
"MOUSE_WHEEL_CLICK_COUNT_HORIZONTAL",
&angles.x)) {
if (!evdev_read_wheel_click_prop(device,
"MOUSE_WHEEL_CLICK_ANGLE_HORIZONTAL",
&angles.x))
if (evdev_read_wheel_click_count_prop(device, wheel_count, &angles.y) ||
evdev_read_wheel_click_prop(device, wheel_angle, &angles.y)) {
evdev_log_debug(device,
"wheel: vert click angle: %.2f\n", angles.y);
}
if (evdev_read_wheel_click_count_prop(device, hwheel_count, &angles.x) ||
evdev_read_wheel_click_prop(device, hwheel_angle, &angles.x)) {
evdev_log_debug(device,
"wheel: horizontal click angle: %.2f\n", angles.y);
} else {
angles.x = angles.y;
}
......@@ -1897,99 +1899,26 @@ evdev_pre_configure_model_quirks(struct evdev_device *device)
{
struct quirks_context *quirks;
struct quirks *q;
const struct quirk_tuples *t;
char *prop;
/* The Cyborg RAT has a mode button that cycles through event codes.
* On press, we get a release for the current mode and a press for the
* next mode:
* E: 0.000001 0004 0004 589833 # EV_MSC / MSC_SCAN 589833
* E: 0.000001 0001 0118 0000 # EV_KEY / (null) 0
* E: 0.000001 0004 0004 589834 # EV_MSC / MSC_SCAN 589834
* E: 0.000001 0001 0119 0001 # EV_KEY / (null) 1
* E: 0.000001 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +0ms
* E: 0.705000 0004 0004 589834 # EV_MSC / MSC_SCAN 589834
* E: 0.705000 0001 0119 0000 # EV_KEY / (null) 0
* E: 0.705000 0004 0004 589835 # EV_MSC / MSC_SCAN 589835
* E: 0.705000 0001 011a 0001 # EV_KEY / (null) 1
* E: 0.705000 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +705ms
* E: 1.496995 0004 0004 589833 # EV_MSC / MSC_SCAN 589833
* E: 1.496995 0001 0118 0001 # EV_KEY / (null) 1
* E: 1.496995 0004 0004 589835 # EV_MSC / MSC_SCAN 589835
* E: 1.496995 0001 011a 0000 # EV_KEY / (null) 0
* E: 1.496995 0000 0000 0000 # ------------ SYN_REPORT (0) ---------- +791ms
*
* https://bugs.freedesktop.org/show_bug.cgi?id=92127
*
* Disable the event codes to avoid stuck buttons.
*/
if (evdev_device_has_model_quirk(device, QUIRK_MODEL_CYBORG_RAT)) {
libevdev_disable_event_code(device->evdev, EV_KEY, 0x118);
libevdev_disable_event_code(device->evdev, EV_KEY, 0x119);
libevdev_disable_event_code(device->evdev, EV_KEY, 0x11a);
}
/* The Apple MagicMouse has a touchpad built-in but the kernel still
* emulates a full 2/3 button mouse for us. Ignore anything from the
* ABS interface
*/
if (evdev_device_has_model_quirk(device, QUIRK_MODEL_APPLE_MAGICMOUSE))
libevdev_disable_event_type(device->evdev, EV_ABS);
/* Claims to have double/tripletap but doesn't actually send it
* https://bugzilla.redhat.com/show_bug.cgi?id=1351285 and
* https://bugs.freedesktop.org/show_bug.cgi?id=98538
*/
if (evdev_device_has_model_quirk(device, QUIRK_MODEL_HP8510_TOUCHPAD) ||
evdev_device_has_model_quirk(device, QUIRK_MODEL_HP6910_TOUCHPAD)) {
libevdev_disable_event_code(device->evdev, EV_KEY, BTN_TOOL_DOUBLETAP);
libevdev_disable_event_code(device->evdev, EV_KEY, BTN_TOOL_TRIPLETAP);
}
/* Touchpad is a clickpad but INPUT_PROP_BUTTONPAD is not set, see
* fdo bug 97147. Remove when RMI4 is commonplace */
if (evdev_device_has_model_quirk(device, QUIRK_MODEL_HP_STREAM11_TOUCHPAD))
libevdev_enable_property(device->evdev,
INPUT_PROP_BUTTONPAD);
/* Touchpad is a clickpad but INPUT_PROP_BUTTONPAD is not set, see
* https://gitlab.freedesktop.org/libinput/libinput/issues/177 */
if (evdev_device_has_model_quirk(device, QUIRK_MODEL_LENOVO_T480S_TOUCHPAD))
libevdev_enable_property(device->evdev,
INPUT_PROP_BUTTONPAD);
/* Touchpad claims to have 4 slots but only ever sends 2
* https://bugs.freedesktop.org/show_bug.cgi?id=98100 */
if (evdev_device_has_model_quirk(device, QUIRK_MODEL_HP_ZBOOK_STUDIO_G3))
libevdev_set_abs_maximum(device->evdev, ABS_MT_SLOT, 1);
/* Logitech Marble Mouse claims to have a middle button, same for
* the Kensington Orbit */
if (evdev_device_has_model_quirk(device,
QUIRK_MODEL_LOGITECH_MARBLE_MOUSE) ||
evdev_device_has_model_quirk(device,
QUIRK_MODEL_KENSINGTON_ORBIT))
libevdev_disable_event_code(device->evdev, EV_KEY, BTN_MIDDLE);
/* Aiptek tablets have tilt but don't send events */
if (evdev_device_has_model_quirk(device, QUIRK_MODEL_TABLET_NO_TILT)) {
libevdev_disable_event_code(device->evdev, EV_ABS, ABS_TILT_X);
libevdev_disable_event_code(device->evdev, EV_ABS, ABS_TILT_Y);
}
/* Lenovo Carbon X1 6th gen sends bogus ABS_MT_TOOL_TYPE events for
* MT_TOOL_PALM */
if (evdev_device_has_model_quirk(device, QUIRK_MODEL_LENOVO_CARBON_X1_6TH))
libevdev_disable_event_code(device->evdev,
EV_ABS,
ABS_MT_TOOL_TYPE);
/* Asus UX302LA touchpad doesn't update the pressure values once two
* fingers are down. So let's just pretend it doesn't have pressure
* at all. https://gitlab.freedesktop.org/libinput/libinput/issues/145
*/
if (evdev_device_has_model_quirk(device,
QUIRK_MODEL_ASUS_UX320LA_TOUCHPAD)) {
libevdev_disable_event_code(device->evdev,
EV_ABS,
ABS_MT_PRESSURE);
libevdev_disable_event_code(device->evdev,
EV_ABS,
ABS_PRESSURE);
}
/* Generally we don't care about MSC_TIMESTAMP and it can cause
* unnecessary wakeups but on some devices we need to watch it for
* pointer jumps */
......@@ -2000,7 +1929,32 @@ evdev_pre_configure_model_quirks(struct evdev_device *device)
!streq(prop, "watch")) {
libevdev_disable_event_code(device->evdev, EV_MSC, MSC_TIMESTAMP);
}
if (q && quirks_get_tuples(q, QUIRK_ATTR_EVENT_CODE_DISABLE, &t)) {
int type, code;
for (size_t i = 0; i < t->ntuples; i++) {
type = t->tuples[i].first;
code = t->tuples[i].second;
if (code == EVENT_CODE_UNDEFINED)
libevdev_disable_event_type(device->evdev,
type);
else
libevdev_disable_event_code(device->evdev,
type,
code);
evdev_log_debug(device,
"quirks: disabling %s %s (%#x %#x)\n",
libevdev_event_type_get_name(type),
libevdev_event_code_get_name(type, code),
type,
code);
}
}
quirks_unref(q);
}
static void
......
......@@ -36,6 +36,7 @@
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <libevdev/libevdev.h>
#include "libinput-util.h"
#include "libinput-private.h"
......@@ -398,6 +399,125 @@ parse_range_property(const char *prop, int *hi, int *lo)
return true;
}
static bool
parse_evcode_string(const char *s, int *type_out, int *code_out)
{
int type, code;
if (strneq(s, "EV_", 3)) {
type = libevdev_event_type_from_name(s);
if (type == -1)
return false;
code = EVENT_CODE_UNDEFINED;
} else {
struct map {
const char *str;
int type;
} map[] = {
{ "KEY_", EV_KEY },
{ "BTN_", EV_KEY },
{ "ABS_", EV_ABS },
{ "REL_", EV_REL },
{ "SW_", EV_SW },
};
struct map *m;
bool found = false;
ARRAY_FOR_EACH(map, m) {
if (!strneq(s, m->str, strlen(m->str)))
continue;
type = m->type;
code = libevdev_event_code_from_name(type, s);
if (code == -1)
return false;
found = true;
break;
}
if (!found)
return false;
}
*type_out = type;
*code_out = code;
return true;
}
/**
* Parses a string of the format "EV_ABS;KEY_A;BTN_TOOL_DOUBLETAP;ABS_X;"
* where each element must be a named event type OR a named event code OR a
* tuple in the form of EV_KEY:0x123, i.e. a named event type followed by a
* hex event code.
*
* events must point to an existing array of size nevents.
* nevents specifies the size of the array in events and returns the number
* of items, elements exceeding nevents are simply ignored, just make sure
* events is large enough for your use-case.
*
* The results are returned as input events with type and code set, all
* other fields undefined. Where only the event type is specified, the code
* is set to EVENT_CODE_UNDEFINED.
*
* On success, events contains nevents events.
*/
bool
parse_evcode_property(const char *prop, struct input_event *events, size_t *nevents)
{
char **strv = NULL;
bool rc = false;
size_t ncodes = 0;
size_t idx;
struct input_event evs[*nevents];
memset(evs, 0, sizeof evs);
strv = strv_from_string(prop, ";");
if (!strv)
goto out;
for (idx = 0; strv[idx]; idx++)
ncodes++;
/* A randomly chosen max so we avoid crazy quirks */
if (ncodes == 0 || ncodes > 32)
goto out;
ncodes = min(*nevents, ncodes);
for (idx = 0; strv[idx]; idx++) {
char *s = strv[idx];
int type, code;
if (strstr(s, ":") == NULL) {
if (!parse_evcode_string(s, &type, &code))
goto out;
} else {
int consumed;
char stype[13] = {0}; /* EV_FF_STATUS + '\0' */
if (sscanf(s, "%12[A-Z_]:%x%n", stype, &code, &consumed) != 2 ||
strlen(s) != (size_t)consumed ||
(type = libevdev_event_type_from_name(stype)) == -1 ||
code < 0 || code > libevdev_event_type_get_max(type))
goto out;
}
evs[idx].type = type;
evs[idx].code = code;
}
memcpy(events, evs, ncodes * sizeof *events);
*nevents = ncodes;
rc = true;
out:
strv_free(strv);
return rc;
}
/**
* Return the next word in a string pointed to by state before the first
* separator character. Call repeatedly to tokenize a whole string.
......
......@@ -44,6 +44,7 @@
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <linux/input.h>
#include "libinput.h"
......@@ -426,6 +427,8 @@ int parse_mouse_wheel_click_count_property(const char *prop);
bool parse_dimension_property(const char *prop, size_t *width, size_t *height);
bool parse_calibration_property(const char *prop, float calibration[6]);
bool parse_range_property(const char *prop, int *hi, int *lo);
#define EVENT_CODE_UNDEFINED 0xffff
bool parse_evcode_property(const char *prop, struct input_event *events, size_t *nevents);
enum tpkbcombo_layout {
TPKBCOMBO_LAYOUT_UNKNOWN,
......