diff --git a/src/evdev.c b/src/evdev.c index 50c8abd7..f15b8acc 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -1356,6 +1356,25 @@ lid_switch_process(struct evdev_dispatch *evdev_dispatch, } } +static inline enum switch_reliability +evdev_read_switch_reliability_prop(struct evdev_device *device) +{ + const char *prop; + enum switch_reliability r; + + prop = udev_device_get_property_value(device->udev_device, + "LIBINPUT_ATTR_LID_SWITCH_RELIABILITY"); + if (!parse_switch_reliability_property(prop, &r)) { + log_error(evdev_libinput_context(device), + "%s: switch reliability set to unknown value '%s'\n", + device->devname, + prop); + r = RELIABILITY_UNKNOWN; + } + + return r; +} + static void lid_switch_destroy(struct evdev_dispatch *evdev_dispatch) { @@ -1372,10 +1391,25 @@ lid_switch_sync_initial_state(struct evdev_device *device, struct lid_switch_dispatch *dispatch = (struct lid_switch_dispatch*)evdev_dispatch; struct libevdev *evdev = device->evdev; + bool is_closed = false; - dispatch->lid_is_closed = libevdev_get_event_value(evdev, - EV_SW, - SW_LID); + /* For the initial state sync, we depend on whether the lid switch + * is reliable. If we know it's reliable, we sync as expected. + * If we're not sure, we ignore the initial state and only sync on + * the first future lid close event. Laptops with a broken switch + * that always have the switch in 'on' state thus don't mess up our + * touchpad. + */ + switch(evdev_read_switch_reliability_prop(device)) { + case RELIABILITY_UNKNOWN: + is_closed = false; + break; + case RELIABILITY_RELIABLE: + is_closed = libevdev_get_event_value(evdev, EV_SW, SW_LID); + break; + } + + dispatch->lid_is_closed = is_closed; if (dispatch->lid_is_closed) { uint64_t time; time = libinput_now(evdev_libinput_context(device)); diff --git a/src/libinput-util.c b/src/libinput-util.c index 40e1e6e5..f5d0aa7f 100644 --- a/src/libinput-util.c +++ b/src/libinput-util.c @@ -278,6 +278,23 @@ parse_dimension_property(const char *prop, size_t *w, size_t *h) return true; } +bool +parse_switch_reliability_property(const char *prop, + enum switch_reliability *reliability) +{ + if (!prop) { + *reliability = RELIABILITY_UNKNOWN; + return true; + } + + if (streq(prop, "reliable")) + *reliability = RELIABILITY_RELIABLE; + else + return false; + + return true; +} + /** * Return the next word in a string pointed to by state before the first * separator character. Call repeatedly to tokenize a whole string. diff --git a/src/libinput-util.h b/src/libinput-util.h index ba09ab6e..ce3a5acc 100644 --- a/src/libinput-util.h +++ b/src/libinput-util.h @@ -377,6 +377,15 @@ int parse_mouse_wheel_click_count_property(const char *prop); double parse_trackpoint_accel_property(const char *prop); bool parse_dimension_property(const char *prop, size_t *width, size_t *height); +enum switch_reliability { + RELIABILITY_UNKNOWN, + RELIABILITY_RELIABLE, +}; + +bool +parse_switch_reliability_property(const char *prop, + enum switch_reliability *reliability); + static inline uint64_t us(uint64_t us) { diff --git a/test/litest-device-lid-switch.c b/test/litest-device-lid-switch.c index 823a5c9d..b96592dc 100644 --- a/test/litest-device-lid-switch.c +++ b/test/litest-device-lid-switch.c @@ -49,7 +49,8 @@ static const char udev_rule[] = "KERNEL!=\"event*\", GOTO=\"switch_end\"\n" "\n" "ATTRS{name}==\"litest Lid Switch*\",\\\n" -" ENV{ID_INPUT_SWITCH}=\"1\"\n" +" ENV{ID_INPUT_SWITCH}=\"1\",\\\n" +" ENV{LIBINPUT_ATTR_LID_SWITCH_RELIABILITY}=\"reliable\"\n" "\n" "LABEL=\"switch_end\""; diff --git a/test/test-misc.c b/test/test-misc.c index 9517042d..36cabdcf 100644 --- a/test/test-misc.c +++ b/test/test-misc.c @@ -908,6 +908,45 @@ START_TEST(dimension_prop_parser) } END_TEST +struct parser_test_reliability { + char *tag; + bool success; + enum switch_reliability reliability; +}; + +START_TEST(reliability_prop_parser) +{ + struct parser_test_reliability tests[] = { + { "reliable", true, RELIABILITY_RELIABLE }, + { "unreliable", false, 0 }, + { "", false, 0 }, + { "0", false, 0 }, + { "1", false, 0 }, + { NULL, false, 0, } + }; + enum switch_reliability r; + bool success; + int i; + + for (i = 0; tests[i].tag != NULL; i++) { + r = 0xaf; + success = parse_switch_reliability_property(tests[i].tag, &r); + ck_assert(success == tests[i].success); + if (success) + ck_assert_int_eq(r, tests[i].reliability); + else + ck_assert_int_eq(r, 0xaf); + } + + success = parse_switch_reliability_property(NULL, &r); + ck_assert(success == true); + ck_assert_int_eq(r, RELIABILITY_UNKNOWN); + + success = parse_switch_reliability_property("foo", NULL); + ck_assert(success == false); +} +END_TEST + START_TEST(time_conversion) { ck_assert_int_eq(us(10), 10); @@ -1180,6 +1219,7 @@ litest_setup_tests_misc(void) litest_add_no_device("misc:parser", wheel_click_count_parser); litest_add_no_device("misc:parser", trackpoint_accel_parser); litest_add_no_device("misc:parser", dimension_prop_parser); + litest_add_no_device("misc:parser", reliability_prop_parser); litest_add_no_device("misc:parser", safe_atoi_test); litest_add_no_device("misc:parser", safe_atod_test); litest_add_no_device("misc:parser", strsplit_test);