1a46c0ec8Sopenharmony_ci/*
2a46c0ec8Sopenharmony_ci * Copyright © 2014-2015 Red Hat, Inc.
3a46c0ec8Sopenharmony_ci *
4a46c0ec8Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5a46c0ec8Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6a46c0ec8Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7a46c0ec8Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8a46c0ec8Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9a46c0ec8Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10a46c0ec8Sopenharmony_ci *
11a46c0ec8Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12a46c0ec8Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13a46c0ec8Sopenharmony_ci * Software.
14a46c0ec8Sopenharmony_ci *
15a46c0ec8Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16a46c0ec8Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17a46c0ec8Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18a46c0ec8Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19a46c0ec8Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20a46c0ec8Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21a46c0ec8Sopenharmony_ci * DEALINGS IN THE SOFTWARE.
22a46c0ec8Sopenharmony_ci */
23a46c0ec8Sopenharmony_ci
24a46c0ec8Sopenharmony_ci#include "config.h"
25a46c0ec8Sopenharmony_ci
26a46c0ec8Sopenharmony_ci#include <stdint.h>
27a46c0ec8Sopenharmony_ci
28a46c0ec8Sopenharmony_ci#include "evdev.h"
29a46c0ec8Sopenharmony_ci
30a46c0ec8Sopenharmony_ci#define MIDDLEBUTTON_TIMEOUT ms2us(50)
31a46c0ec8Sopenharmony_ci
32a46c0ec8Sopenharmony_ci/*****************************************
33a46c0ec8Sopenharmony_ci * BEFORE YOU EDIT THIS FILE, look at the state diagram in
34a46c0ec8Sopenharmony_ci * doc/middle-button-emulation-state-machine.svg (generated with
35a46c0ec8Sopenharmony_ci * https://www.diagrams.net).
36a46c0ec8Sopenharmony_ci *
37a46c0ec8Sopenharmony_ci * Any changes in this file must be represented in the diagram.
38a46c0ec8Sopenharmony_ci *
39a46c0ec8Sopenharmony_ci * Note in regards to the state machine: it only handles left, right and
40a46c0ec8Sopenharmony_ci * emulated middle button clicks, all other button events are passed
41a46c0ec8Sopenharmony_ci * through. When in the PASSTHROUGH state, all events are passed through
42a46c0ec8Sopenharmony_ci * as-is.
43a46c0ec8Sopenharmony_ci */
44a46c0ec8Sopenharmony_ci
45a46c0ec8Sopenharmony_cistatic inline const char*
46a46c0ec8Sopenharmony_cimiddlebutton_state_to_str(enum evdev_middlebutton_state state)
47a46c0ec8Sopenharmony_ci{
48a46c0ec8Sopenharmony_ci	switch (state) {
49a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(MIDDLEBUTTON_IDLE);
50a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(MIDDLEBUTTON_LEFT_DOWN);
51a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(MIDDLEBUTTON_RIGHT_DOWN);
52a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(MIDDLEBUTTON_MIDDLE);
53a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(MIDDLEBUTTON_LEFT_UP_PENDING);
54a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(MIDDLEBUTTON_RIGHT_UP_PENDING);
55a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(MIDDLEBUTTON_PASSTHROUGH);
56a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(MIDDLEBUTTON_IGNORE_LR);
57a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(MIDDLEBUTTON_IGNORE_L);
58a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(MIDDLEBUTTON_IGNORE_R);
59a46c0ec8Sopenharmony_ci	}
60a46c0ec8Sopenharmony_ci
61a46c0ec8Sopenharmony_ci	return NULL;
62a46c0ec8Sopenharmony_ci}
63a46c0ec8Sopenharmony_ci
64a46c0ec8Sopenharmony_cistatic inline const char*
65a46c0ec8Sopenharmony_cimiddlebutton_event_to_str(enum evdev_middlebutton_event event)
66a46c0ec8Sopenharmony_ci{
67a46c0ec8Sopenharmony_ci	switch (event) {
68a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(MIDDLEBUTTON_EVENT_L_DOWN);
69a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(MIDDLEBUTTON_EVENT_R_DOWN);
70a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(MIDDLEBUTTON_EVENT_OTHER);
71a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(MIDDLEBUTTON_EVENT_L_UP);
72a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(MIDDLEBUTTON_EVENT_R_UP);
73a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(MIDDLEBUTTON_EVENT_TIMEOUT);
74a46c0ec8Sopenharmony_ci	CASE_RETURN_STRING(MIDDLEBUTTON_EVENT_ALL_UP);
75a46c0ec8Sopenharmony_ci	}
76a46c0ec8Sopenharmony_ci
77a46c0ec8Sopenharmony_ci	return NULL;
78a46c0ec8Sopenharmony_ci}
79a46c0ec8Sopenharmony_ci
80a46c0ec8Sopenharmony_cistatic void
81a46c0ec8Sopenharmony_cimiddlebutton_state_error(struct evdev_device *device,
82a46c0ec8Sopenharmony_ci			 enum evdev_middlebutton_event event)
83a46c0ec8Sopenharmony_ci{
84a46c0ec8Sopenharmony_ci	evdev_log_bug_libinput(device,
85a46c0ec8Sopenharmony_ci			       "Invalid event %s in middle btn state %s\n",
86a46c0ec8Sopenharmony_ci			       middlebutton_event_to_str(event),
87a46c0ec8Sopenharmony_ci			       middlebutton_state_to_str(device->middlebutton.state));
88a46c0ec8Sopenharmony_ci}
89a46c0ec8Sopenharmony_ci
90a46c0ec8Sopenharmony_cistatic void
91a46c0ec8Sopenharmony_cimiddlebutton_timer_set(struct evdev_device *device, uint64_t now)
92a46c0ec8Sopenharmony_ci{
93a46c0ec8Sopenharmony_ci	libinput_timer_set(&device->middlebutton.timer,
94a46c0ec8Sopenharmony_ci			   now + MIDDLEBUTTON_TIMEOUT);
95a46c0ec8Sopenharmony_ci}
96a46c0ec8Sopenharmony_ci
97a46c0ec8Sopenharmony_cistatic void
98a46c0ec8Sopenharmony_cimiddlebutton_timer_cancel(struct evdev_device *device)
99a46c0ec8Sopenharmony_ci{
100a46c0ec8Sopenharmony_ci	libinput_timer_cancel(&device->middlebutton.timer);
101a46c0ec8Sopenharmony_ci}
102a46c0ec8Sopenharmony_ci
103a46c0ec8Sopenharmony_cistatic inline void
104a46c0ec8Sopenharmony_cimiddlebutton_set_state(struct evdev_device *device,
105a46c0ec8Sopenharmony_ci		       enum evdev_middlebutton_state state,
106a46c0ec8Sopenharmony_ci		       uint64_t now)
107a46c0ec8Sopenharmony_ci{
108a46c0ec8Sopenharmony_ci	switch (state) {
109a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_LEFT_DOWN:
110a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_RIGHT_DOWN:
111a46c0ec8Sopenharmony_ci		middlebutton_timer_set(device, now);
112a46c0ec8Sopenharmony_ci		device->middlebutton.first_event_time = now;
113a46c0ec8Sopenharmony_ci		break;
114a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_IDLE:
115a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_MIDDLE:
116a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_LEFT_UP_PENDING:
117a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_RIGHT_UP_PENDING:
118a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_PASSTHROUGH:
119a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_IGNORE_LR:
120a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_IGNORE_L:
121a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_IGNORE_R:
122a46c0ec8Sopenharmony_ci		middlebutton_timer_cancel(device);
123a46c0ec8Sopenharmony_ci		break;
124a46c0ec8Sopenharmony_ci	}
125a46c0ec8Sopenharmony_ci
126a46c0ec8Sopenharmony_ci	device->middlebutton.state = state;
127a46c0ec8Sopenharmony_ci}
128a46c0ec8Sopenharmony_ci
129a46c0ec8Sopenharmony_cistatic void
130a46c0ec8Sopenharmony_cimiddlebutton_post_event(struct evdev_device *device,
131a46c0ec8Sopenharmony_ci			uint64_t now,
132a46c0ec8Sopenharmony_ci			int button,
133a46c0ec8Sopenharmony_ci			enum libinput_button_state state)
134a46c0ec8Sopenharmony_ci{
135a46c0ec8Sopenharmony_ci	evdev_pointer_notify_button(device,
136a46c0ec8Sopenharmony_ci				    now,
137a46c0ec8Sopenharmony_ci				    button,
138a46c0ec8Sopenharmony_ci				    state);
139a46c0ec8Sopenharmony_ci}
140a46c0ec8Sopenharmony_ci
141a46c0ec8Sopenharmony_cistatic int
142a46c0ec8Sopenharmony_cievdev_middlebutton_idle_handle_event(struct evdev_device *device,
143a46c0ec8Sopenharmony_ci				     uint64_t time,
144a46c0ec8Sopenharmony_ci				     enum evdev_middlebutton_event event)
145a46c0ec8Sopenharmony_ci{
146a46c0ec8Sopenharmony_ci	switch (event) {
147a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_L_DOWN:
148a46c0ec8Sopenharmony_ci		middlebutton_set_state(device, MIDDLEBUTTON_LEFT_DOWN, time);
149a46c0ec8Sopenharmony_ci		break;
150a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_R_DOWN:
151a46c0ec8Sopenharmony_ci		middlebutton_set_state(device, MIDDLEBUTTON_RIGHT_DOWN, time);
152a46c0ec8Sopenharmony_ci		break;
153a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_OTHER:
154a46c0ec8Sopenharmony_ci		return 0;
155a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_R_UP:
156a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_L_UP:
157a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_TIMEOUT:
158a46c0ec8Sopenharmony_ci		middlebutton_state_error(device, event);
159a46c0ec8Sopenharmony_ci		break;
160a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_ALL_UP:
161a46c0ec8Sopenharmony_ci		break;
162a46c0ec8Sopenharmony_ci	}
163a46c0ec8Sopenharmony_ci
164a46c0ec8Sopenharmony_ci	return 1;
165a46c0ec8Sopenharmony_ci}
166a46c0ec8Sopenharmony_ci
167a46c0ec8Sopenharmony_cistatic int
168a46c0ec8Sopenharmony_cievdev_middlebutton_ldown_handle_event(struct evdev_device *device,
169a46c0ec8Sopenharmony_ci				      uint64_t time,
170a46c0ec8Sopenharmony_ci				      enum evdev_middlebutton_event event)
171a46c0ec8Sopenharmony_ci{
172a46c0ec8Sopenharmony_ci	switch (event) {
173a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_L_DOWN:
174a46c0ec8Sopenharmony_ci		middlebutton_state_error(device, event);
175a46c0ec8Sopenharmony_ci		break;
176a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_R_DOWN:
177a46c0ec8Sopenharmony_ci		middlebutton_post_event(device, time,
178a46c0ec8Sopenharmony_ci					BTN_MIDDLE,
179a46c0ec8Sopenharmony_ci					LIBINPUT_BUTTON_STATE_PRESSED);
180a46c0ec8Sopenharmony_ci		middlebutton_set_state(device, MIDDLEBUTTON_MIDDLE, time);
181a46c0ec8Sopenharmony_ci		break;
182a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_OTHER:
183a46c0ec8Sopenharmony_ci		middlebutton_post_event(device, time,
184a46c0ec8Sopenharmony_ci					BTN_LEFT,
185a46c0ec8Sopenharmony_ci					LIBINPUT_BUTTON_STATE_PRESSED);
186a46c0ec8Sopenharmony_ci		middlebutton_set_state(device,
187a46c0ec8Sopenharmony_ci				       MIDDLEBUTTON_PASSTHROUGH,
188a46c0ec8Sopenharmony_ci				       time);
189a46c0ec8Sopenharmony_ci		return 0;
190a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_R_UP:
191a46c0ec8Sopenharmony_ci		middlebutton_state_error(device, event);
192a46c0ec8Sopenharmony_ci		break;
193a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_L_UP:
194a46c0ec8Sopenharmony_ci		middlebutton_post_event(device,
195a46c0ec8Sopenharmony_ci					device->middlebutton.first_event_time,
196a46c0ec8Sopenharmony_ci					BTN_LEFT,
197a46c0ec8Sopenharmony_ci					LIBINPUT_BUTTON_STATE_PRESSED);
198a46c0ec8Sopenharmony_ci		middlebutton_post_event(device, time,
199a46c0ec8Sopenharmony_ci					BTN_LEFT,
200a46c0ec8Sopenharmony_ci					LIBINPUT_BUTTON_STATE_RELEASED);
201a46c0ec8Sopenharmony_ci		middlebutton_set_state(device, MIDDLEBUTTON_IDLE, time);
202a46c0ec8Sopenharmony_ci		break;
203a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_TIMEOUT:
204a46c0ec8Sopenharmony_ci		middlebutton_post_event(device,
205a46c0ec8Sopenharmony_ci					device->middlebutton.first_event_time,
206a46c0ec8Sopenharmony_ci					BTN_LEFT,
207a46c0ec8Sopenharmony_ci					LIBINPUT_BUTTON_STATE_PRESSED);
208a46c0ec8Sopenharmony_ci		middlebutton_set_state(device,
209a46c0ec8Sopenharmony_ci				       MIDDLEBUTTON_PASSTHROUGH,
210a46c0ec8Sopenharmony_ci				       time);
211a46c0ec8Sopenharmony_ci		break;
212a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_ALL_UP:
213a46c0ec8Sopenharmony_ci		middlebutton_state_error(device, event);
214a46c0ec8Sopenharmony_ci		break;
215a46c0ec8Sopenharmony_ci	}
216a46c0ec8Sopenharmony_ci
217a46c0ec8Sopenharmony_ci	return 1;
218a46c0ec8Sopenharmony_ci}
219a46c0ec8Sopenharmony_ci
220a46c0ec8Sopenharmony_cistatic int
221a46c0ec8Sopenharmony_cievdev_middlebutton_rdown_handle_event(struct evdev_device *device,
222a46c0ec8Sopenharmony_ci				      uint64_t time,
223a46c0ec8Sopenharmony_ci				      enum evdev_middlebutton_event event)
224a46c0ec8Sopenharmony_ci{
225a46c0ec8Sopenharmony_ci	switch (event) {
226a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_L_DOWN:
227a46c0ec8Sopenharmony_ci		middlebutton_post_event(device, time,
228a46c0ec8Sopenharmony_ci					BTN_MIDDLE,
229a46c0ec8Sopenharmony_ci					LIBINPUT_BUTTON_STATE_PRESSED);
230a46c0ec8Sopenharmony_ci		middlebutton_set_state(device, MIDDLEBUTTON_MIDDLE, time);
231a46c0ec8Sopenharmony_ci		break;
232a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_R_DOWN:
233a46c0ec8Sopenharmony_ci		middlebutton_state_error(device, event);
234a46c0ec8Sopenharmony_ci		break;
235a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_OTHER:
236a46c0ec8Sopenharmony_ci		middlebutton_post_event(device,
237a46c0ec8Sopenharmony_ci					device->middlebutton.first_event_time,
238a46c0ec8Sopenharmony_ci					BTN_RIGHT,
239a46c0ec8Sopenharmony_ci					LIBINPUT_BUTTON_STATE_PRESSED);
240a46c0ec8Sopenharmony_ci		middlebutton_set_state(device,
241a46c0ec8Sopenharmony_ci				       MIDDLEBUTTON_PASSTHROUGH,
242a46c0ec8Sopenharmony_ci				       time);
243a46c0ec8Sopenharmony_ci		return 0;
244a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_R_UP:
245a46c0ec8Sopenharmony_ci		middlebutton_post_event(device,
246a46c0ec8Sopenharmony_ci					device->middlebutton.first_event_time,
247a46c0ec8Sopenharmony_ci					BTN_RIGHT,
248a46c0ec8Sopenharmony_ci					LIBINPUT_BUTTON_STATE_PRESSED);
249a46c0ec8Sopenharmony_ci		middlebutton_post_event(device, time,
250a46c0ec8Sopenharmony_ci					BTN_RIGHT,
251a46c0ec8Sopenharmony_ci					LIBINPUT_BUTTON_STATE_RELEASED);
252a46c0ec8Sopenharmony_ci		middlebutton_set_state(device, MIDDLEBUTTON_IDLE, time);
253a46c0ec8Sopenharmony_ci		break;
254a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_L_UP:
255a46c0ec8Sopenharmony_ci		middlebutton_state_error(device, event);
256a46c0ec8Sopenharmony_ci		break;
257a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_TIMEOUT:
258a46c0ec8Sopenharmony_ci		middlebutton_post_event(device,
259a46c0ec8Sopenharmony_ci					device->middlebutton.first_event_time,
260a46c0ec8Sopenharmony_ci					BTN_RIGHT,
261a46c0ec8Sopenharmony_ci					LIBINPUT_BUTTON_STATE_PRESSED);
262a46c0ec8Sopenharmony_ci		middlebutton_set_state(device,
263a46c0ec8Sopenharmony_ci				       MIDDLEBUTTON_PASSTHROUGH,
264a46c0ec8Sopenharmony_ci				       time);
265a46c0ec8Sopenharmony_ci		break;
266a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_ALL_UP:
267a46c0ec8Sopenharmony_ci		middlebutton_state_error(device, event);
268a46c0ec8Sopenharmony_ci		break;
269a46c0ec8Sopenharmony_ci	}
270a46c0ec8Sopenharmony_ci
271a46c0ec8Sopenharmony_ci	return 1;
272a46c0ec8Sopenharmony_ci}
273a46c0ec8Sopenharmony_ci
274a46c0ec8Sopenharmony_cistatic int
275a46c0ec8Sopenharmony_cievdev_middlebutton_middle_handle_event(struct evdev_device *device,
276a46c0ec8Sopenharmony_ci				       uint64_t time,
277a46c0ec8Sopenharmony_ci				       enum evdev_middlebutton_event event)
278a46c0ec8Sopenharmony_ci{
279a46c0ec8Sopenharmony_ci	switch (event) {
280a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_L_DOWN:
281a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_R_DOWN:
282a46c0ec8Sopenharmony_ci		middlebutton_state_error(device, event);
283a46c0ec8Sopenharmony_ci		break;
284a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_OTHER:
285a46c0ec8Sopenharmony_ci		middlebutton_post_event(device, time,
286a46c0ec8Sopenharmony_ci					BTN_MIDDLE,
287a46c0ec8Sopenharmony_ci					LIBINPUT_BUTTON_STATE_RELEASED);
288a46c0ec8Sopenharmony_ci		middlebutton_set_state(device, MIDDLEBUTTON_IGNORE_LR, time);
289a46c0ec8Sopenharmony_ci		return 0;
290a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_R_UP:
291a46c0ec8Sopenharmony_ci		middlebutton_post_event(device, time,
292a46c0ec8Sopenharmony_ci					BTN_MIDDLE,
293a46c0ec8Sopenharmony_ci					LIBINPUT_BUTTON_STATE_RELEASED);
294a46c0ec8Sopenharmony_ci		middlebutton_set_state(device,
295a46c0ec8Sopenharmony_ci				       MIDDLEBUTTON_LEFT_UP_PENDING,
296a46c0ec8Sopenharmony_ci				       time);
297a46c0ec8Sopenharmony_ci		break;
298a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_L_UP:
299a46c0ec8Sopenharmony_ci		middlebutton_post_event(device, time,
300a46c0ec8Sopenharmony_ci					BTN_MIDDLE,
301a46c0ec8Sopenharmony_ci					LIBINPUT_BUTTON_STATE_RELEASED);
302a46c0ec8Sopenharmony_ci		middlebutton_set_state(device,
303a46c0ec8Sopenharmony_ci				       MIDDLEBUTTON_RIGHT_UP_PENDING,
304a46c0ec8Sopenharmony_ci				       time);
305a46c0ec8Sopenharmony_ci		break;
306a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_TIMEOUT:
307a46c0ec8Sopenharmony_ci		middlebutton_state_error(device, event);
308a46c0ec8Sopenharmony_ci		break;
309a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_ALL_UP:
310a46c0ec8Sopenharmony_ci		middlebutton_state_error(device, event);
311a46c0ec8Sopenharmony_ci		break;
312a46c0ec8Sopenharmony_ci	}
313a46c0ec8Sopenharmony_ci
314a46c0ec8Sopenharmony_ci	return 1;
315a46c0ec8Sopenharmony_ci}
316a46c0ec8Sopenharmony_ci
317a46c0ec8Sopenharmony_cistatic int
318a46c0ec8Sopenharmony_cievdev_middlebutton_lup_pending_handle_event(struct evdev_device *device,
319a46c0ec8Sopenharmony_ci					    uint64_t time,
320a46c0ec8Sopenharmony_ci					    enum evdev_middlebutton_event event)
321a46c0ec8Sopenharmony_ci{
322a46c0ec8Sopenharmony_ci	switch (event) {
323a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_L_DOWN:
324a46c0ec8Sopenharmony_ci		middlebutton_state_error(device, event);
325a46c0ec8Sopenharmony_ci		break;
326a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_R_DOWN:
327a46c0ec8Sopenharmony_ci		middlebutton_post_event(device, time,
328a46c0ec8Sopenharmony_ci					BTN_MIDDLE,
329a46c0ec8Sopenharmony_ci					LIBINPUT_BUTTON_STATE_PRESSED);
330a46c0ec8Sopenharmony_ci		middlebutton_set_state(device, MIDDLEBUTTON_MIDDLE, time);
331a46c0ec8Sopenharmony_ci		break;
332a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_OTHER:
333a46c0ec8Sopenharmony_ci		middlebutton_set_state(device, MIDDLEBUTTON_IGNORE_L, time);
334a46c0ec8Sopenharmony_ci		return 0;
335a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_R_UP:
336a46c0ec8Sopenharmony_ci		middlebutton_state_error(device, event);
337a46c0ec8Sopenharmony_ci		break;
338a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_L_UP:
339a46c0ec8Sopenharmony_ci		middlebutton_set_state(device, MIDDLEBUTTON_IDLE, time);
340a46c0ec8Sopenharmony_ci		break;
341a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_TIMEOUT:
342a46c0ec8Sopenharmony_ci		middlebutton_state_error(device, event);
343a46c0ec8Sopenharmony_ci		break;
344a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_ALL_UP:
345a46c0ec8Sopenharmony_ci		middlebutton_state_error(device, event);
346a46c0ec8Sopenharmony_ci		break;
347a46c0ec8Sopenharmony_ci	}
348a46c0ec8Sopenharmony_ci
349a46c0ec8Sopenharmony_ci	return 1;
350a46c0ec8Sopenharmony_ci}
351a46c0ec8Sopenharmony_ci
352a46c0ec8Sopenharmony_cistatic int
353a46c0ec8Sopenharmony_cievdev_middlebutton_rup_pending_handle_event(struct evdev_device *device,
354a46c0ec8Sopenharmony_ci					    uint64_t time,
355a46c0ec8Sopenharmony_ci					    enum evdev_middlebutton_event event)
356a46c0ec8Sopenharmony_ci{
357a46c0ec8Sopenharmony_ci	switch (event) {
358a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_L_DOWN:
359a46c0ec8Sopenharmony_ci		middlebutton_post_event(device, time,
360a46c0ec8Sopenharmony_ci					BTN_MIDDLE,
361a46c0ec8Sopenharmony_ci					LIBINPUT_BUTTON_STATE_PRESSED);
362a46c0ec8Sopenharmony_ci		middlebutton_set_state(device, MIDDLEBUTTON_MIDDLE, time);
363a46c0ec8Sopenharmony_ci		break;
364a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_R_DOWN:
365a46c0ec8Sopenharmony_ci		middlebutton_state_error(device, event);
366a46c0ec8Sopenharmony_ci		break;
367a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_OTHER:
368a46c0ec8Sopenharmony_ci		middlebutton_set_state(device, MIDDLEBUTTON_IGNORE_R, time);
369a46c0ec8Sopenharmony_ci		return 0;
370a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_R_UP:
371a46c0ec8Sopenharmony_ci		middlebutton_set_state(device, MIDDLEBUTTON_IDLE, time);
372a46c0ec8Sopenharmony_ci		break;
373a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_L_UP:
374a46c0ec8Sopenharmony_ci		middlebutton_state_error(device, event);
375a46c0ec8Sopenharmony_ci		break;
376a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_TIMEOUT:
377a46c0ec8Sopenharmony_ci		middlebutton_state_error(device, event);
378a46c0ec8Sopenharmony_ci		break;
379a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_ALL_UP:
380a46c0ec8Sopenharmony_ci		middlebutton_state_error(device, event);
381a46c0ec8Sopenharmony_ci		break;
382a46c0ec8Sopenharmony_ci	}
383a46c0ec8Sopenharmony_ci
384a46c0ec8Sopenharmony_ci	return 1;
385a46c0ec8Sopenharmony_ci}
386a46c0ec8Sopenharmony_ci
387a46c0ec8Sopenharmony_cistatic int
388a46c0ec8Sopenharmony_cievdev_middlebutton_passthrough_handle_event(struct evdev_device *device,
389a46c0ec8Sopenharmony_ci					    uint64_t time,
390a46c0ec8Sopenharmony_ci					    enum evdev_middlebutton_event event)
391a46c0ec8Sopenharmony_ci{
392a46c0ec8Sopenharmony_ci	switch (event) {
393a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_L_DOWN:
394a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_R_DOWN:
395a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_OTHER:
396a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_R_UP:
397a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_L_UP:
398a46c0ec8Sopenharmony_ci		return 0;
399a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_TIMEOUT:
400a46c0ec8Sopenharmony_ci		middlebutton_state_error(device, event);
401a46c0ec8Sopenharmony_ci		break;
402a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_ALL_UP:
403a46c0ec8Sopenharmony_ci		middlebutton_set_state(device, MIDDLEBUTTON_IDLE, time);
404a46c0ec8Sopenharmony_ci		break;
405a46c0ec8Sopenharmony_ci	}
406a46c0ec8Sopenharmony_ci
407a46c0ec8Sopenharmony_ci	return 1;
408a46c0ec8Sopenharmony_ci}
409a46c0ec8Sopenharmony_ci
410a46c0ec8Sopenharmony_cistatic int
411a46c0ec8Sopenharmony_cievdev_middlebutton_ignore_lr_handle_event(struct evdev_device *device,
412a46c0ec8Sopenharmony_ci					  uint64_t time,
413a46c0ec8Sopenharmony_ci					  enum evdev_middlebutton_event event)
414a46c0ec8Sopenharmony_ci{
415a46c0ec8Sopenharmony_ci	switch (event) {
416a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_L_DOWN:
417a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_R_DOWN:
418a46c0ec8Sopenharmony_ci		middlebutton_state_error(device, event);
419a46c0ec8Sopenharmony_ci		break;
420a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_OTHER:
421a46c0ec8Sopenharmony_ci		return 0;
422a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_R_UP:
423a46c0ec8Sopenharmony_ci		middlebutton_set_state(device, MIDDLEBUTTON_IGNORE_L, time);
424a46c0ec8Sopenharmony_ci		break;
425a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_L_UP:
426a46c0ec8Sopenharmony_ci		middlebutton_set_state(device, MIDDLEBUTTON_IGNORE_R, time);
427a46c0ec8Sopenharmony_ci		break;
428a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_TIMEOUT:
429a46c0ec8Sopenharmony_ci		middlebutton_state_error(device, event);
430a46c0ec8Sopenharmony_ci		break;
431a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_ALL_UP:
432a46c0ec8Sopenharmony_ci		middlebutton_state_error(device, event);
433a46c0ec8Sopenharmony_ci		break;
434a46c0ec8Sopenharmony_ci	}
435a46c0ec8Sopenharmony_ci
436a46c0ec8Sopenharmony_ci	return 1;
437a46c0ec8Sopenharmony_ci}
438a46c0ec8Sopenharmony_ci
439a46c0ec8Sopenharmony_cistatic int
440a46c0ec8Sopenharmony_cievdev_middlebutton_ignore_l_handle_event(struct evdev_device *device,
441a46c0ec8Sopenharmony_ci					 uint64_t time,
442a46c0ec8Sopenharmony_ci					 enum evdev_middlebutton_event event)
443a46c0ec8Sopenharmony_ci{
444a46c0ec8Sopenharmony_ci	switch (event) {
445a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_L_DOWN:
446a46c0ec8Sopenharmony_ci		middlebutton_state_error(device, event);
447a46c0ec8Sopenharmony_ci		break;
448a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_R_DOWN:
449a46c0ec8Sopenharmony_ci		return 0;
450a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_OTHER:
451a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_R_UP:
452a46c0ec8Sopenharmony_ci		return 0;
453a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_L_UP:
454a46c0ec8Sopenharmony_ci		middlebutton_set_state(device,
455a46c0ec8Sopenharmony_ci				       MIDDLEBUTTON_PASSTHROUGH,
456a46c0ec8Sopenharmony_ci				       time);
457a46c0ec8Sopenharmony_ci		break;
458a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_TIMEOUT:
459a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_ALL_UP:
460a46c0ec8Sopenharmony_ci		middlebutton_state_error(device, event);
461a46c0ec8Sopenharmony_ci		break;
462a46c0ec8Sopenharmony_ci	}
463a46c0ec8Sopenharmony_ci
464a46c0ec8Sopenharmony_ci	return 1;
465a46c0ec8Sopenharmony_ci}
466a46c0ec8Sopenharmony_cistatic int
467a46c0ec8Sopenharmony_cievdev_middlebutton_ignore_r_handle_event(struct evdev_device *device,
468a46c0ec8Sopenharmony_ci					 uint64_t time,
469a46c0ec8Sopenharmony_ci					 enum evdev_middlebutton_event event)
470a46c0ec8Sopenharmony_ci{
471a46c0ec8Sopenharmony_ci	switch (event) {
472a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_L_DOWN:
473a46c0ec8Sopenharmony_ci		return 0;
474a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_R_DOWN:
475a46c0ec8Sopenharmony_ci		middlebutton_state_error(device, event);
476a46c0ec8Sopenharmony_ci		break;
477a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_OTHER:
478a46c0ec8Sopenharmony_ci		return 0;
479a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_R_UP:
480a46c0ec8Sopenharmony_ci		middlebutton_set_state(device,
481a46c0ec8Sopenharmony_ci				       MIDDLEBUTTON_PASSTHROUGH,
482a46c0ec8Sopenharmony_ci				       time);
483a46c0ec8Sopenharmony_ci		break;
484a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_L_UP:
485a46c0ec8Sopenharmony_ci		return 0;
486a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_TIMEOUT:
487a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_EVENT_ALL_UP:
488a46c0ec8Sopenharmony_ci		break;
489a46c0ec8Sopenharmony_ci	}
490a46c0ec8Sopenharmony_ci
491a46c0ec8Sopenharmony_ci	return 1;
492a46c0ec8Sopenharmony_ci}
493a46c0ec8Sopenharmony_ci
494a46c0ec8Sopenharmony_cistatic int
495a46c0ec8Sopenharmony_cievdev_middlebutton_handle_event(struct evdev_device *device,
496a46c0ec8Sopenharmony_ci				uint64_t time,
497a46c0ec8Sopenharmony_ci				enum evdev_middlebutton_event event)
498a46c0ec8Sopenharmony_ci{
499a46c0ec8Sopenharmony_ci	int rc = 0;
500a46c0ec8Sopenharmony_ci	enum evdev_middlebutton_state current;
501a46c0ec8Sopenharmony_ci
502a46c0ec8Sopenharmony_ci	current = device->middlebutton.state;
503a46c0ec8Sopenharmony_ci
504a46c0ec8Sopenharmony_ci	switch (current) {
505a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_IDLE:
506a46c0ec8Sopenharmony_ci		rc = evdev_middlebutton_idle_handle_event(device, time, event);
507a46c0ec8Sopenharmony_ci		break;
508a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_LEFT_DOWN:
509a46c0ec8Sopenharmony_ci		rc = evdev_middlebutton_ldown_handle_event(device, time, event);
510a46c0ec8Sopenharmony_ci		break;
511a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_RIGHT_DOWN:
512a46c0ec8Sopenharmony_ci		rc = evdev_middlebutton_rdown_handle_event(device, time, event);
513a46c0ec8Sopenharmony_ci		break;
514a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_MIDDLE:
515a46c0ec8Sopenharmony_ci		rc = evdev_middlebutton_middle_handle_event(device, time, event);
516a46c0ec8Sopenharmony_ci		break;
517a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_LEFT_UP_PENDING:
518a46c0ec8Sopenharmony_ci		rc = evdev_middlebutton_lup_pending_handle_event(device,
519a46c0ec8Sopenharmony_ci								 time,
520a46c0ec8Sopenharmony_ci								 event);
521a46c0ec8Sopenharmony_ci		break;
522a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_RIGHT_UP_PENDING:
523a46c0ec8Sopenharmony_ci		rc = evdev_middlebutton_rup_pending_handle_event(device,
524a46c0ec8Sopenharmony_ci								 time,
525a46c0ec8Sopenharmony_ci								 event);
526a46c0ec8Sopenharmony_ci		break;
527a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_PASSTHROUGH:
528a46c0ec8Sopenharmony_ci		rc = evdev_middlebutton_passthrough_handle_event(device,
529a46c0ec8Sopenharmony_ci								 time,
530a46c0ec8Sopenharmony_ci								 event);
531a46c0ec8Sopenharmony_ci		break;
532a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_IGNORE_LR:
533a46c0ec8Sopenharmony_ci		rc = evdev_middlebutton_ignore_lr_handle_event(device,
534a46c0ec8Sopenharmony_ci							       time,
535a46c0ec8Sopenharmony_ci							       event);
536a46c0ec8Sopenharmony_ci		break;
537a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_IGNORE_L:
538a46c0ec8Sopenharmony_ci		rc = evdev_middlebutton_ignore_l_handle_event(device,
539a46c0ec8Sopenharmony_ci							      time,
540a46c0ec8Sopenharmony_ci							      event);
541a46c0ec8Sopenharmony_ci		break;
542a46c0ec8Sopenharmony_ci	case MIDDLEBUTTON_IGNORE_R:
543a46c0ec8Sopenharmony_ci		rc = evdev_middlebutton_ignore_r_handle_event(device,
544a46c0ec8Sopenharmony_ci							      time,
545a46c0ec8Sopenharmony_ci							      event);
546a46c0ec8Sopenharmony_ci		break;
547a46c0ec8Sopenharmony_ci	default:
548a46c0ec8Sopenharmony_ci		evdev_log_bug_libinput(device,
549a46c0ec8Sopenharmony_ci				       "Invalid middle button state %d\n",
550a46c0ec8Sopenharmony_ci				       current);
551a46c0ec8Sopenharmony_ci		break;
552a46c0ec8Sopenharmony_ci	}
553a46c0ec8Sopenharmony_ci
554a46c0ec8Sopenharmony_ci	evdev_log_debug(device,
555a46c0ec8Sopenharmony_ci			"middlebutton state: %s → %s → %s, rc %d\n",
556a46c0ec8Sopenharmony_ci			middlebutton_state_to_str(current),
557a46c0ec8Sopenharmony_ci			middlebutton_event_to_str(event),
558a46c0ec8Sopenharmony_ci			middlebutton_state_to_str(device->middlebutton.state),
559a46c0ec8Sopenharmony_ci			rc);
560a46c0ec8Sopenharmony_ci
561a46c0ec8Sopenharmony_ci	return rc;
562a46c0ec8Sopenharmony_ci}
563a46c0ec8Sopenharmony_ci
564a46c0ec8Sopenharmony_cistatic inline void
565a46c0ec8Sopenharmony_cievdev_middlebutton_apply_config(struct evdev_device *device)
566a46c0ec8Sopenharmony_ci{
567a46c0ec8Sopenharmony_ci	if (device->middlebutton.want_enabled ==
568a46c0ec8Sopenharmony_ci	    device->middlebutton.enabled)
569a46c0ec8Sopenharmony_ci		return;
570a46c0ec8Sopenharmony_ci
571a46c0ec8Sopenharmony_ci	if (device->middlebutton.button_mask != 0)
572a46c0ec8Sopenharmony_ci		return;
573a46c0ec8Sopenharmony_ci
574a46c0ec8Sopenharmony_ci	device->middlebutton.enabled = device->middlebutton.want_enabled;
575a46c0ec8Sopenharmony_ci}
576a46c0ec8Sopenharmony_ci
577a46c0ec8Sopenharmony_cibool
578a46c0ec8Sopenharmony_cievdev_middlebutton_filter_button(struct evdev_device *device,
579a46c0ec8Sopenharmony_ci				 uint64_t time,
580a46c0ec8Sopenharmony_ci				 int button,
581a46c0ec8Sopenharmony_ci				 enum libinput_button_state state)
582a46c0ec8Sopenharmony_ci{
583a46c0ec8Sopenharmony_ci	enum evdev_middlebutton_event event;
584a46c0ec8Sopenharmony_ci	bool is_press = state == LIBINPUT_BUTTON_STATE_PRESSED;
585a46c0ec8Sopenharmony_ci	int rc;
586a46c0ec8Sopenharmony_ci	unsigned int btnbit = (button - BTN_LEFT);
587a46c0ec8Sopenharmony_ci	uint32_t old_mask = 0;
588a46c0ec8Sopenharmony_ci
589a46c0ec8Sopenharmony_ci	if (!device->middlebutton.enabled)
590a46c0ec8Sopenharmony_ci		return false;
591a46c0ec8Sopenharmony_ci
592a46c0ec8Sopenharmony_ci	switch (button) {
593a46c0ec8Sopenharmony_ci	case BTN_LEFT:
594a46c0ec8Sopenharmony_ci		if (is_press)
595a46c0ec8Sopenharmony_ci			event = MIDDLEBUTTON_EVENT_L_DOWN;
596a46c0ec8Sopenharmony_ci		else
597a46c0ec8Sopenharmony_ci			event = MIDDLEBUTTON_EVENT_L_UP;
598a46c0ec8Sopenharmony_ci		break;
599a46c0ec8Sopenharmony_ci	case BTN_RIGHT:
600a46c0ec8Sopenharmony_ci		if (is_press)
601a46c0ec8Sopenharmony_ci			event = MIDDLEBUTTON_EVENT_R_DOWN;
602a46c0ec8Sopenharmony_ci		else
603a46c0ec8Sopenharmony_ci			event = MIDDLEBUTTON_EVENT_R_UP;
604a46c0ec8Sopenharmony_ci		break;
605a46c0ec8Sopenharmony_ci
606a46c0ec8Sopenharmony_ci	/* BTN_MIDDLE counts as "other" and resets middle button
607a46c0ec8Sopenharmony_ci	 * emulation */
608a46c0ec8Sopenharmony_ci	case BTN_MIDDLE:
609a46c0ec8Sopenharmony_ci	default:
610a46c0ec8Sopenharmony_ci		event = MIDDLEBUTTON_EVENT_OTHER;
611a46c0ec8Sopenharmony_ci		break;
612a46c0ec8Sopenharmony_ci	}
613a46c0ec8Sopenharmony_ci
614a46c0ec8Sopenharmony_ci	if (button < BTN_LEFT ||
615a46c0ec8Sopenharmony_ci	    btnbit >= sizeof(device->middlebutton.button_mask) * 8) {
616a46c0ec8Sopenharmony_ci		evdev_log_bug_libinput(device,
617a46c0ec8Sopenharmony_ci				       "Button mask too small for %s\n",
618a46c0ec8Sopenharmony_ci				       libevdev_event_code_get_name(EV_KEY,
619a46c0ec8Sopenharmony_ci								    button));
620a46c0ec8Sopenharmony_ci		return true;
621a46c0ec8Sopenharmony_ci	}
622a46c0ec8Sopenharmony_ci
623a46c0ec8Sopenharmony_ci	rc = evdev_middlebutton_handle_event(device, time, event);
624a46c0ec8Sopenharmony_ci
625a46c0ec8Sopenharmony_ci	old_mask = device->middlebutton.button_mask;
626a46c0ec8Sopenharmony_ci	if (is_press)
627a46c0ec8Sopenharmony_ci		device->middlebutton.button_mask |= bit(btnbit);
628a46c0ec8Sopenharmony_ci	else
629a46c0ec8Sopenharmony_ci		device->middlebutton.button_mask &= ~bit(btnbit);
630a46c0ec8Sopenharmony_ci
631a46c0ec8Sopenharmony_ci	if (old_mask != device->middlebutton.button_mask &&
632a46c0ec8Sopenharmony_ci	    device->middlebutton.button_mask == 0) {
633a46c0ec8Sopenharmony_ci		evdev_middlebutton_handle_event(device,
634a46c0ec8Sopenharmony_ci						time,
635a46c0ec8Sopenharmony_ci						MIDDLEBUTTON_EVENT_ALL_UP);
636a46c0ec8Sopenharmony_ci		evdev_middlebutton_apply_config(device);
637a46c0ec8Sopenharmony_ci	}
638a46c0ec8Sopenharmony_ci
639a46c0ec8Sopenharmony_ci	return rc;
640a46c0ec8Sopenharmony_ci}
641a46c0ec8Sopenharmony_ci
642a46c0ec8Sopenharmony_cistatic void
643a46c0ec8Sopenharmony_cievdev_middlebutton_handle_timeout(uint64_t now, void *data)
644a46c0ec8Sopenharmony_ci{
645a46c0ec8Sopenharmony_ci	struct evdev_device *device = evdev_device(data);
646a46c0ec8Sopenharmony_ci
647a46c0ec8Sopenharmony_ci	evdev_middlebutton_handle_event(device, now, MIDDLEBUTTON_EVENT_TIMEOUT);
648a46c0ec8Sopenharmony_ci}
649a46c0ec8Sopenharmony_ci
650a46c0ec8Sopenharmony_ciint
651a46c0ec8Sopenharmony_cievdev_middlebutton_is_available(struct libinput_device *device)
652a46c0ec8Sopenharmony_ci{
653a46c0ec8Sopenharmony_ci	return 1;
654a46c0ec8Sopenharmony_ci}
655a46c0ec8Sopenharmony_ci
656a46c0ec8Sopenharmony_cistatic enum libinput_config_status
657a46c0ec8Sopenharmony_cievdev_middlebutton_set(struct libinput_device *device,
658a46c0ec8Sopenharmony_ci		       enum libinput_config_middle_emulation_state enable)
659a46c0ec8Sopenharmony_ci{
660a46c0ec8Sopenharmony_ci	struct evdev_device *evdev = evdev_device(device);
661a46c0ec8Sopenharmony_ci
662a46c0ec8Sopenharmony_ci	switch (enable) {
663a46c0ec8Sopenharmony_ci	case LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED:
664a46c0ec8Sopenharmony_ci		evdev->middlebutton.want_enabled = true;
665a46c0ec8Sopenharmony_ci		break;
666a46c0ec8Sopenharmony_ci	case LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED:
667a46c0ec8Sopenharmony_ci		evdev->middlebutton.want_enabled = false;
668a46c0ec8Sopenharmony_ci		break;
669a46c0ec8Sopenharmony_ci	default:
670a46c0ec8Sopenharmony_ci		return LIBINPUT_CONFIG_STATUS_INVALID;
671a46c0ec8Sopenharmony_ci	}
672a46c0ec8Sopenharmony_ci
673a46c0ec8Sopenharmony_ci	evdev_middlebutton_apply_config(evdev);
674a46c0ec8Sopenharmony_ci
675a46c0ec8Sopenharmony_ci	return LIBINPUT_CONFIG_STATUS_SUCCESS;
676a46c0ec8Sopenharmony_ci}
677a46c0ec8Sopenharmony_ci
678a46c0ec8Sopenharmony_cienum libinput_config_middle_emulation_state
679a46c0ec8Sopenharmony_cievdev_middlebutton_get(struct libinput_device *device)
680a46c0ec8Sopenharmony_ci{
681a46c0ec8Sopenharmony_ci	struct evdev_device *evdev = evdev_device(device);
682a46c0ec8Sopenharmony_ci
683a46c0ec8Sopenharmony_ci	return evdev->middlebutton.want_enabled ?
684a46c0ec8Sopenharmony_ci			LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED :
685a46c0ec8Sopenharmony_ci			LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED;
686a46c0ec8Sopenharmony_ci}
687a46c0ec8Sopenharmony_ci
688a46c0ec8Sopenharmony_cienum libinput_config_middle_emulation_state
689a46c0ec8Sopenharmony_cievdev_middlebutton_get_default(struct libinput_device *device)
690a46c0ec8Sopenharmony_ci{
691a46c0ec8Sopenharmony_ci	struct evdev_device *evdev = evdev_device(device);
692a46c0ec8Sopenharmony_ci
693a46c0ec8Sopenharmony_ci	return evdev->middlebutton.enabled_default ?
694a46c0ec8Sopenharmony_ci			LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED :
695a46c0ec8Sopenharmony_ci			LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED;
696a46c0ec8Sopenharmony_ci}
697a46c0ec8Sopenharmony_ci
698a46c0ec8Sopenharmony_civoid
699a46c0ec8Sopenharmony_cievdev_init_middlebutton(struct evdev_device *device,
700a46c0ec8Sopenharmony_ci			bool enable,
701a46c0ec8Sopenharmony_ci			bool want_config)
702a46c0ec8Sopenharmony_ci{
703a46c0ec8Sopenharmony_ci	char timer_name[64];
704a46c0ec8Sopenharmony_ci
705a46c0ec8Sopenharmony_ci	snprintf(timer_name,
706a46c0ec8Sopenharmony_ci		 sizeof(timer_name),
707a46c0ec8Sopenharmony_ci		 "%s middlebutton",
708a46c0ec8Sopenharmony_ci		 evdev_device_get_sysname(device));
709a46c0ec8Sopenharmony_ci	libinput_timer_init(&device->middlebutton.timer,
710a46c0ec8Sopenharmony_ci			    evdev_libinput_context(device),
711a46c0ec8Sopenharmony_ci			    timer_name,
712a46c0ec8Sopenharmony_ci			    evdev_middlebutton_handle_timeout,
713a46c0ec8Sopenharmony_ci			    device);
714a46c0ec8Sopenharmony_ci	device->middlebutton.enabled_default = enable;
715a46c0ec8Sopenharmony_ci	device->middlebutton.want_enabled = enable;
716a46c0ec8Sopenharmony_ci	device->middlebutton.enabled = enable;
717a46c0ec8Sopenharmony_ci
718a46c0ec8Sopenharmony_ci	if (!want_config)
719a46c0ec8Sopenharmony_ci		return;
720a46c0ec8Sopenharmony_ci
721a46c0ec8Sopenharmony_ci	device->middlebutton.config.available = evdev_middlebutton_is_available;
722a46c0ec8Sopenharmony_ci	device->middlebutton.config.set = evdev_middlebutton_set;
723a46c0ec8Sopenharmony_ci	device->middlebutton.config.get = evdev_middlebutton_get;
724a46c0ec8Sopenharmony_ci	device->middlebutton.config.get_default = evdev_middlebutton_get_default;
725a46c0ec8Sopenharmony_ci	device->base.config.middle_emulation = &device->middlebutton.config;
726a46c0ec8Sopenharmony_ci}
727