1a46c0ec8Sopenharmony_ci/* 2a46c0ec8Sopenharmony_ci * Copyright © 2010 Intel Corporation 3a46c0ec8Sopenharmony_ci * Copyright © 2013 Jonas Ådahl 4a46c0ec8Sopenharmony_ci * Copyright © 2013-2017 Red Hat, Inc. 5a46c0ec8Sopenharmony_ci * Copyright © 2017 James Ye <jye836@gmail.com> 6a46c0ec8Sopenharmony_ci * 7a46c0ec8Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 8a46c0ec8Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 9a46c0ec8Sopenharmony_ci * to deal in the Software without restriction, including without limitation 10a46c0ec8Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11a46c0ec8Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 12a46c0ec8Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 13a46c0ec8Sopenharmony_ci * 14a46c0ec8Sopenharmony_ci * The above copyright notice and this permission notice (including the next 15a46c0ec8Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 16a46c0ec8Sopenharmony_ci * Software. 17a46c0ec8Sopenharmony_ci * 18a46c0ec8Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19a46c0ec8Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20a46c0ec8Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21a46c0ec8Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22a46c0ec8Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23a46c0ec8Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24a46c0ec8Sopenharmony_ci * DEALINGS IN THE SOFTWARE. 25a46c0ec8Sopenharmony_ci */ 26a46c0ec8Sopenharmony_ci 27a46c0ec8Sopenharmony_ci#include "config.h" 28a46c0ec8Sopenharmony_ci 29a46c0ec8Sopenharmony_ci#include <mtdev-plumbing.h> 30a46c0ec8Sopenharmony_ci 31a46c0ec8Sopenharmony_ci#include "evdev-fallback.h" 32a46c0ec8Sopenharmony_ci#include "util-input-event.h" 33a46c0ec8Sopenharmony_ci 34a46c0ec8Sopenharmony_cistatic void 35a46c0ec8Sopenharmony_cifallback_keyboard_notify_key(struct fallback_dispatch *dispatch, 36a46c0ec8Sopenharmony_ci struct evdev_device *device, 37a46c0ec8Sopenharmony_ci uint64_t time, 38a46c0ec8Sopenharmony_ci int key, 39a46c0ec8Sopenharmony_ci enum libinput_key_state state) 40a46c0ec8Sopenharmony_ci{ 41a46c0ec8Sopenharmony_ci int down_count; 42a46c0ec8Sopenharmony_ci 43a46c0ec8Sopenharmony_ci down_count = evdev_update_key_down_count(device, key, state); 44a46c0ec8Sopenharmony_ci 45a46c0ec8Sopenharmony_ci if ((state == LIBINPUT_KEY_STATE_PRESSED && down_count == 1) || 46a46c0ec8Sopenharmony_ci (state == LIBINPUT_KEY_STATE_RELEASED && down_count == 0)) 47a46c0ec8Sopenharmony_ci keyboard_notify_key(&device->base, time, key, state); 48a46c0ec8Sopenharmony_ci} 49a46c0ec8Sopenharmony_ci 50a46c0ec8Sopenharmony_cistatic void 51a46c0ec8Sopenharmony_cifallback_lid_notify_toggle(struct fallback_dispatch *dispatch, 52a46c0ec8Sopenharmony_ci struct evdev_device *device, 53a46c0ec8Sopenharmony_ci uint64_t time) 54a46c0ec8Sopenharmony_ci{ 55a46c0ec8Sopenharmony_ci if (dispatch->lid.is_closed ^ dispatch->lid.is_closed_client_state) { 56a46c0ec8Sopenharmony_ci switch_notify_toggle(&device->base, 57a46c0ec8Sopenharmony_ci time, 58a46c0ec8Sopenharmony_ci LIBINPUT_SWITCH_LID, 59a46c0ec8Sopenharmony_ci dispatch->lid.is_closed); 60a46c0ec8Sopenharmony_ci dispatch->lid.is_closed_client_state = dispatch->lid.is_closed; 61a46c0ec8Sopenharmony_ci } 62a46c0ec8Sopenharmony_ci} 63a46c0ec8Sopenharmony_ci 64a46c0ec8Sopenharmony_civoid 65a46c0ec8Sopenharmony_cifallback_notify_physical_button(struct fallback_dispatch *dispatch, 66a46c0ec8Sopenharmony_ci struct evdev_device *device, 67a46c0ec8Sopenharmony_ci uint64_t time, 68a46c0ec8Sopenharmony_ci int button, 69a46c0ec8Sopenharmony_ci enum libinput_button_state state) 70a46c0ec8Sopenharmony_ci{ 71a46c0ec8Sopenharmony_ci evdev_pointer_notify_physical_button(device, time, button, state); 72a46c0ec8Sopenharmony_ci} 73a46c0ec8Sopenharmony_ci 74a46c0ec8Sopenharmony_cistatic enum libinput_switch_state 75a46c0ec8Sopenharmony_cifallback_interface_get_switch_state(struct evdev_dispatch *evdev_dispatch, 76a46c0ec8Sopenharmony_ci enum libinput_switch sw) 77a46c0ec8Sopenharmony_ci{ 78a46c0ec8Sopenharmony_ci struct fallback_dispatch *dispatch = fallback_dispatch(evdev_dispatch); 79a46c0ec8Sopenharmony_ci 80a46c0ec8Sopenharmony_ci switch (sw) { 81a46c0ec8Sopenharmony_ci case LIBINPUT_SWITCH_TABLET_MODE: 82a46c0ec8Sopenharmony_ci break; 83a46c0ec8Sopenharmony_ci default: 84a46c0ec8Sopenharmony_ci /* Internal function only, so we can abort here */ 85a46c0ec8Sopenharmony_ci abort(); 86a46c0ec8Sopenharmony_ci } 87a46c0ec8Sopenharmony_ci 88a46c0ec8Sopenharmony_ci return dispatch->tablet_mode.sw.state ? 89a46c0ec8Sopenharmony_ci LIBINPUT_SWITCH_STATE_ON : 90a46c0ec8Sopenharmony_ci LIBINPUT_SWITCH_STATE_OFF; 91a46c0ec8Sopenharmony_ci} 92a46c0ec8Sopenharmony_ci 93a46c0ec8Sopenharmony_cistatic inline bool 94a46c0ec8Sopenharmony_cipost_button_scroll(struct evdev_device *device, 95a46c0ec8Sopenharmony_ci struct device_float_coords raw, 96a46c0ec8Sopenharmony_ci uint64_t time) 97a46c0ec8Sopenharmony_ci{ 98a46c0ec8Sopenharmony_ci if (device->scroll.method != LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN) 99a46c0ec8Sopenharmony_ci return false; 100a46c0ec8Sopenharmony_ci 101a46c0ec8Sopenharmony_ci switch(device->scroll.button_scroll_state) { 102a46c0ec8Sopenharmony_ci case BUTTONSCROLL_IDLE: 103a46c0ec8Sopenharmony_ci return false; 104a46c0ec8Sopenharmony_ci case BUTTONSCROLL_BUTTON_DOWN: 105a46c0ec8Sopenharmony_ci /* if the button is down but scroll is not active, we're within the 106a46c0ec8Sopenharmony_ci timeout where we swallow motion events but don't post 107a46c0ec8Sopenharmony_ci scroll buttons */ 108a46c0ec8Sopenharmony_ci evdev_log_debug(device, "btnscroll: discarding\n"); 109a46c0ec8Sopenharmony_ci return true; 110a46c0ec8Sopenharmony_ci case BUTTONSCROLL_READY: 111a46c0ec8Sopenharmony_ci device->scroll.button_scroll_state = BUTTONSCROLL_SCROLLING; 112a46c0ec8Sopenharmony_ci _fallthrough_; 113a46c0ec8Sopenharmony_ci case BUTTONSCROLL_SCROLLING: 114a46c0ec8Sopenharmony_ci { 115a46c0ec8Sopenharmony_ci const struct normalized_coords normalized = 116a46c0ec8Sopenharmony_ci filter_dispatch_scroll(device->pointer.filter, 117a46c0ec8Sopenharmony_ci &raw, 118a46c0ec8Sopenharmony_ci device, 119a46c0ec8Sopenharmony_ci time); 120a46c0ec8Sopenharmony_ci evdev_post_scroll(device, time, 121a46c0ec8Sopenharmony_ci LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS, 122a46c0ec8Sopenharmony_ci &normalized); 123a46c0ec8Sopenharmony_ci } 124a46c0ec8Sopenharmony_ci return true; 125a46c0ec8Sopenharmony_ci } 126a46c0ec8Sopenharmony_ci 127a46c0ec8Sopenharmony_ci assert(!"invalid scroll button state"); 128a46c0ec8Sopenharmony_ci} 129a46c0ec8Sopenharmony_ci 130a46c0ec8Sopenharmony_cistatic inline bool 131a46c0ec8Sopenharmony_cifallback_filter_defuzz_touch(struct fallback_dispatch *dispatch, 132a46c0ec8Sopenharmony_ci struct evdev_device *device, 133a46c0ec8Sopenharmony_ci struct mt_slot *slot) 134a46c0ec8Sopenharmony_ci{ 135a46c0ec8Sopenharmony_ci struct device_coords point; 136a46c0ec8Sopenharmony_ci 137a46c0ec8Sopenharmony_ci if (!dispatch->mt.want_hysteresis) 138a46c0ec8Sopenharmony_ci return false; 139a46c0ec8Sopenharmony_ci 140a46c0ec8Sopenharmony_ci point = evdev_hysteresis(&slot->point, 141a46c0ec8Sopenharmony_ci &slot->hysteresis_center, 142a46c0ec8Sopenharmony_ci &dispatch->mt.hysteresis_margin); 143a46c0ec8Sopenharmony_ci slot->point = point; 144a46c0ec8Sopenharmony_ci 145a46c0ec8Sopenharmony_ci if (point.x == slot->hysteresis_center.x && 146a46c0ec8Sopenharmony_ci point.y == slot->hysteresis_center.y) 147a46c0ec8Sopenharmony_ci return true; 148a46c0ec8Sopenharmony_ci 149a46c0ec8Sopenharmony_ci slot->hysteresis_center = point; 150a46c0ec8Sopenharmony_ci 151a46c0ec8Sopenharmony_ci return false; 152a46c0ec8Sopenharmony_ci} 153a46c0ec8Sopenharmony_ci 154a46c0ec8Sopenharmony_cistatic inline struct device_float_coords 155a46c0ec8Sopenharmony_cifallback_rotate_relative(struct fallback_dispatch *dispatch, 156a46c0ec8Sopenharmony_ci struct evdev_device *device) 157a46c0ec8Sopenharmony_ci{ 158a46c0ec8Sopenharmony_ci struct device_float_coords rel = { dispatch->rel.x, dispatch->rel.y }; 159a46c0ec8Sopenharmony_ci 160a46c0ec8Sopenharmony_ci if (!device->base.config.rotation) 161a46c0ec8Sopenharmony_ci return rel; 162a46c0ec8Sopenharmony_ci 163a46c0ec8Sopenharmony_ci matrix_mult_vec_double(&dispatch->rotation.matrix, &rel.x, &rel.y); 164a46c0ec8Sopenharmony_ci 165a46c0ec8Sopenharmony_ci return rel; 166a46c0ec8Sopenharmony_ci} 167a46c0ec8Sopenharmony_ci 168a46c0ec8Sopenharmony_cistatic void 169a46c0ec8Sopenharmony_cifallback_flush_relative_motion(struct fallback_dispatch *dispatch, 170a46c0ec8Sopenharmony_ci struct evdev_device *device, 171a46c0ec8Sopenharmony_ci uint64_t time) 172a46c0ec8Sopenharmony_ci{ 173a46c0ec8Sopenharmony_ci struct libinput_device *base = &device->base; 174a46c0ec8Sopenharmony_ci struct normalized_coords accel; 175a46c0ec8Sopenharmony_ci 176a46c0ec8Sopenharmony_ci if (!(device->seat_caps & EVDEV_DEVICE_POINTER)) 177a46c0ec8Sopenharmony_ci return; 178a46c0ec8Sopenharmony_ci 179a46c0ec8Sopenharmony_ci struct device_float_coords raw = fallback_rotate_relative(dispatch, device); 180a46c0ec8Sopenharmony_ci 181a46c0ec8Sopenharmony_ci dispatch->rel.x = 0; 182a46c0ec8Sopenharmony_ci dispatch->rel.y = 0; 183a46c0ec8Sopenharmony_ci 184a46c0ec8Sopenharmony_ci /* Use unaccelerated deltas for pointing stick scroll */ 185a46c0ec8Sopenharmony_ci if (post_button_scroll(device, raw, time)) 186a46c0ec8Sopenharmony_ci return; 187a46c0ec8Sopenharmony_ci 188a46c0ec8Sopenharmony_ci if (device->pointer.filter) { 189a46c0ec8Sopenharmony_ci /* Apply pointer acceleration. */ 190a46c0ec8Sopenharmony_ci accel = filter_dispatch(device->pointer.filter, 191a46c0ec8Sopenharmony_ci &raw, 192a46c0ec8Sopenharmony_ci device, 193a46c0ec8Sopenharmony_ci time); 194a46c0ec8Sopenharmony_ci } else { 195a46c0ec8Sopenharmony_ci evdev_log_bug_libinput(device, 196a46c0ec8Sopenharmony_ci "accel filter missing\n"); 197a46c0ec8Sopenharmony_ci accel.x = accel.y = 0; 198a46c0ec8Sopenharmony_ci } 199a46c0ec8Sopenharmony_ci 200a46c0ec8Sopenharmony_ci if (normalized_is_zero(accel)) 201a46c0ec8Sopenharmony_ci return; 202a46c0ec8Sopenharmony_ci 203a46c0ec8Sopenharmony_ci pointer_notify_motion(base, time, &accel, &raw); 204a46c0ec8Sopenharmony_ci} 205a46c0ec8Sopenharmony_ci 206a46c0ec8Sopenharmony_cistatic void 207a46c0ec8Sopenharmony_cifallback_flush_absolute_motion(struct fallback_dispatch *dispatch, 208a46c0ec8Sopenharmony_ci struct evdev_device *device, 209a46c0ec8Sopenharmony_ci uint64_t time) 210a46c0ec8Sopenharmony_ci{ 211a46c0ec8Sopenharmony_ci struct libinput_device *base = &device->base; 212a46c0ec8Sopenharmony_ci struct device_coords point; 213a46c0ec8Sopenharmony_ci 214a46c0ec8Sopenharmony_ci if (!(device->seat_caps & EVDEV_DEVICE_POINTER)) 215a46c0ec8Sopenharmony_ci return; 216a46c0ec8Sopenharmony_ci 217a46c0ec8Sopenharmony_ci point = dispatch->abs.point; 218a46c0ec8Sopenharmony_ci evdev_transform_absolute(device, &point); 219a46c0ec8Sopenharmony_ci 220a46c0ec8Sopenharmony_ci pointer_notify_motion_absolute(base, time, &point); 221a46c0ec8Sopenharmony_ci} 222a46c0ec8Sopenharmony_ci 223a46c0ec8Sopenharmony_cistatic bool 224a46c0ec8Sopenharmony_cifallback_flush_mt_down(struct fallback_dispatch *dispatch, 225a46c0ec8Sopenharmony_ci struct evdev_device *device, 226a46c0ec8Sopenharmony_ci int slot_idx, 227a46c0ec8Sopenharmony_ci uint64_t time) 228a46c0ec8Sopenharmony_ci{ 229a46c0ec8Sopenharmony_ci struct libinput_device *base = &device->base; 230a46c0ec8Sopenharmony_ci struct libinput_seat *seat = base->seat; 231a46c0ec8Sopenharmony_ci struct device_coords point; 232a46c0ec8Sopenharmony_ci struct mt_slot *slot; 233a46c0ec8Sopenharmony_ci int seat_slot; 234a46c0ec8Sopenharmony_ci 235a46c0ec8Sopenharmony_ci if (!(device->seat_caps & EVDEV_DEVICE_TOUCH)) 236a46c0ec8Sopenharmony_ci return false; 237a46c0ec8Sopenharmony_ci 238a46c0ec8Sopenharmony_ci slot = &dispatch->mt.slots[slot_idx]; 239a46c0ec8Sopenharmony_ci if (slot->seat_slot != -1) { 240a46c0ec8Sopenharmony_ci evdev_log_bug_kernel(device, 241a46c0ec8Sopenharmony_ci "driver sent multiple touch down for the same slot"); 242a46c0ec8Sopenharmony_ci return false; 243a46c0ec8Sopenharmony_ci } 244a46c0ec8Sopenharmony_ci 245a46c0ec8Sopenharmony_ci seat_slot = ffs(~seat->slot_map) - 1; 246a46c0ec8Sopenharmony_ci slot->seat_slot = seat_slot; 247a46c0ec8Sopenharmony_ci 248a46c0ec8Sopenharmony_ci if (seat_slot == -1) 249a46c0ec8Sopenharmony_ci return false; 250a46c0ec8Sopenharmony_ci 251a46c0ec8Sopenharmony_ci seat->slot_map |= bit(seat_slot); 252a46c0ec8Sopenharmony_ci point = slot->point; 253a46c0ec8Sopenharmony_ci slot->hysteresis_center = point; 254a46c0ec8Sopenharmony_ci evdev_transform_absolute(device, &point); 255a46c0ec8Sopenharmony_ci 256a46c0ec8Sopenharmony_ci touch_notify_touch_down(base, time, slot_idx, seat_slot, 257a46c0ec8Sopenharmony_ci &point); 258a46c0ec8Sopenharmony_ci 259a46c0ec8Sopenharmony_ci return true; 260a46c0ec8Sopenharmony_ci} 261a46c0ec8Sopenharmony_ci 262a46c0ec8Sopenharmony_cistatic bool 263a46c0ec8Sopenharmony_cifallback_flush_mt_motion(struct fallback_dispatch *dispatch, 264a46c0ec8Sopenharmony_ci struct evdev_device *device, 265a46c0ec8Sopenharmony_ci int slot_idx, 266a46c0ec8Sopenharmony_ci uint64_t time) 267a46c0ec8Sopenharmony_ci{ 268a46c0ec8Sopenharmony_ci struct libinput_device *base = &device->base; 269a46c0ec8Sopenharmony_ci struct device_coords point; 270a46c0ec8Sopenharmony_ci struct mt_slot *slot; 271a46c0ec8Sopenharmony_ci int seat_slot; 272a46c0ec8Sopenharmony_ci 273a46c0ec8Sopenharmony_ci if (!(device->seat_caps & EVDEV_DEVICE_TOUCH)) 274a46c0ec8Sopenharmony_ci return false; 275a46c0ec8Sopenharmony_ci 276a46c0ec8Sopenharmony_ci slot = &dispatch->mt.slots[slot_idx]; 277a46c0ec8Sopenharmony_ci seat_slot = slot->seat_slot; 278a46c0ec8Sopenharmony_ci point = slot->point; 279a46c0ec8Sopenharmony_ci 280a46c0ec8Sopenharmony_ci if (seat_slot == -1) 281a46c0ec8Sopenharmony_ci return false; 282a46c0ec8Sopenharmony_ci 283a46c0ec8Sopenharmony_ci if (fallback_filter_defuzz_touch(dispatch, device, slot)) 284a46c0ec8Sopenharmony_ci return false; 285a46c0ec8Sopenharmony_ci 286a46c0ec8Sopenharmony_ci evdev_transform_absolute(device, &point); 287a46c0ec8Sopenharmony_ci touch_notify_touch_motion(base, time, slot_idx, seat_slot, 288a46c0ec8Sopenharmony_ci &point); 289a46c0ec8Sopenharmony_ci 290a46c0ec8Sopenharmony_ci return true; 291a46c0ec8Sopenharmony_ci} 292a46c0ec8Sopenharmony_ci 293a46c0ec8Sopenharmony_cistatic bool 294a46c0ec8Sopenharmony_cifallback_flush_mt_up(struct fallback_dispatch *dispatch, 295a46c0ec8Sopenharmony_ci struct evdev_device *device, 296a46c0ec8Sopenharmony_ci int slot_idx, 297a46c0ec8Sopenharmony_ci uint64_t time) 298a46c0ec8Sopenharmony_ci{ 299a46c0ec8Sopenharmony_ci struct libinput_device *base = &device->base; 300a46c0ec8Sopenharmony_ci struct libinput_seat *seat = base->seat; 301a46c0ec8Sopenharmony_ci struct mt_slot *slot; 302a46c0ec8Sopenharmony_ci int seat_slot; 303a46c0ec8Sopenharmony_ci 304a46c0ec8Sopenharmony_ci if (!(device->seat_caps & EVDEV_DEVICE_TOUCH)) 305a46c0ec8Sopenharmony_ci return false; 306a46c0ec8Sopenharmony_ci 307a46c0ec8Sopenharmony_ci slot = &dispatch->mt.slots[slot_idx]; 308a46c0ec8Sopenharmony_ci seat_slot = slot->seat_slot; 309a46c0ec8Sopenharmony_ci slot->seat_slot = -1; 310a46c0ec8Sopenharmony_ci 311a46c0ec8Sopenharmony_ci if (seat_slot == -1) 312a46c0ec8Sopenharmony_ci return false; 313a46c0ec8Sopenharmony_ci 314a46c0ec8Sopenharmony_ci seat->slot_map &= ~bit(seat_slot); 315a46c0ec8Sopenharmony_ci 316a46c0ec8Sopenharmony_ci touch_notify_touch_up(base, time, slot_idx, seat_slot); 317a46c0ec8Sopenharmony_ci 318a46c0ec8Sopenharmony_ci return true; 319a46c0ec8Sopenharmony_ci} 320a46c0ec8Sopenharmony_ci 321a46c0ec8Sopenharmony_cistatic bool 322a46c0ec8Sopenharmony_cifallback_flush_mt_cancel(struct fallback_dispatch *dispatch, 323a46c0ec8Sopenharmony_ci struct evdev_device *device, 324a46c0ec8Sopenharmony_ci int slot_idx, 325a46c0ec8Sopenharmony_ci uint64_t time) 326a46c0ec8Sopenharmony_ci{ 327a46c0ec8Sopenharmony_ci struct libinput_device *base = &device->base; 328a46c0ec8Sopenharmony_ci struct libinput_seat *seat = base->seat; 329a46c0ec8Sopenharmony_ci struct mt_slot *slot; 330a46c0ec8Sopenharmony_ci int seat_slot; 331a46c0ec8Sopenharmony_ci 332a46c0ec8Sopenharmony_ci if (!(device->seat_caps & EVDEV_DEVICE_TOUCH)) 333a46c0ec8Sopenharmony_ci return false; 334a46c0ec8Sopenharmony_ci 335a46c0ec8Sopenharmony_ci slot = &dispatch->mt.slots[slot_idx]; 336a46c0ec8Sopenharmony_ci seat_slot = slot->seat_slot; 337a46c0ec8Sopenharmony_ci slot->seat_slot = -1; 338a46c0ec8Sopenharmony_ci 339a46c0ec8Sopenharmony_ci if (seat_slot == -1) 340a46c0ec8Sopenharmony_ci return false; 341a46c0ec8Sopenharmony_ci 342a46c0ec8Sopenharmony_ci seat->slot_map &= ~bit(seat_slot); 343a46c0ec8Sopenharmony_ci 344a46c0ec8Sopenharmony_ci touch_notify_touch_cancel(base, time, slot_idx, seat_slot); 345a46c0ec8Sopenharmony_ci 346a46c0ec8Sopenharmony_ci return true; 347a46c0ec8Sopenharmony_ci} 348a46c0ec8Sopenharmony_ci 349a46c0ec8Sopenharmony_cistatic bool 350a46c0ec8Sopenharmony_cifallback_flush_st_down(struct fallback_dispatch *dispatch, 351a46c0ec8Sopenharmony_ci struct evdev_device *device, 352a46c0ec8Sopenharmony_ci uint64_t time) 353a46c0ec8Sopenharmony_ci{ 354a46c0ec8Sopenharmony_ci struct libinput_device *base = &device->base; 355a46c0ec8Sopenharmony_ci struct libinput_seat *seat = base->seat; 356a46c0ec8Sopenharmony_ci struct device_coords point; 357a46c0ec8Sopenharmony_ci int seat_slot; 358a46c0ec8Sopenharmony_ci 359a46c0ec8Sopenharmony_ci if (!(device->seat_caps & EVDEV_DEVICE_TOUCH)) 360a46c0ec8Sopenharmony_ci return false; 361a46c0ec8Sopenharmony_ci 362a46c0ec8Sopenharmony_ci if (dispatch->abs.seat_slot != -1) { 363a46c0ec8Sopenharmony_ci evdev_log_bug_kernel(device, 364a46c0ec8Sopenharmony_ci "driver sent multiple touch down for the same slot"); 365a46c0ec8Sopenharmony_ci return false; 366a46c0ec8Sopenharmony_ci } 367a46c0ec8Sopenharmony_ci 368a46c0ec8Sopenharmony_ci seat_slot = ffs(~seat->slot_map) - 1; 369a46c0ec8Sopenharmony_ci dispatch->abs.seat_slot = seat_slot; 370a46c0ec8Sopenharmony_ci 371a46c0ec8Sopenharmony_ci if (seat_slot == -1) 372a46c0ec8Sopenharmony_ci return false; 373a46c0ec8Sopenharmony_ci 374a46c0ec8Sopenharmony_ci seat->slot_map |= bit(seat_slot); 375a46c0ec8Sopenharmony_ci 376a46c0ec8Sopenharmony_ci point = dispatch->abs.point; 377a46c0ec8Sopenharmony_ci evdev_transform_absolute(device, &point); 378a46c0ec8Sopenharmony_ci 379a46c0ec8Sopenharmony_ci touch_notify_touch_down(base, time, -1, seat_slot, &point); 380a46c0ec8Sopenharmony_ci 381a46c0ec8Sopenharmony_ci return true; 382a46c0ec8Sopenharmony_ci} 383a46c0ec8Sopenharmony_ci 384a46c0ec8Sopenharmony_cistatic bool 385a46c0ec8Sopenharmony_cifallback_flush_st_motion(struct fallback_dispatch *dispatch, 386a46c0ec8Sopenharmony_ci struct evdev_device *device, 387a46c0ec8Sopenharmony_ci uint64_t time) 388a46c0ec8Sopenharmony_ci{ 389a46c0ec8Sopenharmony_ci struct libinput_device *base = &device->base; 390a46c0ec8Sopenharmony_ci struct device_coords point; 391a46c0ec8Sopenharmony_ci int seat_slot; 392a46c0ec8Sopenharmony_ci 393a46c0ec8Sopenharmony_ci point = dispatch->abs.point; 394a46c0ec8Sopenharmony_ci evdev_transform_absolute(device, &point); 395a46c0ec8Sopenharmony_ci 396a46c0ec8Sopenharmony_ci seat_slot = dispatch->abs.seat_slot; 397a46c0ec8Sopenharmony_ci 398a46c0ec8Sopenharmony_ci if (seat_slot == -1) 399a46c0ec8Sopenharmony_ci return false; 400a46c0ec8Sopenharmony_ci 401a46c0ec8Sopenharmony_ci touch_notify_touch_motion(base, time, -1, seat_slot, &point); 402a46c0ec8Sopenharmony_ci 403a46c0ec8Sopenharmony_ci return true; 404a46c0ec8Sopenharmony_ci} 405a46c0ec8Sopenharmony_ci 406a46c0ec8Sopenharmony_cistatic bool 407a46c0ec8Sopenharmony_cifallback_flush_st_up(struct fallback_dispatch *dispatch, 408a46c0ec8Sopenharmony_ci struct evdev_device *device, 409a46c0ec8Sopenharmony_ci uint64_t time) 410a46c0ec8Sopenharmony_ci{ 411a46c0ec8Sopenharmony_ci struct libinput_device *base = &device->base; 412a46c0ec8Sopenharmony_ci struct libinput_seat *seat = base->seat; 413a46c0ec8Sopenharmony_ci int seat_slot; 414a46c0ec8Sopenharmony_ci 415a46c0ec8Sopenharmony_ci if (!(device->seat_caps & EVDEV_DEVICE_TOUCH)) 416a46c0ec8Sopenharmony_ci return false; 417a46c0ec8Sopenharmony_ci 418a46c0ec8Sopenharmony_ci seat_slot = dispatch->abs.seat_slot; 419a46c0ec8Sopenharmony_ci dispatch->abs.seat_slot = -1; 420a46c0ec8Sopenharmony_ci 421a46c0ec8Sopenharmony_ci if (seat_slot == -1) 422a46c0ec8Sopenharmony_ci return false; 423a46c0ec8Sopenharmony_ci 424a46c0ec8Sopenharmony_ci seat->slot_map &= ~bit(seat_slot); 425a46c0ec8Sopenharmony_ci 426a46c0ec8Sopenharmony_ci touch_notify_touch_up(base, time, -1, seat_slot); 427a46c0ec8Sopenharmony_ci 428a46c0ec8Sopenharmony_ci return true; 429a46c0ec8Sopenharmony_ci} 430a46c0ec8Sopenharmony_ci 431a46c0ec8Sopenharmony_cistatic bool 432a46c0ec8Sopenharmony_cifallback_flush_st_cancel(struct fallback_dispatch *dispatch, 433a46c0ec8Sopenharmony_ci struct evdev_device *device, 434a46c0ec8Sopenharmony_ci uint64_t time) 435a46c0ec8Sopenharmony_ci{ 436a46c0ec8Sopenharmony_ci struct libinput_device *base = &device->base; 437a46c0ec8Sopenharmony_ci struct libinput_seat *seat = base->seat; 438a46c0ec8Sopenharmony_ci int seat_slot; 439a46c0ec8Sopenharmony_ci 440a46c0ec8Sopenharmony_ci if (!(device->seat_caps & EVDEV_DEVICE_TOUCH)) 441a46c0ec8Sopenharmony_ci return false; 442a46c0ec8Sopenharmony_ci 443a46c0ec8Sopenharmony_ci seat_slot = dispatch->abs.seat_slot; 444a46c0ec8Sopenharmony_ci dispatch->abs.seat_slot = -1; 445a46c0ec8Sopenharmony_ci 446a46c0ec8Sopenharmony_ci if (seat_slot == -1) 447a46c0ec8Sopenharmony_ci return false; 448a46c0ec8Sopenharmony_ci 449a46c0ec8Sopenharmony_ci seat->slot_map &= ~bit(seat_slot); 450a46c0ec8Sopenharmony_ci 451a46c0ec8Sopenharmony_ci touch_notify_touch_cancel(base, time, -1, seat_slot); 452a46c0ec8Sopenharmony_ci 453a46c0ec8Sopenharmony_ci return true; 454a46c0ec8Sopenharmony_ci} 455a46c0ec8Sopenharmony_ci 456a46c0ec8Sopenharmony_cistatic void 457a46c0ec8Sopenharmony_cifallback_process_touch_button(struct fallback_dispatch *dispatch, 458a46c0ec8Sopenharmony_ci struct evdev_device *device, 459a46c0ec8Sopenharmony_ci uint64_t time, int value) 460a46c0ec8Sopenharmony_ci{ 461a46c0ec8Sopenharmony_ci dispatch->pending_event |= (value) ? 462a46c0ec8Sopenharmony_ci EVDEV_ABSOLUTE_TOUCH_DOWN : 463a46c0ec8Sopenharmony_ci EVDEV_ABSOLUTE_TOUCH_UP; 464a46c0ec8Sopenharmony_ci} 465a46c0ec8Sopenharmony_ci 466a46c0ec8Sopenharmony_cistatic inline void 467a46c0ec8Sopenharmony_cifallback_process_key(struct fallback_dispatch *dispatch, 468a46c0ec8Sopenharmony_ci struct evdev_device *device, 469a46c0ec8Sopenharmony_ci struct input_event *e, uint64_t time) 470a46c0ec8Sopenharmony_ci{ 471a46c0ec8Sopenharmony_ci enum key_type type; 472a46c0ec8Sopenharmony_ci 473a46c0ec8Sopenharmony_ci /* ignore kernel key repeat */ 474a46c0ec8Sopenharmony_ci if (e->value == 2) 475a46c0ec8Sopenharmony_ci return; 476a46c0ec8Sopenharmony_ci 477a46c0ec8Sopenharmony_ci if (e->code == BTN_TOUCH) { 478a46c0ec8Sopenharmony_ci if (!device->is_mt) 479a46c0ec8Sopenharmony_ci fallback_process_touch_button(dispatch, 480a46c0ec8Sopenharmony_ci device, 481a46c0ec8Sopenharmony_ci time, 482a46c0ec8Sopenharmony_ci e->value); 483a46c0ec8Sopenharmony_ci return; 484a46c0ec8Sopenharmony_ci } 485a46c0ec8Sopenharmony_ci 486a46c0ec8Sopenharmony_ci type = get_key_type(e->code); 487a46c0ec8Sopenharmony_ci 488a46c0ec8Sopenharmony_ci /* Ignore key release events from the kernel for keys that libinput 489a46c0ec8Sopenharmony_ci * never got a pressed event for or key presses for keys that we 490a46c0ec8Sopenharmony_ci * think are still down */ 491a46c0ec8Sopenharmony_ci switch (type) { 492a46c0ec8Sopenharmony_ci case KEY_TYPE_NONE: 493a46c0ec8Sopenharmony_ci break; 494a46c0ec8Sopenharmony_ci case KEY_TYPE_KEY: 495a46c0ec8Sopenharmony_ci case KEY_TYPE_BUTTON: 496a46c0ec8Sopenharmony_ci if ((e->value && hw_is_key_down(dispatch, e->code)) || 497a46c0ec8Sopenharmony_ci (e->value == 0 && !hw_is_key_down(dispatch, e->code))) 498a46c0ec8Sopenharmony_ci return; 499a46c0ec8Sopenharmony_ci 500a46c0ec8Sopenharmony_ci dispatch->pending_event |= EVDEV_KEY; 501a46c0ec8Sopenharmony_ci break; 502a46c0ec8Sopenharmony_ci } 503a46c0ec8Sopenharmony_ci 504a46c0ec8Sopenharmony_ci hw_set_key_down(dispatch, e->code, e->value); 505a46c0ec8Sopenharmony_ci 506a46c0ec8Sopenharmony_ci switch (type) { 507a46c0ec8Sopenharmony_ci case KEY_TYPE_NONE: 508a46c0ec8Sopenharmony_ci break; 509a46c0ec8Sopenharmony_ci case KEY_TYPE_KEY: 510a46c0ec8Sopenharmony_ci fallback_keyboard_notify_key( 511a46c0ec8Sopenharmony_ci dispatch, 512a46c0ec8Sopenharmony_ci device, 513a46c0ec8Sopenharmony_ci time, 514a46c0ec8Sopenharmony_ci e->code, 515a46c0ec8Sopenharmony_ci e->value ? LIBINPUT_KEY_STATE_PRESSED : 516a46c0ec8Sopenharmony_ci LIBINPUT_KEY_STATE_RELEASED); 517a46c0ec8Sopenharmony_ci break; 518a46c0ec8Sopenharmony_ci case KEY_TYPE_BUTTON: 519a46c0ec8Sopenharmony_ci break; 520a46c0ec8Sopenharmony_ci } 521a46c0ec8Sopenharmony_ci} 522a46c0ec8Sopenharmony_ci 523a46c0ec8Sopenharmony_cistatic void 524a46c0ec8Sopenharmony_cifallback_process_touch(struct fallback_dispatch *dispatch, 525a46c0ec8Sopenharmony_ci struct evdev_device *device, 526a46c0ec8Sopenharmony_ci struct input_event *e, 527a46c0ec8Sopenharmony_ci uint64_t time) 528a46c0ec8Sopenharmony_ci{ 529a46c0ec8Sopenharmony_ci struct mt_slot *slot = &dispatch->mt.slots[dispatch->mt.slot]; 530a46c0ec8Sopenharmony_ci 531a46c0ec8Sopenharmony_ci if (e->code == ABS_MT_SLOT) { 532a46c0ec8Sopenharmony_ci if ((size_t)e->value >= dispatch->mt.slots_len) { 533a46c0ec8Sopenharmony_ci evdev_log_bug_libinput(device, 534a46c0ec8Sopenharmony_ci "exceeded slot count (%d of max %zd)\n", 535a46c0ec8Sopenharmony_ci e->value, 536a46c0ec8Sopenharmony_ci dispatch->mt.slots_len); 537a46c0ec8Sopenharmony_ci e->value = dispatch->mt.slots_len - 1; 538a46c0ec8Sopenharmony_ci } 539a46c0ec8Sopenharmony_ci dispatch->mt.slot = e->value; 540a46c0ec8Sopenharmony_ci return; 541a46c0ec8Sopenharmony_ci } 542a46c0ec8Sopenharmony_ci 543a46c0ec8Sopenharmony_ci switch (e->code) { 544a46c0ec8Sopenharmony_ci case ABS_MT_TRACKING_ID: 545a46c0ec8Sopenharmony_ci if (e->value >= 0) { 546a46c0ec8Sopenharmony_ci dispatch->pending_event |= EVDEV_ABSOLUTE_MT; 547a46c0ec8Sopenharmony_ci slot->state = SLOT_STATE_BEGIN; 548a46c0ec8Sopenharmony_ci if (dispatch->mt.has_palm) { 549a46c0ec8Sopenharmony_ci int v; 550a46c0ec8Sopenharmony_ci v = libevdev_get_slot_value(device->evdev, 551a46c0ec8Sopenharmony_ci dispatch->mt.slot, 552a46c0ec8Sopenharmony_ci ABS_MT_TOOL_TYPE); 553a46c0ec8Sopenharmony_ci switch (v) { 554a46c0ec8Sopenharmony_ci case MT_TOOL_PALM: 555a46c0ec8Sopenharmony_ci /* new touch, no cancel needed */ 556a46c0ec8Sopenharmony_ci slot->palm_state = PALM_WAS_PALM; 557a46c0ec8Sopenharmony_ci break; 558a46c0ec8Sopenharmony_ci default: 559a46c0ec8Sopenharmony_ci slot->palm_state = PALM_NONE; 560a46c0ec8Sopenharmony_ci break; 561a46c0ec8Sopenharmony_ci } 562a46c0ec8Sopenharmony_ci } else { 563a46c0ec8Sopenharmony_ci slot->palm_state = PALM_NONE; 564a46c0ec8Sopenharmony_ci } 565a46c0ec8Sopenharmony_ci } else { 566a46c0ec8Sopenharmony_ci dispatch->pending_event |= EVDEV_ABSOLUTE_MT; 567a46c0ec8Sopenharmony_ci slot->state = SLOT_STATE_END; 568a46c0ec8Sopenharmony_ci } 569a46c0ec8Sopenharmony_ci slot->dirty = true; 570a46c0ec8Sopenharmony_ci break; 571a46c0ec8Sopenharmony_ci case ABS_MT_POSITION_X: 572a46c0ec8Sopenharmony_ci evdev_device_check_abs_axis_range(device, e->code, e->value); 573a46c0ec8Sopenharmony_ci dispatch->mt.slots[dispatch->mt.slot].point.x = e->value; 574a46c0ec8Sopenharmony_ci dispatch->pending_event |= EVDEV_ABSOLUTE_MT; 575a46c0ec8Sopenharmony_ci slot->dirty = true; 576a46c0ec8Sopenharmony_ci break; 577a46c0ec8Sopenharmony_ci case ABS_MT_POSITION_Y: 578a46c0ec8Sopenharmony_ci evdev_device_check_abs_axis_range(device, e->code, e->value); 579a46c0ec8Sopenharmony_ci dispatch->mt.slots[dispatch->mt.slot].point.y = e->value; 580a46c0ec8Sopenharmony_ci dispatch->pending_event |= EVDEV_ABSOLUTE_MT; 581a46c0ec8Sopenharmony_ci slot->dirty = true; 582a46c0ec8Sopenharmony_ci break; 583a46c0ec8Sopenharmony_ci case ABS_MT_TOOL_TYPE: 584a46c0ec8Sopenharmony_ci /* The transitions matter - we (may) need to send a touch 585a46c0ec8Sopenharmony_ci * cancel event if we just switched to a palm touch. And the 586a46c0ec8Sopenharmony_ci * kernel may switch back to finger but we keep the touch as 587a46c0ec8Sopenharmony_ci * palm - but then we need to reset correctly on a new touch 588a46c0ec8Sopenharmony_ci * sequence. 589a46c0ec8Sopenharmony_ci */ 590a46c0ec8Sopenharmony_ci switch (e->value) { 591a46c0ec8Sopenharmony_ci case MT_TOOL_PALM: 592a46c0ec8Sopenharmony_ci if (slot->palm_state == PALM_NONE) 593a46c0ec8Sopenharmony_ci slot->palm_state = PALM_NEW; 594a46c0ec8Sopenharmony_ci break; 595a46c0ec8Sopenharmony_ci default: 596a46c0ec8Sopenharmony_ci if (slot->palm_state == PALM_IS_PALM) 597a46c0ec8Sopenharmony_ci slot->palm_state = PALM_WAS_PALM; 598a46c0ec8Sopenharmony_ci break; 599a46c0ec8Sopenharmony_ci } 600a46c0ec8Sopenharmony_ci dispatch->pending_event |= EVDEV_ABSOLUTE_MT; 601a46c0ec8Sopenharmony_ci slot->dirty = true; 602a46c0ec8Sopenharmony_ci break; 603a46c0ec8Sopenharmony_ci } 604a46c0ec8Sopenharmony_ci} 605a46c0ec8Sopenharmony_ci 606a46c0ec8Sopenharmony_cistatic inline void 607a46c0ec8Sopenharmony_cifallback_process_absolute_motion(struct fallback_dispatch *dispatch, 608a46c0ec8Sopenharmony_ci struct evdev_device *device, 609a46c0ec8Sopenharmony_ci struct input_event *e) 610a46c0ec8Sopenharmony_ci{ 611a46c0ec8Sopenharmony_ci switch (e->code) { 612a46c0ec8Sopenharmony_ci case ABS_X: 613a46c0ec8Sopenharmony_ci evdev_device_check_abs_axis_range(device, e->code, e->value); 614a46c0ec8Sopenharmony_ci dispatch->abs.point.x = e->value; 615a46c0ec8Sopenharmony_ci dispatch->pending_event |= EVDEV_ABSOLUTE_MOTION; 616a46c0ec8Sopenharmony_ci break; 617a46c0ec8Sopenharmony_ci case ABS_Y: 618a46c0ec8Sopenharmony_ci evdev_device_check_abs_axis_range(device, e->code, e->value); 619a46c0ec8Sopenharmony_ci dispatch->abs.point.y = e->value; 620a46c0ec8Sopenharmony_ci dispatch->pending_event |= EVDEV_ABSOLUTE_MOTION; 621a46c0ec8Sopenharmony_ci break; 622a46c0ec8Sopenharmony_ci } 623a46c0ec8Sopenharmony_ci} 624a46c0ec8Sopenharmony_ci 625a46c0ec8Sopenharmony_cistatic void 626a46c0ec8Sopenharmony_cifallback_lid_keyboard_event(uint64_t time, 627a46c0ec8Sopenharmony_ci struct libinput_event *event, 628a46c0ec8Sopenharmony_ci void *data) 629a46c0ec8Sopenharmony_ci{ 630a46c0ec8Sopenharmony_ci struct fallback_dispatch *dispatch = fallback_dispatch(data); 631a46c0ec8Sopenharmony_ci 632a46c0ec8Sopenharmony_ci if (!dispatch->lid.is_closed) 633a46c0ec8Sopenharmony_ci return; 634a46c0ec8Sopenharmony_ci 635a46c0ec8Sopenharmony_ci if (event->type != LIBINPUT_EVENT_KEYBOARD_KEY) 636a46c0ec8Sopenharmony_ci return; 637a46c0ec8Sopenharmony_ci 638a46c0ec8Sopenharmony_ci if (dispatch->lid.reliability == RELIABILITY_WRITE_OPEN) { 639a46c0ec8Sopenharmony_ci int fd = libevdev_get_fd(dispatch->device->evdev); 640a46c0ec8Sopenharmony_ci int rc; 641a46c0ec8Sopenharmony_ci struct input_event ev[2]; 642a46c0ec8Sopenharmony_ci 643a46c0ec8Sopenharmony_ci ev[0] = input_event_init(0, EV_SW, SW_LID, 0); 644a46c0ec8Sopenharmony_ci ev[1] = input_event_init(0, EV_SYN, SYN_REPORT, 0); 645a46c0ec8Sopenharmony_ci 646a46c0ec8Sopenharmony_ci rc = write(fd, ev, sizeof(ev)); 647a46c0ec8Sopenharmony_ci 648a46c0ec8Sopenharmony_ci if (rc < 0) 649a46c0ec8Sopenharmony_ci evdev_log_error(dispatch->device, 650a46c0ec8Sopenharmony_ci "failed to write SW_LID state (%s)", 651a46c0ec8Sopenharmony_ci strerror(errno)); 652a46c0ec8Sopenharmony_ci 653a46c0ec8Sopenharmony_ci /* In case write() fails, we sync the lid state manually 654a46c0ec8Sopenharmony_ci * regardless. */ 655a46c0ec8Sopenharmony_ci } 656a46c0ec8Sopenharmony_ci 657a46c0ec8Sopenharmony_ci /* Posting the event here means we preempt the keyboard events that 658a46c0ec8Sopenharmony_ci * caused us to wake up, so the lid event is always passed on before 659a46c0ec8Sopenharmony_ci * the key event. 660a46c0ec8Sopenharmony_ci */ 661a46c0ec8Sopenharmony_ci dispatch->lid.is_closed = false; 662a46c0ec8Sopenharmony_ci fallback_lid_notify_toggle(dispatch, dispatch->device, time); 663a46c0ec8Sopenharmony_ci} 664a46c0ec8Sopenharmony_ci 665a46c0ec8Sopenharmony_cistatic void 666a46c0ec8Sopenharmony_cifallback_lid_toggle_keyboard_listener(struct fallback_dispatch *dispatch, 667a46c0ec8Sopenharmony_ci struct evdev_paired_keyboard *kbd, 668a46c0ec8Sopenharmony_ci bool is_closed) 669a46c0ec8Sopenharmony_ci{ 670a46c0ec8Sopenharmony_ci assert(kbd->device); 671a46c0ec8Sopenharmony_ci 672a46c0ec8Sopenharmony_ci libinput_device_remove_event_listener(&kbd->listener); 673a46c0ec8Sopenharmony_ci 674a46c0ec8Sopenharmony_ci if (is_closed) { 675a46c0ec8Sopenharmony_ci libinput_device_add_event_listener( 676a46c0ec8Sopenharmony_ci &kbd->device->base, 677a46c0ec8Sopenharmony_ci &kbd->listener, 678a46c0ec8Sopenharmony_ci fallback_lid_keyboard_event, 679a46c0ec8Sopenharmony_ci dispatch); 680a46c0ec8Sopenharmony_ci } else { 681a46c0ec8Sopenharmony_ci libinput_device_init_event_listener(&kbd->listener); 682a46c0ec8Sopenharmony_ci } 683a46c0ec8Sopenharmony_ci} 684a46c0ec8Sopenharmony_ci 685a46c0ec8Sopenharmony_cistatic void 686a46c0ec8Sopenharmony_cifallback_lid_toggle_keyboard_listeners(struct fallback_dispatch *dispatch, 687a46c0ec8Sopenharmony_ci bool is_closed) 688a46c0ec8Sopenharmony_ci{ 689a46c0ec8Sopenharmony_ci struct evdev_paired_keyboard *kbd; 690a46c0ec8Sopenharmony_ci 691a46c0ec8Sopenharmony_ci list_for_each(kbd, &dispatch->lid.paired_keyboard_list, link) { 692a46c0ec8Sopenharmony_ci if (!kbd->device) 693a46c0ec8Sopenharmony_ci continue; 694a46c0ec8Sopenharmony_ci 695a46c0ec8Sopenharmony_ci fallback_lid_toggle_keyboard_listener(dispatch, 696a46c0ec8Sopenharmony_ci kbd, 697a46c0ec8Sopenharmony_ci is_closed); 698a46c0ec8Sopenharmony_ci } 699a46c0ec8Sopenharmony_ci} 700a46c0ec8Sopenharmony_ci 701a46c0ec8Sopenharmony_cistatic inline void 702a46c0ec8Sopenharmony_cifallback_process_switch(struct fallback_dispatch *dispatch, 703a46c0ec8Sopenharmony_ci struct evdev_device *device, 704a46c0ec8Sopenharmony_ci struct input_event *e, 705a46c0ec8Sopenharmony_ci uint64_t time) 706a46c0ec8Sopenharmony_ci{ 707a46c0ec8Sopenharmony_ci enum libinput_switch_state state; 708a46c0ec8Sopenharmony_ci bool is_closed; 709a46c0ec8Sopenharmony_ci 710a46c0ec8Sopenharmony_ci /* TODO: this should to move to handle_state */ 711a46c0ec8Sopenharmony_ci 712a46c0ec8Sopenharmony_ci switch (e->code) { 713a46c0ec8Sopenharmony_ci case SW_LID: 714a46c0ec8Sopenharmony_ci is_closed = !!e->value; 715a46c0ec8Sopenharmony_ci 716a46c0ec8Sopenharmony_ci fallback_lid_toggle_keyboard_listeners(dispatch, is_closed); 717a46c0ec8Sopenharmony_ci 718a46c0ec8Sopenharmony_ci if (dispatch->lid.is_closed == is_closed) 719a46c0ec8Sopenharmony_ci return; 720a46c0ec8Sopenharmony_ci 721a46c0ec8Sopenharmony_ci dispatch->lid.is_closed = is_closed; 722a46c0ec8Sopenharmony_ci fallback_lid_notify_toggle(dispatch, device, time); 723a46c0ec8Sopenharmony_ci break; 724a46c0ec8Sopenharmony_ci case SW_TABLET_MODE: 725a46c0ec8Sopenharmony_ci if (dispatch->tablet_mode.sw.state == e->value) 726a46c0ec8Sopenharmony_ci return; 727a46c0ec8Sopenharmony_ci 728a46c0ec8Sopenharmony_ci dispatch->tablet_mode.sw.state = e->value; 729a46c0ec8Sopenharmony_ci if (e->value) 730a46c0ec8Sopenharmony_ci state = LIBINPUT_SWITCH_STATE_ON; 731a46c0ec8Sopenharmony_ci else 732a46c0ec8Sopenharmony_ci state = LIBINPUT_SWITCH_STATE_OFF; 733a46c0ec8Sopenharmony_ci switch_notify_toggle(&device->base, 734a46c0ec8Sopenharmony_ci time, 735a46c0ec8Sopenharmony_ci LIBINPUT_SWITCH_TABLET_MODE, 736a46c0ec8Sopenharmony_ci state); 737a46c0ec8Sopenharmony_ci break; 738a46c0ec8Sopenharmony_ci } 739a46c0ec8Sopenharmony_ci} 740a46c0ec8Sopenharmony_ci 741a46c0ec8Sopenharmony_cistatic inline bool 742a46c0ec8Sopenharmony_cifallback_reject_relative(struct evdev_device *device, 743a46c0ec8Sopenharmony_ci const struct input_event *e, 744a46c0ec8Sopenharmony_ci uint64_t time) 745a46c0ec8Sopenharmony_ci{ 746a46c0ec8Sopenharmony_ci if ((e->code == REL_X || e->code == REL_Y) && 747a46c0ec8Sopenharmony_ci (device->seat_caps & EVDEV_DEVICE_POINTER) == 0) { 748a46c0ec8Sopenharmony_ci evdev_log_bug_libinput_ratelimit(device, 749a46c0ec8Sopenharmony_ci &device->nonpointer_rel_limit, 750a46c0ec8Sopenharmony_ci "REL_X/Y from a non-pointer device\n"); 751a46c0ec8Sopenharmony_ci return true; 752a46c0ec8Sopenharmony_ci } 753a46c0ec8Sopenharmony_ci 754a46c0ec8Sopenharmony_ci return false; 755a46c0ec8Sopenharmony_ci} 756a46c0ec8Sopenharmony_ci 757a46c0ec8Sopenharmony_cistatic inline void 758a46c0ec8Sopenharmony_cifallback_process_relative(struct fallback_dispatch *dispatch, 759a46c0ec8Sopenharmony_ci struct evdev_device *device, 760a46c0ec8Sopenharmony_ci struct input_event *e, uint64_t time) 761a46c0ec8Sopenharmony_ci{ 762a46c0ec8Sopenharmony_ci if (fallback_reject_relative(device, e, time)) 763a46c0ec8Sopenharmony_ci return; 764a46c0ec8Sopenharmony_ci 765a46c0ec8Sopenharmony_ci switch (e->code) { 766a46c0ec8Sopenharmony_ci case REL_X: 767a46c0ec8Sopenharmony_ci dispatch->rel.x += e->value; 768a46c0ec8Sopenharmony_ci dispatch->pending_event |= EVDEV_RELATIVE_MOTION; 769a46c0ec8Sopenharmony_ci break; 770a46c0ec8Sopenharmony_ci case REL_Y: 771a46c0ec8Sopenharmony_ci dispatch->rel.y += e->value; 772a46c0ec8Sopenharmony_ci dispatch->pending_event |= EVDEV_RELATIVE_MOTION; 773a46c0ec8Sopenharmony_ci break; 774a46c0ec8Sopenharmony_ci } 775a46c0ec8Sopenharmony_ci 776a46c0ec8Sopenharmony_ci fallback_wheel_process_relative(dispatch, device, e, time); 777a46c0ec8Sopenharmony_ci} 778a46c0ec8Sopenharmony_ci 779a46c0ec8Sopenharmony_cistatic inline void 780a46c0ec8Sopenharmony_cifallback_process_absolute(struct fallback_dispatch *dispatch, 781a46c0ec8Sopenharmony_ci struct evdev_device *device, 782a46c0ec8Sopenharmony_ci struct input_event *e, 783a46c0ec8Sopenharmony_ci uint64_t time) 784a46c0ec8Sopenharmony_ci{ 785a46c0ec8Sopenharmony_ci if (device->is_mt) { 786a46c0ec8Sopenharmony_ci fallback_process_touch(dispatch, device, e, time); 787a46c0ec8Sopenharmony_ci } else { 788a46c0ec8Sopenharmony_ci fallback_process_absolute_motion(dispatch, device, e); 789a46c0ec8Sopenharmony_ci } 790a46c0ec8Sopenharmony_ci} 791a46c0ec8Sopenharmony_ci 792a46c0ec8Sopenharmony_cistatic inline bool 793a46c0ec8Sopenharmony_cifallback_any_button_down(struct fallback_dispatch *dispatch, 794a46c0ec8Sopenharmony_ci struct evdev_device *device) 795a46c0ec8Sopenharmony_ci{ 796a46c0ec8Sopenharmony_ci unsigned int button; 797a46c0ec8Sopenharmony_ci 798a46c0ec8Sopenharmony_ci for (button = BTN_LEFT; button < BTN_JOYSTICK; button++) { 799a46c0ec8Sopenharmony_ci if (libevdev_has_event_code(device->evdev, EV_KEY, button) && 800a46c0ec8Sopenharmony_ci hw_is_key_down(dispatch, button)) 801a46c0ec8Sopenharmony_ci return true; 802a46c0ec8Sopenharmony_ci } 803a46c0ec8Sopenharmony_ci return false; 804a46c0ec8Sopenharmony_ci} 805a46c0ec8Sopenharmony_ci 806a46c0ec8Sopenharmony_cistatic inline bool 807a46c0ec8Sopenharmony_cifallback_arbitrate_touch(struct fallback_dispatch *dispatch, 808a46c0ec8Sopenharmony_ci struct mt_slot *slot) 809a46c0ec8Sopenharmony_ci{ 810a46c0ec8Sopenharmony_ci bool discard = false; 811a46c0ec8Sopenharmony_ci struct device_coords point = slot->point; 812a46c0ec8Sopenharmony_ci evdev_transform_absolute(dispatch->device, &point); 813a46c0ec8Sopenharmony_ci 814a46c0ec8Sopenharmony_ci if (dispatch->arbitration.state == ARBITRATION_IGNORE_RECT && 815a46c0ec8Sopenharmony_ci point_in_rect(&point, &dispatch->arbitration.rect)) { 816a46c0ec8Sopenharmony_ci slot->palm_state = PALM_IS_PALM; 817a46c0ec8Sopenharmony_ci discard = true; 818a46c0ec8Sopenharmony_ci } 819a46c0ec8Sopenharmony_ci 820a46c0ec8Sopenharmony_ci return discard; 821a46c0ec8Sopenharmony_ci} 822a46c0ec8Sopenharmony_ci 823a46c0ec8Sopenharmony_cistatic inline bool 824a46c0ec8Sopenharmony_cifallback_flush_mt_events(struct fallback_dispatch *dispatch, 825a46c0ec8Sopenharmony_ci struct evdev_device *device, 826a46c0ec8Sopenharmony_ci uint64_t time) 827a46c0ec8Sopenharmony_ci{ 828a46c0ec8Sopenharmony_ci bool sent = false; 829a46c0ec8Sopenharmony_ci 830a46c0ec8Sopenharmony_ci for (size_t i = 0; i < dispatch->mt.slots_len; i++) { 831a46c0ec8Sopenharmony_ci struct mt_slot *slot = &dispatch->mt.slots[i]; 832a46c0ec8Sopenharmony_ci 833a46c0ec8Sopenharmony_ci if (!slot->dirty) 834a46c0ec8Sopenharmony_ci continue; 835a46c0ec8Sopenharmony_ci 836a46c0ec8Sopenharmony_ci slot->dirty = false; 837a46c0ec8Sopenharmony_ci 838a46c0ec8Sopenharmony_ci /* Any palm state other than PALM_NEW means we've either 839a46c0ec8Sopenharmony_ci * already cancelled the touch or the touch was never 840a46c0ec8Sopenharmony_ci * a finger anyway and we didn't send the begin. 841a46c0ec8Sopenharmony_ci */ 842a46c0ec8Sopenharmony_ci if (slot->palm_state == PALM_NEW) { 843a46c0ec8Sopenharmony_ci if (slot->state != SLOT_STATE_BEGIN) 844a46c0ec8Sopenharmony_ci sent = fallback_flush_mt_cancel(dispatch, 845a46c0ec8Sopenharmony_ci device, 846a46c0ec8Sopenharmony_ci i, 847a46c0ec8Sopenharmony_ci time); 848a46c0ec8Sopenharmony_ci slot->palm_state = PALM_IS_PALM; 849a46c0ec8Sopenharmony_ci } else if (slot->palm_state == PALM_NONE) { 850a46c0ec8Sopenharmony_ci switch (slot->state) { 851a46c0ec8Sopenharmony_ci case SLOT_STATE_BEGIN: 852a46c0ec8Sopenharmony_ci if (!fallback_arbitrate_touch(dispatch, 853a46c0ec8Sopenharmony_ci slot)) { 854a46c0ec8Sopenharmony_ci sent = fallback_flush_mt_down(dispatch, 855a46c0ec8Sopenharmony_ci device, 856a46c0ec8Sopenharmony_ci i, 857a46c0ec8Sopenharmony_ci time); 858a46c0ec8Sopenharmony_ci } 859a46c0ec8Sopenharmony_ci break; 860a46c0ec8Sopenharmony_ci case SLOT_STATE_UPDATE: 861a46c0ec8Sopenharmony_ci sent = fallback_flush_mt_motion(dispatch, 862a46c0ec8Sopenharmony_ci device, 863a46c0ec8Sopenharmony_ci i, 864a46c0ec8Sopenharmony_ci time); 865a46c0ec8Sopenharmony_ci break; 866a46c0ec8Sopenharmony_ci case SLOT_STATE_END: 867a46c0ec8Sopenharmony_ci sent = fallback_flush_mt_up(dispatch, 868a46c0ec8Sopenharmony_ci device, 869a46c0ec8Sopenharmony_ci i, 870a46c0ec8Sopenharmony_ci time); 871a46c0ec8Sopenharmony_ci break; 872a46c0ec8Sopenharmony_ci case SLOT_STATE_NONE: 873a46c0ec8Sopenharmony_ci break; 874a46c0ec8Sopenharmony_ci } 875a46c0ec8Sopenharmony_ci } 876a46c0ec8Sopenharmony_ci 877a46c0ec8Sopenharmony_ci /* State machine continues independent of the palm state */ 878a46c0ec8Sopenharmony_ci switch (slot->state) { 879a46c0ec8Sopenharmony_ci case SLOT_STATE_BEGIN: 880a46c0ec8Sopenharmony_ci slot->state = SLOT_STATE_UPDATE; 881a46c0ec8Sopenharmony_ci break; 882a46c0ec8Sopenharmony_ci case SLOT_STATE_UPDATE: 883a46c0ec8Sopenharmony_ci break; 884a46c0ec8Sopenharmony_ci case SLOT_STATE_END: 885a46c0ec8Sopenharmony_ci slot->state = SLOT_STATE_NONE; 886a46c0ec8Sopenharmony_ci break; 887a46c0ec8Sopenharmony_ci case SLOT_STATE_NONE: 888a46c0ec8Sopenharmony_ci /* touch arbitration may swallow the begin, 889a46c0ec8Sopenharmony_ci * so we may get updates for a touch still 890a46c0ec8Sopenharmony_ci * in NONE state */ 891a46c0ec8Sopenharmony_ci break; 892a46c0ec8Sopenharmony_ci } 893a46c0ec8Sopenharmony_ci } 894a46c0ec8Sopenharmony_ci 895a46c0ec8Sopenharmony_ci return sent; 896a46c0ec8Sopenharmony_ci} 897a46c0ec8Sopenharmony_ci 898a46c0ec8Sopenharmony_cistatic void 899a46c0ec8Sopenharmony_cifallback_handle_state(struct fallback_dispatch *dispatch, 900a46c0ec8Sopenharmony_ci struct evdev_device *device, 901a46c0ec8Sopenharmony_ci uint64_t time) 902a46c0ec8Sopenharmony_ci{ 903a46c0ec8Sopenharmony_ci bool need_touch_frame = false; 904a46c0ec8Sopenharmony_ci 905a46c0ec8Sopenharmony_ci /* Relative motion */ 906a46c0ec8Sopenharmony_ci if (dispatch->pending_event & EVDEV_RELATIVE_MOTION) 907a46c0ec8Sopenharmony_ci fallback_flush_relative_motion(dispatch, device, time); 908a46c0ec8Sopenharmony_ci 909a46c0ec8Sopenharmony_ci /* Single touch or absolute pointer devices */ 910a46c0ec8Sopenharmony_ci if (dispatch->pending_event & EVDEV_ABSOLUTE_TOUCH_DOWN) { 911a46c0ec8Sopenharmony_ci if (fallback_flush_st_down(dispatch, device, time)) 912a46c0ec8Sopenharmony_ci need_touch_frame = true; 913a46c0ec8Sopenharmony_ci } else if (dispatch->pending_event & EVDEV_ABSOLUTE_MOTION) { 914a46c0ec8Sopenharmony_ci if (device->seat_caps & EVDEV_DEVICE_TOUCH) { 915a46c0ec8Sopenharmony_ci if (fallback_flush_st_motion(dispatch, 916a46c0ec8Sopenharmony_ci device, 917a46c0ec8Sopenharmony_ci time)) 918a46c0ec8Sopenharmony_ci need_touch_frame = true; 919a46c0ec8Sopenharmony_ci } else if (device->seat_caps & EVDEV_DEVICE_POINTER) { 920a46c0ec8Sopenharmony_ci fallback_flush_absolute_motion(dispatch, 921a46c0ec8Sopenharmony_ci device, 922a46c0ec8Sopenharmony_ci time); 923a46c0ec8Sopenharmony_ci } 924a46c0ec8Sopenharmony_ci } 925a46c0ec8Sopenharmony_ci 926a46c0ec8Sopenharmony_ci if (dispatch->pending_event & EVDEV_ABSOLUTE_TOUCH_UP) { 927a46c0ec8Sopenharmony_ci if (fallback_flush_st_up(dispatch, device, time)) 928a46c0ec8Sopenharmony_ci need_touch_frame = true; 929a46c0ec8Sopenharmony_ci } 930a46c0ec8Sopenharmony_ci 931a46c0ec8Sopenharmony_ci /* Multitouch devices */ 932a46c0ec8Sopenharmony_ci if (dispatch->pending_event & EVDEV_ABSOLUTE_MT) 933a46c0ec8Sopenharmony_ci need_touch_frame = fallback_flush_mt_events(dispatch, 934a46c0ec8Sopenharmony_ci device, 935a46c0ec8Sopenharmony_ci time); 936a46c0ec8Sopenharmony_ci 937a46c0ec8Sopenharmony_ci if (need_touch_frame) 938a46c0ec8Sopenharmony_ci touch_notify_frame(&device->base, time); 939a46c0ec8Sopenharmony_ci 940a46c0ec8Sopenharmony_ci fallback_wheel_handle_state(dispatch, device, time); 941a46c0ec8Sopenharmony_ci 942a46c0ec8Sopenharmony_ci /* Buttons and keys */ 943a46c0ec8Sopenharmony_ci if (dispatch->pending_event & EVDEV_KEY) { 944a46c0ec8Sopenharmony_ci bool want_debounce = false; 945a46c0ec8Sopenharmony_ci for (unsigned int code = 0; code <= KEY_MAX; code++) { 946a46c0ec8Sopenharmony_ci if (!hw_key_has_changed(dispatch, code)) 947a46c0ec8Sopenharmony_ci continue; 948a46c0ec8Sopenharmony_ci 949a46c0ec8Sopenharmony_ci if (get_key_type(code) == KEY_TYPE_BUTTON) { 950a46c0ec8Sopenharmony_ci want_debounce = true; 951a46c0ec8Sopenharmony_ci break; 952a46c0ec8Sopenharmony_ci } 953a46c0ec8Sopenharmony_ci } 954a46c0ec8Sopenharmony_ci 955a46c0ec8Sopenharmony_ci if (want_debounce) 956a46c0ec8Sopenharmony_ci fallback_debounce_handle_state(dispatch, time); 957a46c0ec8Sopenharmony_ci 958a46c0ec8Sopenharmony_ci hw_key_update_last_state(dispatch); 959a46c0ec8Sopenharmony_ci } 960a46c0ec8Sopenharmony_ci 961a46c0ec8Sopenharmony_ci dispatch->pending_event = EVDEV_NONE; 962a46c0ec8Sopenharmony_ci} 963a46c0ec8Sopenharmony_ci 964a46c0ec8Sopenharmony_cistatic void 965a46c0ec8Sopenharmony_cifallback_interface_process(struct evdev_dispatch *evdev_dispatch, 966a46c0ec8Sopenharmony_ci struct evdev_device *device, 967a46c0ec8Sopenharmony_ci struct input_event *event, 968a46c0ec8Sopenharmony_ci uint64_t time) 969a46c0ec8Sopenharmony_ci{ 970a46c0ec8Sopenharmony_ci struct fallback_dispatch *dispatch = fallback_dispatch(evdev_dispatch); 971a46c0ec8Sopenharmony_ci static bool warned = false; 972a46c0ec8Sopenharmony_ci 973a46c0ec8Sopenharmony_ci if (dispatch->arbitration.in_arbitration) { 974a46c0ec8Sopenharmony_ci if (!warned) { 975a46c0ec8Sopenharmony_ci evdev_log_debug(device, "dropping events due to touch arbitration\n"); 976a46c0ec8Sopenharmony_ci warned = true; 977a46c0ec8Sopenharmony_ci } 978a46c0ec8Sopenharmony_ci return; 979a46c0ec8Sopenharmony_ci } 980a46c0ec8Sopenharmony_ci 981a46c0ec8Sopenharmony_ci warned = false; 982a46c0ec8Sopenharmony_ci 983a46c0ec8Sopenharmony_ci switch (event->type) { 984a46c0ec8Sopenharmony_ci case EV_REL: 985a46c0ec8Sopenharmony_ci fallback_process_relative(dispatch, device, event, time); 986a46c0ec8Sopenharmony_ci break; 987a46c0ec8Sopenharmony_ci case EV_ABS: 988a46c0ec8Sopenharmony_ci fallback_process_absolute(dispatch, device, event, time); 989a46c0ec8Sopenharmony_ci break; 990a46c0ec8Sopenharmony_ci case EV_KEY: 991a46c0ec8Sopenharmony_ci fallback_process_key(dispatch, device, event, time); 992a46c0ec8Sopenharmony_ci break; 993a46c0ec8Sopenharmony_ci case EV_SW: 994a46c0ec8Sopenharmony_ci fallback_process_switch(dispatch, device, event, time); 995a46c0ec8Sopenharmony_ci break; 996a46c0ec8Sopenharmony_ci case EV_SYN: 997a46c0ec8Sopenharmony_ci fallback_handle_state(dispatch, device, time); 998a46c0ec8Sopenharmony_ci break; 999a46c0ec8Sopenharmony_ci } 1000a46c0ec8Sopenharmony_ci} 1001a46c0ec8Sopenharmony_ci 1002a46c0ec8Sopenharmony_cistatic void 1003a46c0ec8Sopenharmony_cicancel_touches(struct fallback_dispatch *dispatch, 1004a46c0ec8Sopenharmony_ci struct evdev_device *device, 1005a46c0ec8Sopenharmony_ci const struct device_coord_rect *rect, 1006a46c0ec8Sopenharmony_ci uint64_t time) 1007a46c0ec8Sopenharmony_ci{ 1008a46c0ec8Sopenharmony_ci unsigned int idx; 1009a46c0ec8Sopenharmony_ci bool need_frame = false; 1010a46c0ec8Sopenharmony_ci struct device_coords point; 1011a46c0ec8Sopenharmony_ci 1012a46c0ec8Sopenharmony_ci point = dispatch->abs.point; 1013a46c0ec8Sopenharmony_ci evdev_transform_absolute(device, &point); 1014a46c0ec8Sopenharmony_ci if (!rect || point_in_rect(&point, rect)) 1015a46c0ec8Sopenharmony_ci need_frame = fallback_flush_st_cancel(dispatch, 1016a46c0ec8Sopenharmony_ci device, 1017a46c0ec8Sopenharmony_ci time); 1018a46c0ec8Sopenharmony_ci 1019a46c0ec8Sopenharmony_ci for (idx = 0; idx < dispatch->mt.slots_len; idx++) { 1020a46c0ec8Sopenharmony_ci struct mt_slot *slot = &dispatch->mt.slots[idx]; 1021a46c0ec8Sopenharmony_ci point = slot->point; 1022a46c0ec8Sopenharmony_ci evdev_transform_absolute(device, &point); 1023a46c0ec8Sopenharmony_ci 1024a46c0ec8Sopenharmony_ci if (slot->seat_slot == -1) 1025a46c0ec8Sopenharmony_ci continue; 1026a46c0ec8Sopenharmony_ci 1027a46c0ec8Sopenharmony_ci if ((!rect || point_in_rect(&point, rect)) && 1028a46c0ec8Sopenharmony_ci fallback_flush_mt_cancel(dispatch, device, idx, time)) 1029a46c0ec8Sopenharmony_ci need_frame = true; 1030a46c0ec8Sopenharmony_ci } 1031a46c0ec8Sopenharmony_ci 1032a46c0ec8Sopenharmony_ci if (need_frame) 1033a46c0ec8Sopenharmony_ci touch_notify_frame(&device->base, time); 1034a46c0ec8Sopenharmony_ci} 1035a46c0ec8Sopenharmony_ci 1036a46c0ec8Sopenharmony_cistatic void 1037a46c0ec8Sopenharmony_cirelease_pressed_keys(struct fallback_dispatch *dispatch, 1038a46c0ec8Sopenharmony_ci struct evdev_device *device, 1039a46c0ec8Sopenharmony_ci uint64_t time) 1040a46c0ec8Sopenharmony_ci{ 1041a46c0ec8Sopenharmony_ci int code; 1042a46c0ec8Sopenharmony_ci 1043a46c0ec8Sopenharmony_ci for (code = 0; code < KEY_CNT; code++) { 1044a46c0ec8Sopenharmony_ci int count = get_key_down_count(device, code); 1045a46c0ec8Sopenharmony_ci 1046a46c0ec8Sopenharmony_ci if (count == 0) 1047a46c0ec8Sopenharmony_ci continue; 1048a46c0ec8Sopenharmony_ci 1049a46c0ec8Sopenharmony_ci if (count > 1) { 1050a46c0ec8Sopenharmony_ci evdev_log_bug_libinput(device, 1051a46c0ec8Sopenharmony_ci "key %d is down %d times.\n", 1052a46c0ec8Sopenharmony_ci code, 1053a46c0ec8Sopenharmony_ci count); 1054a46c0ec8Sopenharmony_ci } 1055a46c0ec8Sopenharmony_ci 1056a46c0ec8Sopenharmony_ci switch (get_key_type(code)) { 1057a46c0ec8Sopenharmony_ci case KEY_TYPE_NONE: 1058a46c0ec8Sopenharmony_ci break; 1059a46c0ec8Sopenharmony_ci case KEY_TYPE_KEY: 1060a46c0ec8Sopenharmony_ci fallback_keyboard_notify_key( 1061a46c0ec8Sopenharmony_ci dispatch, 1062a46c0ec8Sopenharmony_ci device, 1063a46c0ec8Sopenharmony_ci time, 1064a46c0ec8Sopenharmony_ci code, 1065a46c0ec8Sopenharmony_ci LIBINPUT_KEY_STATE_RELEASED); 1066a46c0ec8Sopenharmony_ci break; 1067a46c0ec8Sopenharmony_ci case KEY_TYPE_BUTTON: 1068a46c0ec8Sopenharmony_ci /* Note: the left-handed configuration is nonzero for 1069a46c0ec8Sopenharmony_ci * the mapped button (not the physical button), in 1070a46c0ec8Sopenharmony_ci * get_key_down_count(). We must not map this to left-handed 1071a46c0ec8Sopenharmony_ci * again, see #881. 1072a46c0ec8Sopenharmony_ci */ 1073a46c0ec8Sopenharmony_ci evdev_pointer_notify_button( 1074a46c0ec8Sopenharmony_ci device, 1075a46c0ec8Sopenharmony_ci time, 1076a46c0ec8Sopenharmony_ci code, 1077a46c0ec8Sopenharmony_ci LIBINPUT_BUTTON_STATE_RELEASED); 1078a46c0ec8Sopenharmony_ci break; 1079a46c0ec8Sopenharmony_ci } 1080a46c0ec8Sopenharmony_ci 1081a46c0ec8Sopenharmony_ci count = get_key_down_count(device, code); 1082a46c0ec8Sopenharmony_ci if (count != 0) { 1083a46c0ec8Sopenharmony_ci evdev_log_bug_libinput(device, 1084a46c0ec8Sopenharmony_ci "releasing key %d failed.\n", 1085a46c0ec8Sopenharmony_ci code); 1086a46c0ec8Sopenharmony_ci break; 1087a46c0ec8Sopenharmony_ci } 1088a46c0ec8Sopenharmony_ci } 1089a46c0ec8Sopenharmony_ci} 1090a46c0ec8Sopenharmony_ci 1091a46c0ec8Sopenharmony_cistatic void 1092a46c0ec8Sopenharmony_cifallback_return_to_neutral_state(struct fallback_dispatch *dispatch, 1093a46c0ec8Sopenharmony_ci struct evdev_device *device) 1094a46c0ec8Sopenharmony_ci{ 1095a46c0ec8Sopenharmony_ci struct libinput *libinput = evdev_libinput_context(device); 1096a46c0ec8Sopenharmony_ci uint64_t time; 1097a46c0ec8Sopenharmony_ci 1098a46c0ec8Sopenharmony_ci if ((time = libinput_now(libinput)) == 0) 1099a46c0ec8Sopenharmony_ci return; 1100a46c0ec8Sopenharmony_ci 1101a46c0ec8Sopenharmony_ci cancel_touches(dispatch, device, NULL, time); 1102a46c0ec8Sopenharmony_ci release_pressed_keys(dispatch, device, time); 1103a46c0ec8Sopenharmony_ci memset(dispatch->hw_key_mask, 0, sizeof(dispatch->hw_key_mask)); 1104a46c0ec8Sopenharmony_ci memset(dispatch->hw_key_mask, 0, sizeof(dispatch->last_hw_key_mask)); 1105a46c0ec8Sopenharmony_ci} 1106a46c0ec8Sopenharmony_ci 1107a46c0ec8Sopenharmony_cistatic void 1108a46c0ec8Sopenharmony_cifallback_interface_suspend(struct evdev_dispatch *evdev_dispatch, 1109a46c0ec8Sopenharmony_ci struct evdev_device *device) 1110a46c0ec8Sopenharmony_ci{ 1111a46c0ec8Sopenharmony_ci struct fallback_dispatch *dispatch = fallback_dispatch(evdev_dispatch); 1112a46c0ec8Sopenharmony_ci 1113a46c0ec8Sopenharmony_ci fallback_return_to_neutral_state(dispatch, device); 1114a46c0ec8Sopenharmony_ci} 1115a46c0ec8Sopenharmony_ci 1116a46c0ec8Sopenharmony_cistatic void 1117a46c0ec8Sopenharmony_cifallback_interface_remove(struct evdev_dispatch *evdev_dispatch) 1118a46c0ec8Sopenharmony_ci{ 1119a46c0ec8Sopenharmony_ci struct fallback_dispatch *dispatch = fallback_dispatch(evdev_dispatch); 1120a46c0ec8Sopenharmony_ci struct evdev_paired_keyboard *kbd; 1121a46c0ec8Sopenharmony_ci 1122a46c0ec8Sopenharmony_ci libinput_timer_cancel(&dispatch->wheel.scroll_timer); 1123a46c0ec8Sopenharmony_ci libinput_timer_cancel(&dispatch->debounce.timer); 1124a46c0ec8Sopenharmony_ci libinput_timer_cancel(&dispatch->debounce.timer_short); 1125a46c0ec8Sopenharmony_ci libinput_timer_cancel(&dispatch->arbitration.arbitration_timer); 1126a46c0ec8Sopenharmony_ci 1127a46c0ec8Sopenharmony_ci libinput_device_remove_event_listener(&dispatch->tablet_mode.other.listener); 1128a46c0ec8Sopenharmony_ci 1129a46c0ec8Sopenharmony_ci list_for_each_safe(kbd, 1130a46c0ec8Sopenharmony_ci &dispatch->lid.paired_keyboard_list, 1131a46c0ec8Sopenharmony_ci link) { 1132a46c0ec8Sopenharmony_ci evdev_paired_keyboard_destroy(kbd); 1133a46c0ec8Sopenharmony_ci } 1134a46c0ec8Sopenharmony_ci} 1135a46c0ec8Sopenharmony_ci 1136a46c0ec8Sopenharmony_cistatic void 1137a46c0ec8Sopenharmony_cifallback_interface_sync_initial_state(struct evdev_device *device, 1138a46c0ec8Sopenharmony_ci struct evdev_dispatch *evdev_dispatch) 1139a46c0ec8Sopenharmony_ci{ 1140a46c0ec8Sopenharmony_ci struct fallback_dispatch *dispatch = fallback_dispatch(evdev_dispatch); 1141a46c0ec8Sopenharmony_ci uint64_t time = libinput_now(evdev_libinput_context(device)); 1142a46c0ec8Sopenharmony_ci 1143a46c0ec8Sopenharmony_ci if (device->tags & EVDEV_TAG_LID_SWITCH) { 1144a46c0ec8Sopenharmony_ci struct libevdev *evdev = device->evdev; 1145a46c0ec8Sopenharmony_ci 1146a46c0ec8Sopenharmony_ci dispatch->lid.is_closed = libevdev_get_event_value(evdev, 1147a46c0ec8Sopenharmony_ci EV_SW, 1148a46c0ec8Sopenharmony_ci SW_LID); 1149a46c0ec8Sopenharmony_ci dispatch->lid.is_closed_client_state = false; 1150a46c0ec8Sopenharmony_ci 1151a46c0ec8Sopenharmony_ci /* For the initial state sync, we depend on whether the lid switch 1152a46c0ec8Sopenharmony_ci * is reliable. If we know it's reliable, we sync as expected. 1153a46c0ec8Sopenharmony_ci * If we're not sure, we ignore the initial state and only sync on 1154a46c0ec8Sopenharmony_ci * the first future lid close event. Laptops with a broken switch 1155a46c0ec8Sopenharmony_ci * that always have the switch in 'on' state thus don't mess up our 1156a46c0ec8Sopenharmony_ci * touchpad. 1157a46c0ec8Sopenharmony_ci */ 1158a46c0ec8Sopenharmony_ci if (dispatch->lid.is_closed && 1159a46c0ec8Sopenharmony_ci dispatch->lid.reliability == RELIABILITY_RELIABLE) { 1160a46c0ec8Sopenharmony_ci fallback_lid_notify_toggle(dispatch, device, time); 1161a46c0ec8Sopenharmony_ci } 1162a46c0ec8Sopenharmony_ci } 1163a46c0ec8Sopenharmony_ci 1164a46c0ec8Sopenharmony_ci if (dispatch->tablet_mode.sw.state) { 1165a46c0ec8Sopenharmony_ci switch_notify_toggle(&device->base, 1166a46c0ec8Sopenharmony_ci time, 1167a46c0ec8Sopenharmony_ci LIBINPUT_SWITCH_TABLET_MODE, 1168a46c0ec8Sopenharmony_ci LIBINPUT_SWITCH_STATE_ON); 1169a46c0ec8Sopenharmony_ci } 1170a46c0ec8Sopenharmony_ci} 1171a46c0ec8Sopenharmony_ci 1172a46c0ec8Sopenharmony_cistatic void 1173a46c0ec8Sopenharmony_cifallback_interface_update_rect(struct evdev_dispatch *evdev_dispatch, 1174a46c0ec8Sopenharmony_ci struct evdev_device *device, 1175a46c0ec8Sopenharmony_ci const struct phys_rect *phys_rect, 1176a46c0ec8Sopenharmony_ci uint64_t time) 1177a46c0ec8Sopenharmony_ci{ 1178a46c0ec8Sopenharmony_ci struct fallback_dispatch *dispatch = fallback_dispatch(evdev_dispatch); 1179a46c0ec8Sopenharmony_ci struct device_coord_rect rect; 1180a46c0ec8Sopenharmony_ci 1181a46c0ec8Sopenharmony_ci assert(phys_rect); 1182a46c0ec8Sopenharmony_ci 1183a46c0ec8Sopenharmony_ci /* Existing touches do not change, we just update the rect and only 1184a46c0ec8Sopenharmony_ci * new touches in these areas will be ignored. If you want to paint 1185a46c0ec8Sopenharmony_ci * over your finger, be my guest. */ 1186a46c0ec8Sopenharmony_ci rect = evdev_phys_rect_to_units(device, phys_rect); 1187a46c0ec8Sopenharmony_ci dispatch->arbitration.rect = rect; 1188a46c0ec8Sopenharmony_ci} 1189a46c0ec8Sopenharmony_ci 1190a46c0ec8Sopenharmony_cistatic void 1191a46c0ec8Sopenharmony_cifallback_interface_toggle_touch(struct evdev_dispatch *evdev_dispatch, 1192a46c0ec8Sopenharmony_ci struct evdev_device *device, 1193a46c0ec8Sopenharmony_ci enum evdev_arbitration_state which, 1194a46c0ec8Sopenharmony_ci const struct phys_rect *phys_rect, 1195a46c0ec8Sopenharmony_ci uint64_t time) 1196a46c0ec8Sopenharmony_ci{ 1197a46c0ec8Sopenharmony_ci struct fallback_dispatch *dispatch = fallback_dispatch(evdev_dispatch); 1198a46c0ec8Sopenharmony_ci struct device_coord_rect rect = {0}; 1199a46c0ec8Sopenharmony_ci const char *state = NULL; 1200a46c0ec8Sopenharmony_ci 1201a46c0ec8Sopenharmony_ci if (which == dispatch->arbitration.state) 1202a46c0ec8Sopenharmony_ci return; 1203a46c0ec8Sopenharmony_ci 1204a46c0ec8Sopenharmony_ci switch (which) { 1205a46c0ec8Sopenharmony_ci case ARBITRATION_NOT_ACTIVE: 1206a46c0ec8Sopenharmony_ci /* if in-kernel arbitration is in use and there is a touch 1207a46c0ec8Sopenharmony_ci * and a pen in proximity, lifting the pen out of proximity 1208a46c0ec8Sopenharmony_ci * causes a touch begin for the touch. On a hand-lift the 1209a46c0ec8Sopenharmony_ci * proximity out precedes the touch up by a few ms, so we 1210a46c0ec8Sopenharmony_ci * get what looks like a tap. Fix this by delaying 1211a46c0ec8Sopenharmony_ci * arbitration by just a little bit so that any touch in 1212a46c0ec8Sopenharmony_ci * event is caught as palm touch. */ 1213a46c0ec8Sopenharmony_ci libinput_timer_set(&dispatch->arbitration.arbitration_timer, 1214a46c0ec8Sopenharmony_ci time + ms2us(90)); 1215a46c0ec8Sopenharmony_ci state = "not-active"; 1216a46c0ec8Sopenharmony_ci break; 1217a46c0ec8Sopenharmony_ci case ARBITRATION_IGNORE_RECT: 1218a46c0ec8Sopenharmony_ci assert(phys_rect); 1219a46c0ec8Sopenharmony_ci rect = evdev_phys_rect_to_units(device, phys_rect); 1220a46c0ec8Sopenharmony_ci cancel_touches(dispatch, device, &rect, time); 1221a46c0ec8Sopenharmony_ci dispatch->arbitration.rect = rect; 1222a46c0ec8Sopenharmony_ci state = "ignore-rect"; 1223a46c0ec8Sopenharmony_ci break; 1224a46c0ec8Sopenharmony_ci case ARBITRATION_IGNORE_ALL: 1225a46c0ec8Sopenharmony_ci libinput_timer_cancel(&dispatch->arbitration.arbitration_timer); 1226a46c0ec8Sopenharmony_ci fallback_return_to_neutral_state(dispatch, device); 1227a46c0ec8Sopenharmony_ci dispatch->arbitration.in_arbitration = true; 1228a46c0ec8Sopenharmony_ci state = "ignore-all"; 1229a46c0ec8Sopenharmony_ci break; 1230a46c0ec8Sopenharmony_ci } 1231a46c0ec8Sopenharmony_ci 1232a46c0ec8Sopenharmony_ci evdev_log_debug(device, "Touch arbitration state now %s\n", state); 1233a46c0ec8Sopenharmony_ci 1234a46c0ec8Sopenharmony_ci dispatch->arbitration.state = which; 1235a46c0ec8Sopenharmony_ci} 1236a46c0ec8Sopenharmony_ci 1237a46c0ec8Sopenharmony_cistatic void 1238a46c0ec8Sopenharmony_cifallback_interface_destroy(struct evdev_dispatch *evdev_dispatch) 1239a46c0ec8Sopenharmony_ci{ 1240a46c0ec8Sopenharmony_ci struct fallback_dispatch *dispatch = fallback_dispatch(evdev_dispatch); 1241a46c0ec8Sopenharmony_ci 1242a46c0ec8Sopenharmony_ci libinput_timer_destroy(&dispatch->wheel.scroll_timer); 1243a46c0ec8Sopenharmony_ci libinput_timer_destroy(&dispatch->arbitration.arbitration_timer); 1244a46c0ec8Sopenharmony_ci libinput_timer_destroy(&dispatch->debounce.timer); 1245a46c0ec8Sopenharmony_ci libinput_timer_destroy(&dispatch->debounce.timer_short); 1246a46c0ec8Sopenharmony_ci 1247a46c0ec8Sopenharmony_ci free(dispatch->mt.slots); 1248a46c0ec8Sopenharmony_ci free(dispatch); 1249a46c0ec8Sopenharmony_ci} 1250a46c0ec8Sopenharmony_ci 1251a46c0ec8Sopenharmony_cistatic void 1252a46c0ec8Sopenharmony_cifallback_lid_pair_keyboard(struct evdev_device *lid_switch, 1253a46c0ec8Sopenharmony_ci struct evdev_device *keyboard) 1254a46c0ec8Sopenharmony_ci{ 1255a46c0ec8Sopenharmony_ci struct fallback_dispatch *dispatch = 1256a46c0ec8Sopenharmony_ci fallback_dispatch(lid_switch->dispatch); 1257a46c0ec8Sopenharmony_ci struct evdev_paired_keyboard *kbd; 1258a46c0ec8Sopenharmony_ci size_t count = 0; 1259a46c0ec8Sopenharmony_ci 1260a46c0ec8Sopenharmony_ci if ((keyboard->tags & EVDEV_TAG_KEYBOARD) == 0 || 1261a46c0ec8Sopenharmony_ci (lid_switch->tags & EVDEV_TAG_LID_SWITCH) == 0) 1262a46c0ec8Sopenharmony_ci return; 1263a46c0ec8Sopenharmony_ci 1264a46c0ec8Sopenharmony_ci if ((keyboard->tags & EVDEV_TAG_INTERNAL_KEYBOARD) == 0) 1265a46c0ec8Sopenharmony_ci return; 1266a46c0ec8Sopenharmony_ci 1267a46c0ec8Sopenharmony_ci list_for_each(kbd, &dispatch->lid.paired_keyboard_list, link) { 1268a46c0ec8Sopenharmony_ci count++; 1269a46c0ec8Sopenharmony_ci if (count > 3) { 1270a46c0ec8Sopenharmony_ci evdev_log_info(lid_switch, 1271a46c0ec8Sopenharmony_ci "lid: too many internal keyboards\n"); 1272a46c0ec8Sopenharmony_ci break; 1273a46c0ec8Sopenharmony_ci } 1274a46c0ec8Sopenharmony_ci } 1275a46c0ec8Sopenharmony_ci 1276a46c0ec8Sopenharmony_ci kbd = zalloc(sizeof(*kbd)); 1277a46c0ec8Sopenharmony_ci kbd->device = keyboard; 1278a46c0ec8Sopenharmony_ci libinput_device_init_event_listener(&kbd->listener); 1279a46c0ec8Sopenharmony_ci list_insert(&dispatch->lid.paired_keyboard_list, &kbd->link); 1280a46c0ec8Sopenharmony_ci evdev_log_debug(lid_switch, 1281a46c0ec8Sopenharmony_ci "lid: keyboard paired with %s<->%s\n", 1282a46c0ec8Sopenharmony_ci lid_switch->devname, 1283a46c0ec8Sopenharmony_ci keyboard->devname); 1284a46c0ec8Sopenharmony_ci 1285a46c0ec8Sopenharmony_ci /* We need to init the event listener now only if the 1286a46c0ec8Sopenharmony_ci * reported state is closed. */ 1287a46c0ec8Sopenharmony_ci if (dispatch->lid.is_closed) 1288a46c0ec8Sopenharmony_ci fallback_lid_toggle_keyboard_listener(dispatch, 1289a46c0ec8Sopenharmony_ci kbd, 1290a46c0ec8Sopenharmony_ci dispatch->lid.is_closed); 1291a46c0ec8Sopenharmony_ci} 1292a46c0ec8Sopenharmony_ci 1293a46c0ec8Sopenharmony_cistatic void 1294a46c0ec8Sopenharmony_cifallback_resume(struct fallback_dispatch *dispatch, 1295a46c0ec8Sopenharmony_ci struct evdev_device *device) 1296a46c0ec8Sopenharmony_ci{ 1297a46c0ec8Sopenharmony_ci if (dispatch->base.sendevents.current_mode == 1298a46c0ec8Sopenharmony_ci LIBINPUT_CONFIG_SEND_EVENTS_DISABLED) 1299a46c0ec8Sopenharmony_ci return; 1300a46c0ec8Sopenharmony_ci 1301a46c0ec8Sopenharmony_ci evdev_device_resume(device); 1302a46c0ec8Sopenharmony_ci} 1303a46c0ec8Sopenharmony_ci 1304a46c0ec8Sopenharmony_cistatic void 1305a46c0ec8Sopenharmony_cifallback_suspend(struct fallback_dispatch *dispatch, 1306a46c0ec8Sopenharmony_ci struct evdev_device *device) 1307a46c0ec8Sopenharmony_ci{ 1308a46c0ec8Sopenharmony_ci evdev_device_suspend(device); 1309a46c0ec8Sopenharmony_ci} 1310a46c0ec8Sopenharmony_ci 1311a46c0ec8Sopenharmony_cistatic void 1312a46c0ec8Sopenharmony_cifallback_tablet_mode_switch_event(uint64_t time, 1313a46c0ec8Sopenharmony_ci struct libinput_event *event, 1314a46c0ec8Sopenharmony_ci void *data) 1315a46c0ec8Sopenharmony_ci{ 1316a46c0ec8Sopenharmony_ci struct fallback_dispatch *dispatch = data; 1317a46c0ec8Sopenharmony_ci struct evdev_device *device = dispatch->device; 1318a46c0ec8Sopenharmony_ci struct libinput_event_switch *swev; 1319a46c0ec8Sopenharmony_ci 1320a46c0ec8Sopenharmony_ci if (libinput_event_get_type(event) != LIBINPUT_EVENT_SWITCH_TOGGLE) 1321a46c0ec8Sopenharmony_ci return; 1322a46c0ec8Sopenharmony_ci 1323a46c0ec8Sopenharmony_ci swev = libinput_event_get_switch_event(event); 1324a46c0ec8Sopenharmony_ci if (libinput_event_switch_get_switch(swev) != 1325a46c0ec8Sopenharmony_ci LIBINPUT_SWITCH_TABLET_MODE) 1326a46c0ec8Sopenharmony_ci return; 1327a46c0ec8Sopenharmony_ci 1328a46c0ec8Sopenharmony_ci switch (libinput_event_switch_get_switch_state(swev)) { 1329a46c0ec8Sopenharmony_ci case LIBINPUT_SWITCH_STATE_OFF: 1330a46c0ec8Sopenharmony_ci fallback_resume(dispatch, device); 1331a46c0ec8Sopenharmony_ci evdev_log_debug(device, "tablet-mode: resuming device\n"); 1332a46c0ec8Sopenharmony_ci break; 1333a46c0ec8Sopenharmony_ci case LIBINPUT_SWITCH_STATE_ON: 1334a46c0ec8Sopenharmony_ci fallback_suspend(dispatch, device); 1335a46c0ec8Sopenharmony_ci evdev_log_debug(device, "tablet-mode: suspending device\n"); 1336a46c0ec8Sopenharmony_ci break; 1337a46c0ec8Sopenharmony_ci } 1338a46c0ec8Sopenharmony_ci} 1339a46c0ec8Sopenharmony_ci 1340a46c0ec8Sopenharmony_cistatic void 1341a46c0ec8Sopenharmony_cifallback_pair_tablet_mode(struct evdev_device *keyboard, 1342a46c0ec8Sopenharmony_ci struct evdev_device *tablet_mode_switch) 1343a46c0ec8Sopenharmony_ci{ 1344a46c0ec8Sopenharmony_ci struct fallback_dispatch *dispatch = 1345a46c0ec8Sopenharmony_ci fallback_dispatch(keyboard->dispatch); 1346a46c0ec8Sopenharmony_ci 1347a46c0ec8Sopenharmony_ci if ((keyboard->tags & EVDEV_TAG_EXTERNAL_KEYBOARD)) 1348a46c0ec8Sopenharmony_ci return; 1349a46c0ec8Sopenharmony_ci 1350a46c0ec8Sopenharmony_ci if ((keyboard->tags & EVDEV_TAG_TRACKPOINT)) { 1351a46c0ec8Sopenharmony_ci if (keyboard->tags & EVDEV_TAG_EXTERNAL_MOUSE) 1352a46c0ec8Sopenharmony_ci return; 1353a46c0ec8Sopenharmony_ci /* This filters out all internal keyboard-like devices (Video 1354a46c0ec8Sopenharmony_ci * Switch) */ 1355a46c0ec8Sopenharmony_ci } else if ((keyboard->tags & EVDEV_TAG_INTERNAL_KEYBOARD) == 0) { 1356a46c0ec8Sopenharmony_ci return; 1357a46c0ec8Sopenharmony_ci } 1358a46c0ec8Sopenharmony_ci 1359a46c0ec8Sopenharmony_ci if (evdev_device_has_model_quirk(keyboard, 1360a46c0ec8Sopenharmony_ci QUIRK_MODEL_TABLET_MODE_NO_SUSPEND)) 1361a46c0ec8Sopenharmony_ci return; 1362a46c0ec8Sopenharmony_ci 1363a46c0ec8Sopenharmony_ci if ((tablet_mode_switch->tags & EVDEV_TAG_TABLET_MODE_SWITCH) == 0) 1364a46c0ec8Sopenharmony_ci return; 1365a46c0ec8Sopenharmony_ci 1366a46c0ec8Sopenharmony_ci if (dispatch->tablet_mode.other.sw_device) 1367a46c0ec8Sopenharmony_ci return; 1368a46c0ec8Sopenharmony_ci 1369a46c0ec8Sopenharmony_ci evdev_log_debug(keyboard, 1370a46c0ec8Sopenharmony_ci "tablet-mode: paired %s<->%s\n", 1371a46c0ec8Sopenharmony_ci keyboard->devname, 1372a46c0ec8Sopenharmony_ci tablet_mode_switch->devname); 1373a46c0ec8Sopenharmony_ci 1374a46c0ec8Sopenharmony_ci libinput_device_add_event_listener(&tablet_mode_switch->base, 1375a46c0ec8Sopenharmony_ci &dispatch->tablet_mode.other.listener, 1376a46c0ec8Sopenharmony_ci fallback_tablet_mode_switch_event, 1377a46c0ec8Sopenharmony_ci dispatch); 1378a46c0ec8Sopenharmony_ci dispatch->tablet_mode.other.sw_device = tablet_mode_switch; 1379a46c0ec8Sopenharmony_ci 1380a46c0ec8Sopenharmony_ci if (evdev_device_switch_get_state(tablet_mode_switch, 1381a46c0ec8Sopenharmony_ci LIBINPUT_SWITCH_TABLET_MODE) 1382a46c0ec8Sopenharmony_ci == LIBINPUT_SWITCH_STATE_ON) { 1383a46c0ec8Sopenharmony_ci evdev_log_debug(keyboard, "tablet-mode: suspending device\n"); 1384a46c0ec8Sopenharmony_ci fallback_suspend(dispatch, keyboard); 1385a46c0ec8Sopenharmony_ci } 1386a46c0ec8Sopenharmony_ci} 1387a46c0ec8Sopenharmony_ci 1388a46c0ec8Sopenharmony_cistatic void 1389a46c0ec8Sopenharmony_cifallback_interface_device_added(struct evdev_device *device, 1390a46c0ec8Sopenharmony_ci struct evdev_device *added_device) 1391a46c0ec8Sopenharmony_ci{ 1392a46c0ec8Sopenharmony_ci fallback_lid_pair_keyboard(device, added_device); 1393a46c0ec8Sopenharmony_ci fallback_pair_tablet_mode(device, added_device); 1394a46c0ec8Sopenharmony_ci} 1395a46c0ec8Sopenharmony_ci 1396a46c0ec8Sopenharmony_cistatic void 1397a46c0ec8Sopenharmony_cifallback_interface_device_removed(struct evdev_device *device, 1398a46c0ec8Sopenharmony_ci struct evdev_device *removed_device) 1399a46c0ec8Sopenharmony_ci{ 1400a46c0ec8Sopenharmony_ci struct fallback_dispatch *dispatch = 1401a46c0ec8Sopenharmony_ci fallback_dispatch(device->dispatch); 1402a46c0ec8Sopenharmony_ci struct evdev_paired_keyboard *kbd; 1403a46c0ec8Sopenharmony_ci 1404a46c0ec8Sopenharmony_ci list_for_each_safe(kbd, 1405a46c0ec8Sopenharmony_ci &dispatch->lid.paired_keyboard_list, 1406a46c0ec8Sopenharmony_ci link) { 1407a46c0ec8Sopenharmony_ci if (!kbd->device) 1408a46c0ec8Sopenharmony_ci continue; 1409a46c0ec8Sopenharmony_ci 1410a46c0ec8Sopenharmony_ci if (kbd->device != removed_device) 1411a46c0ec8Sopenharmony_ci continue; 1412a46c0ec8Sopenharmony_ci 1413a46c0ec8Sopenharmony_ci evdev_paired_keyboard_destroy(kbd); 1414a46c0ec8Sopenharmony_ci } 1415a46c0ec8Sopenharmony_ci 1416a46c0ec8Sopenharmony_ci if (removed_device == dispatch->tablet_mode.other.sw_device) { 1417a46c0ec8Sopenharmony_ci libinput_device_remove_event_listener( 1418a46c0ec8Sopenharmony_ci &dispatch->tablet_mode.other.listener); 1419a46c0ec8Sopenharmony_ci libinput_device_init_event_listener( 1420a46c0ec8Sopenharmony_ci &dispatch->tablet_mode.other.listener); 1421a46c0ec8Sopenharmony_ci dispatch->tablet_mode.other.sw_device = NULL; 1422a46c0ec8Sopenharmony_ci } 1423a46c0ec8Sopenharmony_ci} 1424a46c0ec8Sopenharmony_ci 1425a46c0ec8Sopenharmony_cistruct evdev_dispatch_interface fallback_interface = { 1426a46c0ec8Sopenharmony_ci .process = fallback_interface_process, 1427a46c0ec8Sopenharmony_ci .suspend = fallback_interface_suspend, 1428a46c0ec8Sopenharmony_ci .remove = fallback_interface_remove, 1429a46c0ec8Sopenharmony_ci .destroy = fallback_interface_destroy, 1430a46c0ec8Sopenharmony_ci .device_added = fallback_interface_device_added, 1431a46c0ec8Sopenharmony_ci .device_removed = fallback_interface_device_removed, 1432a46c0ec8Sopenharmony_ci .device_suspended = fallback_interface_device_removed, /* treat as remove */ 1433a46c0ec8Sopenharmony_ci .device_resumed = fallback_interface_device_added, /* treat as add */ 1434a46c0ec8Sopenharmony_ci .post_added = fallback_interface_sync_initial_state, 1435a46c0ec8Sopenharmony_ci .touch_arbitration_toggle = fallback_interface_toggle_touch, 1436a46c0ec8Sopenharmony_ci .touch_arbitration_update_rect = fallback_interface_update_rect, 1437a46c0ec8Sopenharmony_ci .get_switch_state = fallback_interface_get_switch_state, 1438a46c0ec8Sopenharmony_ci}; 1439a46c0ec8Sopenharmony_ci 1440a46c0ec8Sopenharmony_cistatic void 1441a46c0ec8Sopenharmony_cifallback_change_to_left_handed(struct evdev_device *device) 1442a46c0ec8Sopenharmony_ci{ 1443a46c0ec8Sopenharmony_ci struct fallback_dispatch *dispatch = fallback_dispatch(device->dispatch); 1444a46c0ec8Sopenharmony_ci 1445a46c0ec8Sopenharmony_ci if (device->left_handed.want_enabled == device->left_handed.enabled) 1446a46c0ec8Sopenharmony_ci return; 1447a46c0ec8Sopenharmony_ci 1448a46c0ec8Sopenharmony_ci if (fallback_any_button_down(dispatch, device)) 1449a46c0ec8Sopenharmony_ci return; 1450a46c0ec8Sopenharmony_ci 1451a46c0ec8Sopenharmony_ci device->left_handed.enabled = device->left_handed.want_enabled; 1452a46c0ec8Sopenharmony_ci} 1453a46c0ec8Sopenharmony_ci 1454a46c0ec8Sopenharmony_cistatic void 1455a46c0ec8Sopenharmony_cifallback_change_scroll_method(struct evdev_device *device) 1456a46c0ec8Sopenharmony_ci{ 1457a46c0ec8Sopenharmony_ci struct fallback_dispatch *dispatch = fallback_dispatch(device->dispatch); 1458a46c0ec8Sopenharmony_ci 1459a46c0ec8Sopenharmony_ci if (device->scroll.want_method == device->scroll.method && 1460a46c0ec8Sopenharmony_ci device->scroll.want_button == device->scroll.button && 1461a46c0ec8Sopenharmony_ci device->scroll.want_lock_enabled == device->scroll.lock_enabled) 1462a46c0ec8Sopenharmony_ci return; 1463a46c0ec8Sopenharmony_ci 1464a46c0ec8Sopenharmony_ci if (fallback_any_button_down(dispatch, device)) 1465a46c0ec8Sopenharmony_ci return; 1466a46c0ec8Sopenharmony_ci 1467a46c0ec8Sopenharmony_ci device->scroll.method = device->scroll.want_method; 1468a46c0ec8Sopenharmony_ci device->scroll.button = device->scroll.want_button; 1469a46c0ec8Sopenharmony_ci device->scroll.lock_enabled = device->scroll.want_lock_enabled; 1470a46c0ec8Sopenharmony_ci evdev_set_button_scroll_lock_enabled(device, device->scroll.lock_enabled); 1471a46c0ec8Sopenharmony_ci} 1472a46c0ec8Sopenharmony_ci 1473a46c0ec8Sopenharmony_cistatic int 1474a46c0ec8Sopenharmony_cifallback_rotation_config_is_available(struct libinput_device *device) 1475a46c0ec8Sopenharmony_ci{ 1476a46c0ec8Sopenharmony_ci /* This function only gets called when we support rotation */ 1477a46c0ec8Sopenharmony_ci return 1; 1478a46c0ec8Sopenharmony_ci} 1479a46c0ec8Sopenharmony_ci 1480a46c0ec8Sopenharmony_cistatic enum libinput_config_status 1481a46c0ec8Sopenharmony_cifallback_rotation_config_set_angle(struct libinput_device *libinput_device, 1482a46c0ec8Sopenharmony_ci unsigned int degrees_cw) 1483a46c0ec8Sopenharmony_ci{ 1484a46c0ec8Sopenharmony_ci struct evdev_device *device = evdev_device(libinput_device); 1485a46c0ec8Sopenharmony_ci struct fallback_dispatch *dispatch = fallback_dispatch(device->dispatch); 1486a46c0ec8Sopenharmony_ci 1487a46c0ec8Sopenharmony_ci dispatch->rotation.angle = degrees_cw; 1488a46c0ec8Sopenharmony_ci matrix_init_rotate(&dispatch->rotation.matrix, degrees_cw); 1489a46c0ec8Sopenharmony_ci 1490a46c0ec8Sopenharmony_ci return LIBINPUT_CONFIG_STATUS_SUCCESS; 1491a46c0ec8Sopenharmony_ci} 1492a46c0ec8Sopenharmony_ci 1493a46c0ec8Sopenharmony_cistatic unsigned int 1494a46c0ec8Sopenharmony_cifallback_rotation_config_get_angle(struct libinput_device *libinput_device) 1495a46c0ec8Sopenharmony_ci{ 1496a46c0ec8Sopenharmony_ci struct evdev_device *device = evdev_device(libinput_device); 1497a46c0ec8Sopenharmony_ci struct fallback_dispatch *dispatch = fallback_dispatch(device->dispatch); 1498a46c0ec8Sopenharmony_ci 1499a46c0ec8Sopenharmony_ci return dispatch->rotation.angle; 1500a46c0ec8Sopenharmony_ci} 1501a46c0ec8Sopenharmony_ci 1502a46c0ec8Sopenharmony_cistatic unsigned int 1503a46c0ec8Sopenharmony_cifallback_rotation_config_get_default_angle(struct libinput_device *device) 1504a46c0ec8Sopenharmony_ci{ 1505a46c0ec8Sopenharmony_ci return 0; 1506a46c0ec8Sopenharmony_ci} 1507a46c0ec8Sopenharmony_ci 1508a46c0ec8Sopenharmony_cistatic void 1509a46c0ec8Sopenharmony_cifallback_init_rotation(struct fallback_dispatch *dispatch, 1510a46c0ec8Sopenharmony_ci struct evdev_device *device) 1511a46c0ec8Sopenharmony_ci{ 1512a46c0ec8Sopenharmony_ci if (device->tags & EVDEV_TAG_TRACKPOINT) 1513a46c0ec8Sopenharmony_ci return; 1514a46c0ec8Sopenharmony_ci 1515a46c0ec8Sopenharmony_ci dispatch->rotation.config.is_available = fallback_rotation_config_is_available; 1516a46c0ec8Sopenharmony_ci dispatch->rotation.config.set_angle = fallback_rotation_config_set_angle; 1517a46c0ec8Sopenharmony_ci dispatch->rotation.config.get_angle = fallback_rotation_config_get_angle; 1518a46c0ec8Sopenharmony_ci dispatch->rotation.config.get_default_angle = fallback_rotation_config_get_default_angle; 1519a46c0ec8Sopenharmony_ci matrix_init_identity(&dispatch->rotation.matrix); 1520a46c0ec8Sopenharmony_ci device->base.config.rotation = &dispatch->rotation.config; 1521a46c0ec8Sopenharmony_ci} 1522a46c0ec8Sopenharmony_ci 1523a46c0ec8Sopenharmony_cistatic inline int 1524a46c0ec8Sopenharmony_cifallback_dispatch_init_slots(struct fallback_dispatch *dispatch, 1525a46c0ec8Sopenharmony_ci struct evdev_device *device) 1526a46c0ec8Sopenharmony_ci{ 1527a46c0ec8Sopenharmony_ci struct libevdev *evdev = device->evdev; 1528a46c0ec8Sopenharmony_ci struct mt_slot *slots; 1529a46c0ec8Sopenharmony_ci int num_slots; 1530a46c0ec8Sopenharmony_ci int active_slot; 1531a46c0ec8Sopenharmony_ci int slot; 1532a46c0ec8Sopenharmony_ci 1533a46c0ec8Sopenharmony_ci if (evdev_is_fake_mt_device(device) || 1534a46c0ec8Sopenharmony_ci !libevdev_has_event_code(evdev, EV_ABS, ABS_MT_POSITION_X) || 1535a46c0ec8Sopenharmony_ci !libevdev_has_event_code(evdev, EV_ABS, ABS_MT_POSITION_Y)) 1536a46c0ec8Sopenharmony_ci return 0; 1537a46c0ec8Sopenharmony_ci 1538a46c0ec8Sopenharmony_ci /* We only handle the slotted Protocol B in libinput. 1539a46c0ec8Sopenharmony_ci Devices with ABS_MT_POSITION_* but not ABS_MT_SLOT 1540a46c0ec8Sopenharmony_ci require mtdev for conversion. */ 1541a46c0ec8Sopenharmony_ci if (evdev_need_mtdev(device)) { 1542a46c0ec8Sopenharmony_ci device->mtdev = mtdev_new_open(device->fd); 1543a46c0ec8Sopenharmony_ci if (!device->mtdev) 1544a46c0ec8Sopenharmony_ci return -1; 1545a46c0ec8Sopenharmony_ci 1546a46c0ec8Sopenharmony_ci /* pick 10 slots as default for type A 1547a46c0ec8Sopenharmony_ci devices. */ 1548a46c0ec8Sopenharmony_ci num_slots = 10; 1549a46c0ec8Sopenharmony_ci active_slot = device->mtdev->caps.slot.value; 1550a46c0ec8Sopenharmony_ci } else { 1551a46c0ec8Sopenharmony_ci num_slots = libevdev_get_num_slots(device->evdev); 1552a46c0ec8Sopenharmony_ci active_slot = libevdev_get_current_slot(evdev); 1553a46c0ec8Sopenharmony_ci } 1554a46c0ec8Sopenharmony_ci 1555a46c0ec8Sopenharmony_ci slots = zalloc(num_slots * sizeof(struct mt_slot)); 1556a46c0ec8Sopenharmony_ci 1557a46c0ec8Sopenharmony_ci for (slot = 0; slot < num_slots; ++slot) { 1558a46c0ec8Sopenharmony_ci slots[slot].seat_slot = -1; 1559a46c0ec8Sopenharmony_ci 1560a46c0ec8Sopenharmony_ci if (evdev_need_mtdev(device)) 1561a46c0ec8Sopenharmony_ci continue; 1562a46c0ec8Sopenharmony_ci 1563a46c0ec8Sopenharmony_ci slots[slot].point.x = libevdev_get_slot_value(evdev, 1564a46c0ec8Sopenharmony_ci slot, 1565a46c0ec8Sopenharmony_ci ABS_MT_POSITION_X); 1566a46c0ec8Sopenharmony_ci slots[slot].point.y = libevdev_get_slot_value(evdev, 1567a46c0ec8Sopenharmony_ci slot, 1568a46c0ec8Sopenharmony_ci ABS_MT_POSITION_Y); 1569a46c0ec8Sopenharmony_ci } 1570a46c0ec8Sopenharmony_ci dispatch->mt.slots = slots; 1571a46c0ec8Sopenharmony_ci dispatch->mt.slots_len = num_slots; 1572a46c0ec8Sopenharmony_ci dispatch->mt.slot = active_slot; 1573a46c0ec8Sopenharmony_ci dispatch->mt.has_palm = libevdev_has_event_code(evdev, 1574a46c0ec8Sopenharmony_ci EV_ABS, 1575a46c0ec8Sopenharmony_ci ABS_MT_TOOL_TYPE); 1576a46c0ec8Sopenharmony_ci 1577a46c0ec8Sopenharmony_ci if (device->abs.absinfo_x->fuzz || device->abs.absinfo_y->fuzz) { 1578a46c0ec8Sopenharmony_ci dispatch->mt.want_hysteresis = true; 1579a46c0ec8Sopenharmony_ci dispatch->mt.hysteresis_margin.x = device->abs.absinfo_x->fuzz/2; 1580a46c0ec8Sopenharmony_ci dispatch->mt.hysteresis_margin.y = device->abs.absinfo_y->fuzz/2; 1581a46c0ec8Sopenharmony_ci } 1582a46c0ec8Sopenharmony_ci 1583a46c0ec8Sopenharmony_ci return 0; 1584a46c0ec8Sopenharmony_ci} 1585a46c0ec8Sopenharmony_ci 1586a46c0ec8Sopenharmony_cistatic inline void 1587a46c0ec8Sopenharmony_cifallback_dispatch_init_rel(struct fallback_dispatch *dispatch, 1588a46c0ec8Sopenharmony_ci struct evdev_device *device) 1589a46c0ec8Sopenharmony_ci{ 1590a46c0ec8Sopenharmony_ci dispatch->rel.x = 0; 1591a46c0ec8Sopenharmony_ci dispatch->rel.y = 0; 1592a46c0ec8Sopenharmony_ci} 1593a46c0ec8Sopenharmony_ci 1594a46c0ec8Sopenharmony_cistatic inline void 1595a46c0ec8Sopenharmony_cifallback_dispatch_init_abs(struct fallback_dispatch *dispatch, 1596a46c0ec8Sopenharmony_ci struct evdev_device *device) 1597a46c0ec8Sopenharmony_ci{ 1598a46c0ec8Sopenharmony_ci if (!libevdev_has_event_code(device->evdev, EV_ABS, ABS_X)) 1599a46c0ec8Sopenharmony_ci return; 1600a46c0ec8Sopenharmony_ci 1601a46c0ec8Sopenharmony_ci dispatch->abs.point.x = device->abs.absinfo_x->value; 1602a46c0ec8Sopenharmony_ci dispatch->abs.point.y = device->abs.absinfo_y->value; 1603a46c0ec8Sopenharmony_ci dispatch->abs.seat_slot = -1; 1604a46c0ec8Sopenharmony_ci 1605a46c0ec8Sopenharmony_ci evdev_device_init_abs_range_warnings(device); 1606a46c0ec8Sopenharmony_ci} 1607a46c0ec8Sopenharmony_ci 1608a46c0ec8Sopenharmony_cistatic inline void 1609a46c0ec8Sopenharmony_cifallback_dispatch_init_switch(struct fallback_dispatch *dispatch, 1610a46c0ec8Sopenharmony_ci struct evdev_device *device) 1611a46c0ec8Sopenharmony_ci{ 1612a46c0ec8Sopenharmony_ci int val; 1613a46c0ec8Sopenharmony_ci 1614a46c0ec8Sopenharmony_ci list_init(&dispatch->lid.paired_keyboard_list); 1615a46c0ec8Sopenharmony_ci 1616a46c0ec8Sopenharmony_ci if (device->tags & EVDEV_TAG_LID_SWITCH) { 1617a46c0ec8Sopenharmony_ci dispatch->lid.reliability = evdev_read_switch_reliability_prop(device); 1618a46c0ec8Sopenharmony_ci dispatch->lid.is_closed = false; 1619a46c0ec8Sopenharmony_ci } 1620a46c0ec8Sopenharmony_ci 1621a46c0ec8Sopenharmony_ci if (device->tags & EVDEV_TAG_TABLET_MODE_SWITCH) { 1622a46c0ec8Sopenharmony_ci val = libevdev_get_event_value(device->evdev, 1623a46c0ec8Sopenharmony_ci EV_SW, 1624a46c0ec8Sopenharmony_ci SW_TABLET_MODE); 1625a46c0ec8Sopenharmony_ci dispatch->tablet_mode.sw.state = val; 1626a46c0ec8Sopenharmony_ci } 1627a46c0ec8Sopenharmony_ci 1628a46c0ec8Sopenharmony_ci libinput_device_init_event_listener(&dispatch->tablet_mode.other.listener); 1629a46c0ec8Sopenharmony_ci} 1630a46c0ec8Sopenharmony_ci 1631a46c0ec8Sopenharmony_cistatic void 1632a46c0ec8Sopenharmony_cifallback_arbitration_timeout(uint64_t now, void *data) 1633a46c0ec8Sopenharmony_ci{ 1634a46c0ec8Sopenharmony_ci struct fallback_dispatch *dispatch = data; 1635a46c0ec8Sopenharmony_ci 1636a46c0ec8Sopenharmony_ci if (dispatch->arbitration.in_arbitration) 1637a46c0ec8Sopenharmony_ci dispatch->arbitration.in_arbitration = false; 1638a46c0ec8Sopenharmony_ci 1639a46c0ec8Sopenharmony_ci evdev_log_debug(dispatch->device, "touch arbitration timeout\n"); 1640a46c0ec8Sopenharmony_ci} 1641a46c0ec8Sopenharmony_ci 1642a46c0ec8Sopenharmony_cistatic void 1643a46c0ec8Sopenharmony_cifallback_init_arbitration(struct fallback_dispatch *dispatch, 1644a46c0ec8Sopenharmony_ci struct evdev_device *device) 1645a46c0ec8Sopenharmony_ci{ 1646a46c0ec8Sopenharmony_ci char timer_name[64]; 1647a46c0ec8Sopenharmony_ci 1648a46c0ec8Sopenharmony_ci snprintf(timer_name, 1649a46c0ec8Sopenharmony_ci sizeof(timer_name), 1650a46c0ec8Sopenharmony_ci "%s arbitration", 1651a46c0ec8Sopenharmony_ci evdev_device_get_sysname(device)); 1652a46c0ec8Sopenharmony_ci libinput_timer_init(&dispatch->arbitration.arbitration_timer, 1653a46c0ec8Sopenharmony_ci evdev_libinput_context(device), 1654a46c0ec8Sopenharmony_ci timer_name, 1655a46c0ec8Sopenharmony_ci fallback_arbitration_timeout, 1656a46c0ec8Sopenharmony_ci dispatch); 1657a46c0ec8Sopenharmony_ci dispatch->arbitration.in_arbitration = false; 1658a46c0ec8Sopenharmony_ci} 1659a46c0ec8Sopenharmony_ci 1660a46c0ec8Sopenharmony_cistruct evdev_dispatch * 1661a46c0ec8Sopenharmony_cifallback_dispatch_create(struct libinput_device *libinput_device) 1662a46c0ec8Sopenharmony_ci{ 1663a46c0ec8Sopenharmony_ci struct evdev_device *device = evdev_device(libinput_device); 1664a46c0ec8Sopenharmony_ci struct fallback_dispatch *dispatch; 1665a46c0ec8Sopenharmony_ci 1666a46c0ec8Sopenharmony_ci dispatch = zalloc(sizeof *dispatch); 1667a46c0ec8Sopenharmony_ci dispatch->device = evdev_device(libinput_device); 1668a46c0ec8Sopenharmony_ci dispatch->base.dispatch_type = DISPATCH_FALLBACK; 1669a46c0ec8Sopenharmony_ci dispatch->base.interface = &fallback_interface; 1670a46c0ec8Sopenharmony_ci dispatch->pending_event = EVDEV_NONE; 1671a46c0ec8Sopenharmony_ci list_init(&dispatch->lid.paired_keyboard_list); 1672a46c0ec8Sopenharmony_ci 1673a46c0ec8Sopenharmony_ci fallback_dispatch_init_rel(dispatch, device); 1674a46c0ec8Sopenharmony_ci fallback_dispatch_init_abs(dispatch, device); 1675a46c0ec8Sopenharmony_ci if (fallback_dispatch_init_slots(dispatch, device) == -1) { 1676a46c0ec8Sopenharmony_ci free(dispatch); 1677a46c0ec8Sopenharmony_ci return NULL; 1678a46c0ec8Sopenharmony_ci } 1679a46c0ec8Sopenharmony_ci 1680a46c0ec8Sopenharmony_ci fallback_dispatch_init_switch(dispatch, device); 1681a46c0ec8Sopenharmony_ci 1682a46c0ec8Sopenharmony_ci if (device->left_handed.want_enabled) 1683a46c0ec8Sopenharmony_ci evdev_init_left_handed(device, 1684a46c0ec8Sopenharmony_ci fallback_change_to_left_handed); 1685a46c0ec8Sopenharmony_ci 1686a46c0ec8Sopenharmony_ci if (device->scroll.want_button) 1687a46c0ec8Sopenharmony_ci evdev_init_button_scroll(device, 1688a46c0ec8Sopenharmony_ci fallback_change_scroll_method); 1689a46c0ec8Sopenharmony_ci 1690a46c0ec8Sopenharmony_ci if (device->scroll.natural_scrolling_enabled) 1691a46c0ec8Sopenharmony_ci evdev_init_natural_scroll(device); 1692a46c0ec8Sopenharmony_ci 1693a46c0ec8Sopenharmony_ci evdev_init_calibration(device, &dispatch->calibration); 1694a46c0ec8Sopenharmony_ci evdev_init_sendevents(device, &dispatch->base); 1695a46c0ec8Sopenharmony_ci fallback_init_rotation(dispatch, device); 1696a46c0ec8Sopenharmony_ci 1697a46c0ec8Sopenharmony_ci /* BTN_MIDDLE is set on mice even when it's not present. So 1698a46c0ec8Sopenharmony_ci * we can only use the absence of BTN_MIDDLE to mean something, i.e. 1699a46c0ec8Sopenharmony_ci * we enable it by default on anything that only has L&R. 1700a46c0ec8Sopenharmony_ci * If we have L&R and no middle, we don't expose it as config 1701a46c0ec8Sopenharmony_ci * option */ 1702a46c0ec8Sopenharmony_ci if (libevdev_has_event_code(device->evdev, EV_KEY, BTN_LEFT) && 1703a46c0ec8Sopenharmony_ci libevdev_has_event_code(device->evdev, EV_KEY, BTN_RIGHT)) { 1704a46c0ec8Sopenharmony_ci bool has_middle = libevdev_has_event_code(device->evdev, 1705a46c0ec8Sopenharmony_ci EV_KEY, 1706a46c0ec8Sopenharmony_ci BTN_MIDDLE); 1707a46c0ec8Sopenharmony_ci bool want_config = has_middle; 1708a46c0ec8Sopenharmony_ci bool enable_by_default = !has_middle; 1709a46c0ec8Sopenharmony_ci 1710a46c0ec8Sopenharmony_ci evdev_init_middlebutton(device, 1711a46c0ec8Sopenharmony_ci enable_by_default, 1712a46c0ec8Sopenharmony_ci want_config); 1713a46c0ec8Sopenharmony_ci } 1714a46c0ec8Sopenharmony_ci 1715a46c0ec8Sopenharmony_ci fallback_init_wheel(dispatch, device); 1716a46c0ec8Sopenharmony_ci fallback_init_debounce(dispatch); 1717a46c0ec8Sopenharmony_ci fallback_init_arbitration(dispatch, device); 1718a46c0ec8Sopenharmony_ci 1719a46c0ec8Sopenharmony_ci return &dispatch->base; 1720a46c0ec8Sopenharmony_ci} 1721