summarylogtreecommitdiffstats
path: root/fix-101796.patch
blob: 3254dae3ad61c895383d7ced4efcd37a5ff94e49 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
 src/evdev.c         | 20 ++++++++++----------
 test/test-pointer.c | 35 +++++++++++++++++++++++++++++++++++
 2 files changed, 45 insertions(+), 10 deletions(-)

diff --git a/src/evdev.c b/src/evdev.c
index 24bfad07..bd1725c0 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -836,16 +836,16 @@ fallback_process_key(struct fallback_dispatch *dispatch,
 	type = get_key_type(e->code);
 
 	/* Ignore key release events from the kernel for keys that libinput
-	 * never got a pressed event for. */
-	if (e->value == 0) {
-		switch (type) {
-		case EVDEV_KEY_TYPE_NONE:
-			break;
-		case EVDEV_KEY_TYPE_KEY:
-		case EVDEV_KEY_TYPE_BUTTON:
-			if (!hw_is_key_down(dispatch, e->code))
-				return;
-		}
+	 * never got a pressed event for or key presses for keys that we
+	 * think are still down */
+	switch (type) {
+	case EVDEV_KEY_TYPE_NONE:
+		break;
+	case EVDEV_KEY_TYPE_KEY:
+	case EVDEV_KEY_TYPE_BUTTON:
+		if ((e->value && hw_is_key_down(dispatch, e->code)) ||
+		    (e->value == 0 && !hw_is_key_down(dispatch, e->code)))
+			return;
 	}
 
 	hw_set_key_down(dispatch, e->code, e->value);
diff --git a/test/test-pointer.c b/test/test-pointer.c
index e09f8f8a..2f03195a 100644
--- a/test/test-pointer.c
+++ b/test/test-pointer.c
@@ -490,6 +490,40 @@ START_TEST(pointer_button_has_no_button)
 }
 END_TEST
 
+START_TEST(pointer_recover_from_lost_button_count)
+{
+	struct litest_device *dev = litest_current_device();
+	struct libinput *li = dev->libinput;
+	struct libevdev *evdev = dev->evdev;
+
+	disable_button_scrolling(dev);
+
+	litest_drain_events(dev->libinput);
+
+	litest_button_click(dev, BTN_LEFT, 1);
+
+	litest_assert_button_event(li,
+				   BTN_LEFT,
+				   LIBINPUT_BUTTON_STATE_PRESSED);
+
+	/* Grab for the release to make libinput lose count */
+	libevdev_grab(evdev, LIBEVDEV_GRAB);
+	litest_button_click(dev, BTN_LEFT, 0);
+	libevdev_grab(evdev, LIBEVDEV_UNGRAB);
+
+	litest_assert_empty_queue(li);
+
+	litest_button_click(dev, BTN_LEFT, 1);
+	litest_assert_empty_queue(li);
+
+	litest_button_click(dev, BTN_LEFT, 0);
+	litest_assert_button_event(li,
+				   BTN_LEFT,
+				   LIBINPUT_BUTTON_STATE_RELEASED);
+	litest_assert_empty_queue(li);
+}
+END_TEST
+
 static inline double
 wheel_click_count(struct litest_device *dev, int which)
 {
@@ -2088,6 +2122,7 @@ litest_setup_tests_pointer(void)
 	litest_add_no_device("pointer:button", pointer_button_auto_release);
 	litest_add_no_device("pointer:button", pointer_seat_button_count);
 	litest_add_for_device("pointer:button", pointer_button_has_no_button, LITEST_KEYBOARD);
+	litest_add("pointer:button", pointer_recover_from_lost_button_count, LITEST_BUTTON, LITEST_CLICKPAD);
 	litest_add("pointer:scroll", pointer_scroll_wheel, LITEST_WHEEL, LITEST_TABLET);
 	litest_add("pointer:scroll", pointer_scroll_button, LITEST_RELATIVE|LITEST_BUTTON, LITEST_ANY);
 	litest_add("pointer:scroll", pointer_scroll_button_noscroll, LITEST_ABSOLUTE|LITEST_BUTTON, LITEST_RELATIVE);
-- 
2.13.3