1a46c0ec8Sopenharmony_ci/* 2a46c0ec8Sopenharmony_ci * Copyright © 2018 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#include "evdev.h" 26a46c0ec8Sopenharmony_ci 27a46c0ec8Sopenharmony_cienum totem_slot_state { 28a46c0ec8Sopenharmony_ci SLOT_STATE_NONE, 29a46c0ec8Sopenharmony_ci SLOT_STATE_BEGIN, 30a46c0ec8Sopenharmony_ci SLOT_STATE_UPDATE, 31a46c0ec8Sopenharmony_ci SLOT_STATE_END, 32a46c0ec8Sopenharmony_ci}; 33a46c0ec8Sopenharmony_ci 34a46c0ec8Sopenharmony_cistruct totem_slot { 35a46c0ec8Sopenharmony_ci bool dirty; 36a46c0ec8Sopenharmony_ci unsigned int index; 37a46c0ec8Sopenharmony_ci enum totem_slot_state state; 38a46c0ec8Sopenharmony_ci struct libinput_tablet_tool *tool; 39a46c0ec8Sopenharmony_ci struct tablet_axes axes; 40a46c0ec8Sopenharmony_ci unsigned char changed_axes[NCHARS(LIBINPUT_TABLET_TOOL_AXIS_MAX + 1)]; 41a46c0ec8Sopenharmony_ci 42a46c0ec8Sopenharmony_ci struct device_coords last_point; 43a46c0ec8Sopenharmony_ci}; 44a46c0ec8Sopenharmony_ci 45a46c0ec8Sopenharmony_cistruct totem_dispatch { 46a46c0ec8Sopenharmony_ci struct evdev_dispatch base; 47a46c0ec8Sopenharmony_ci struct evdev_device *device; 48a46c0ec8Sopenharmony_ci 49a46c0ec8Sopenharmony_ci int slot; /* current slot */ 50a46c0ec8Sopenharmony_ci struct totem_slot *slots; 51a46c0ec8Sopenharmony_ci size_t nslots; 52a46c0ec8Sopenharmony_ci 53a46c0ec8Sopenharmony_ci struct evdev_device *touch_device; 54a46c0ec8Sopenharmony_ci 55a46c0ec8Sopenharmony_ci /* We only have one button */ 56a46c0ec8Sopenharmony_ci bool button_state_now; 57a46c0ec8Sopenharmony_ci bool button_state_previous; 58a46c0ec8Sopenharmony_ci 59a46c0ec8Sopenharmony_ci enum evdev_arbitration_state arbitration_state; 60a46c0ec8Sopenharmony_ci}; 61a46c0ec8Sopenharmony_ci 62a46c0ec8Sopenharmony_cistatic inline struct totem_dispatch* 63a46c0ec8Sopenharmony_citotem_dispatch(struct evdev_dispatch *totem) 64a46c0ec8Sopenharmony_ci{ 65a46c0ec8Sopenharmony_ci evdev_verify_dispatch_type(totem, DISPATCH_TOTEM); 66a46c0ec8Sopenharmony_ci 67a46c0ec8Sopenharmony_ci return container_of(totem, struct totem_dispatch, base); 68a46c0ec8Sopenharmony_ci} 69a46c0ec8Sopenharmony_ci 70a46c0ec8Sopenharmony_cistatic inline struct libinput * 71a46c0ec8Sopenharmony_citotem_libinput_context(const struct totem_dispatch *totem) 72a46c0ec8Sopenharmony_ci{ 73a46c0ec8Sopenharmony_ci return evdev_libinput_context(totem->device); 74a46c0ec8Sopenharmony_ci} 75a46c0ec8Sopenharmony_ci 76a46c0ec8Sopenharmony_cistatic struct libinput_tablet_tool * 77a46c0ec8Sopenharmony_citotem_new_tool(struct totem_dispatch *totem) 78a46c0ec8Sopenharmony_ci{ 79a46c0ec8Sopenharmony_ci struct libinput *libinput = totem_libinput_context(totem); 80a46c0ec8Sopenharmony_ci struct libinput_tablet_tool *tool; 81a46c0ec8Sopenharmony_ci 82a46c0ec8Sopenharmony_ci tool = zalloc(sizeof *tool); 83a46c0ec8Sopenharmony_ci 84a46c0ec8Sopenharmony_ci *tool = (struct libinput_tablet_tool) { 85a46c0ec8Sopenharmony_ci .type = LIBINPUT_TABLET_TOOL_TYPE_TOTEM, 86a46c0ec8Sopenharmony_ci .serial = 0, 87a46c0ec8Sopenharmony_ci .tool_id = 0, 88a46c0ec8Sopenharmony_ci .refcount = 1, 89a46c0ec8Sopenharmony_ci }; 90a46c0ec8Sopenharmony_ci 91a46c0ec8Sopenharmony_ci tool->pressure.offset = 0; 92a46c0ec8Sopenharmony_ci tool->pressure.has_offset = false; 93a46c0ec8Sopenharmony_ci tool->pressure.threshold.lower = 0; 94a46c0ec8Sopenharmony_ci tool->pressure.threshold.upper = 1; 95a46c0ec8Sopenharmony_ci 96a46c0ec8Sopenharmony_ci set_bit(tool->axis_caps, LIBINPUT_TABLET_TOOL_AXIS_X); 97a46c0ec8Sopenharmony_ci set_bit(tool->axis_caps, LIBINPUT_TABLET_TOOL_AXIS_Y); 98a46c0ec8Sopenharmony_ci set_bit(tool->axis_caps, LIBINPUT_TABLET_TOOL_AXIS_ROTATION_Z); 99a46c0ec8Sopenharmony_ci set_bit(tool->axis_caps, LIBINPUT_TABLET_TOOL_AXIS_SIZE_MAJOR); 100a46c0ec8Sopenharmony_ci set_bit(tool->axis_caps, LIBINPUT_TABLET_TOOL_AXIS_SIZE_MINOR); 101a46c0ec8Sopenharmony_ci set_bit(tool->buttons, BTN_0); 102a46c0ec8Sopenharmony_ci 103a46c0ec8Sopenharmony_ci list_insert(&libinput->tool_list, &tool->link); 104a46c0ec8Sopenharmony_ci 105a46c0ec8Sopenharmony_ci return tool; 106a46c0ec8Sopenharmony_ci} 107a46c0ec8Sopenharmony_ci 108a46c0ec8Sopenharmony_cistatic inline void 109a46c0ec8Sopenharmony_citotem_set_touch_device_enabled(struct totem_dispatch *totem, 110a46c0ec8Sopenharmony_ci bool enable_touch_device, 111a46c0ec8Sopenharmony_ci uint64_t time) 112a46c0ec8Sopenharmony_ci{ 113a46c0ec8Sopenharmony_ci struct evdev_device *touch_device = totem->touch_device; 114a46c0ec8Sopenharmony_ci struct evdev_dispatch *dispatch; 115a46c0ec8Sopenharmony_ci struct phys_rect r, *rect = NULL; 116a46c0ec8Sopenharmony_ci enum evdev_arbitration_state state = ARBITRATION_NOT_ACTIVE; 117a46c0ec8Sopenharmony_ci 118a46c0ec8Sopenharmony_ci if (touch_device == NULL) 119a46c0ec8Sopenharmony_ci return; 120a46c0ec8Sopenharmony_ci 121a46c0ec8Sopenharmony_ci /* We just pick the coordinates of the first touch we find. The 122a46c0ec8Sopenharmony_ci * totem only does one tool right now despite being nominally an MT 123a46c0ec8Sopenharmony_ci * device, so let's not go too hard on ourselves*/ 124a46c0ec8Sopenharmony_ci for (size_t i = 0; !enable_touch_device && i < totem->nslots; i++) { 125a46c0ec8Sopenharmony_ci struct totem_slot *slot = &totem->slots[i]; 126a46c0ec8Sopenharmony_ci struct phys_coords mm; 127a46c0ec8Sopenharmony_ci 128a46c0ec8Sopenharmony_ci if (slot->state == SLOT_STATE_NONE) 129a46c0ec8Sopenharmony_ci continue; 130a46c0ec8Sopenharmony_ci 131a46c0ec8Sopenharmony_ci /* Totem size is ~70mm. We could calculate the real size but 132a46c0ec8Sopenharmony_ci until we need that, hardcoding it is enough */ 133a46c0ec8Sopenharmony_ci mm = evdev_device_units_to_mm(totem->device, &slot->axes.point); 134a46c0ec8Sopenharmony_ci r.x = mm.x - 30; 135a46c0ec8Sopenharmony_ci r.y = mm.y - 30; 136a46c0ec8Sopenharmony_ci r.w = 100; 137a46c0ec8Sopenharmony_ci r.h = 100; 138a46c0ec8Sopenharmony_ci 139a46c0ec8Sopenharmony_ci rect = &r; 140a46c0ec8Sopenharmony_ci 141a46c0ec8Sopenharmony_ci state = ARBITRATION_IGNORE_RECT; 142a46c0ec8Sopenharmony_ci break; 143a46c0ec8Sopenharmony_ci } 144a46c0ec8Sopenharmony_ci 145a46c0ec8Sopenharmony_ci dispatch = touch_device->dispatch; 146a46c0ec8Sopenharmony_ci 147a46c0ec8Sopenharmony_ci if (enable_touch_device) { 148a46c0ec8Sopenharmony_ci if (dispatch->interface->touch_arbitration_toggle) 149a46c0ec8Sopenharmony_ci dispatch->interface->touch_arbitration_toggle(dispatch, 150a46c0ec8Sopenharmony_ci touch_device, 151a46c0ec8Sopenharmony_ci state, 152a46c0ec8Sopenharmony_ci rect, 153a46c0ec8Sopenharmony_ci time); 154a46c0ec8Sopenharmony_ci } else { 155a46c0ec8Sopenharmony_ci switch (totem->arbitration_state) { 156a46c0ec8Sopenharmony_ci case ARBITRATION_IGNORE_ALL: 157a46c0ec8Sopenharmony_ci abort(); 158a46c0ec8Sopenharmony_ci case ARBITRATION_NOT_ACTIVE: 159a46c0ec8Sopenharmony_ci if (dispatch->interface->touch_arbitration_toggle) 160a46c0ec8Sopenharmony_ci dispatch->interface->touch_arbitration_toggle(dispatch, 161a46c0ec8Sopenharmony_ci touch_device, 162a46c0ec8Sopenharmony_ci state, 163a46c0ec8Sopenharmony_ci rect, 164a46c0ec8Sopenharmony_ci time); 165a46c0ec8Sopenharmony_ci break; 166a46c0ec8Sopenharmony_ci case ARBITRATION_IGNORE_RECT: 167a46c0ec8Sopenharmony_ci if (dispatch->interface->touch_arbitration_update_rect) 168a46c0ec8Sopenharmony_ci dispatch->interface->touch_arbitration_update_rect(dispatch, 169a46c0ec8Sopenharmony_ci touch_device, 170a46c0ec8Sopenharmony_ci rect, 171a46c0ec8Sopenharmony_ci time); 172a46c0ec8Sopenharmony_ci break; 173a46c0ec8Sopenharmony_ci } 174a46c0ec8Sopenharmony_ci } 175a46c0ec8Sopenharmony_ci totem->arbitration_state = state; 176a46c0ec8Sopenharmony_ci} 177a46c0ec8Sopenharmony_ci 178a46c0ec8Sopenharmony_cistatic void 179a46c0ec8Sopenharmony_citotem_process_key(struct totem_dispatch *totem, 180a46c0ec8Sopenharmony_ci struct evdev_device *device, 181a46c0ec8Sopenharmony_ci struct input_event *e, 182a46c0ec8Sopenharmony_ci uint64_t time) 183a46c0ec8Sopenharmony_ci{ 184a46c0ec8Sopenharmony_ci /* ignore kernel key repeat */ 185a46c0ec8Sopenharmony_ci if (e->value == 2) 186a46c0ec8Sopenharmony_ci return; 187a46c0ec8Sopenharmony_ci 188a46c0ec8Sopenharmony_ci switch(e->code) { 189a46c0ec8Sopenharmony_ci case BTN_0: 190a46c0ec8Sopenharmony_ci totem->button_state_now = !!e->value; 191a46c0ec8Sopenharmony_ci break; 192a46c0ec8Sopenharmony_ci default: 193a46c0ec8Sopenharmony_ci evdev_log_info(device, 194a46c0ec8Sopenharmony_ci "Unhandled KEY event code %#x\n", 195a46c0ec8Sopenharmony_ci e->code); 196a46c0ec8Sopenharmony_ci break; 197a46c0ec8Sopenharmony_ci } 198a46c0ec8Sopenharmony_ci} 199a46c0ec8Sopenharmony_ci 200a46c0ec8Sopenharmony_cistatic void 201a46c0ec8Sopenharmony_citotem_process_abs(struct totem_dispatch *totem, 202a46c0ec8Sopenharmony_ci struct evdev_device *device, 203a46c0ec8Sopenharmony_ci struct input_event *e, 204a46c0ec8Sopenharmony_ci uint64_t time) 205a46c0ec8Sopenharmony_ci{ 206a46c0ec8Sopenharmony_ci struct totem_slot *slot = &totem->slots[totem->slot]; 207a46c0ec8Sopenharmony_ci 208a46c0ec8Sopenharmony_ci switch(e->code) { 209a46c0ec8Sopenharmony_ci case ABS_MT_SLOT: 210a46c0ec8Sopenharmony_ci if ((size_t)e->value >= totem->nslots) { 211a46c0ec8Sopenharmony_ci evdev_log_bug_libinput(device, 212a46c0ec8Sopenharmony_ci "exceeded slot count (%d of max %zd)\n", 213a46c0ec8Sopenharmony_ci e->value, 214a46c0ec8Sopenharmony_ci totem->nslots); 215a46c0ec8Sopenharmony_ci e->value = totem->nslots - 1; 216a46c0ec8Sopenharmony_ci } 217a46c0ec8Sopenharmony_ci totem->slot = e->value; 218a46c0ec8Sopenharmony_ci return; 219a46c0ec8Sopenharmony_ci case ABS_MT_TRACKING_ID: 220a46c0ec8Sopenharmony_ci /* If the totem is already down on init, we currently 221a46c0ec8Sopenharmony_ci ignore it */ 222a46c0ec8Sopenharmony_ci if (e->value >= 0) 223a46c0ec8Sopenharmony_ci slot->state = SLOT_STATE_BEGIN; 224a46c0ec8Sopenharmony_ci else if (slot->state != SLOT_STATE_NONE) 225a46c0ec8Sopenharmony_ci slot->state = SLOT_STATE_END; 226a46c0ec8Sopenharmony_ci break; 227a46c0ec8Sopenharmony_ci case ABS_MT_POSITION_X: 228a46c0ec8Sopenharmony_ci set_bit(slot->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_X); 229a46c0ec8Sopenharmony_ci break; 230a46c0ec8Sopenharmony_ci case ABS_MT_POSITION_Y: 231a46c0ec8Sopenharmony_ci set_bit(slot->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_Y); 232a46c0ec8Sopenharmony_ci break; 233a46c0ec8Sopenharmony_ci case ABS_MT_TOUCH_MAJOR: 234a46c0ec8Sopenharmony_ci set_bit(slot->changed_axes, 235a46c0ec8Sopenharmony_ci LIBINPUT_TABLET_TOOL_AXIS_SIZE_MAJOR); 236a46c0ec8Sopenharmony_ci break; 237a46c0ec8Sopenharmony_ci case ABS_MT_TOUCH_MINOR: 238a46c0ec8Sopenharmony_ci set_bit(slot->changed_axes, 239a46c0ec8Sopenharmony_ci LIBINPUT_TABLET_TOOL_AXIS_SIZE_MINOR); 240a46c0ec8Sopenharmony_ci break; 241a46c0ec8Sopenharmony_ci case ABS_MT_ORIENTATION: 242a46c0ec8Sopenharmony_ci set_bit(slot->changed_axes, 243a46c0ec8Sopenharmony_ci LIBINPUT_TABLET_TOOL_AXIS_ROTATION_Z); 244a46c0ec8Sopenharmony_ci break; 245a46c0ec8Sopenharmony_ci case ABS_MT_TOOL_TYPE: 246a46c0ec8Sopenharmony_ci if (e->value != MT_TOOL_DIAL) { 247a46c0ec8Sopenharmony_ci evdev_log_info(device, 248a46c0ec8Sopenharmony_ci "Unexpected tool type %#x, changing to dial\n", 249a46c0ec8Sopenharmony_ci e->code); 250a46c0ec8Sopenharmony_ci } 251a46c0ec8Sopenharmony_ci break; 252a46c0ec8Sopenharmony_ci default: 253a46c0ec8Sopenharmony_ci evdev_log_info(device, 254a46c0ec8Sopenharmony_ci "Unhandled ABS event code %#x\n", 255a46c0ec8Sopenharmony_ci e->code); 256a46c0ec8Sopenharmony_ci break; 257a46c0ec8Sopenharmony_ci } 258a46c0ec8Sopenharmony_ci} 259a46c0ec8Sopenharmony_ci 260a46c0ec8Sopenharmony_cistatic bool 261a46c0ec8Sopenharmony_citotem_slot_fetch_axes(struct totem_dispatch *totem, 262a46c0ec8Sopenharmony_ci struct totem_slot *slot, 263a46c0ec8Sopenharmony_ci struct libinput_tablet_tool *tool, 264a46c0ec8Sopenharmony_ci struct tablet_axes *axes_out, 265a46c0ec8Sopenharmony_ci uint64_t time) 266a46c0ec8Sopenharmony_ci{ 267a46c0ec8Sopenharmony_ci struct evdev_device *device = totem->device; 268a46c0ec8Sopenharmony_ci const char tmp[sizeof(slot->changed_axes)] = {0}; 269a46c0ec8Sopenharmony_ci struct tablet_axes axes = {0}; 270a46c0ec8Sopenharmony_ci struct device_float_coords delta; 271a46c0ec8Sopenharmony_ci bool rc = false; 272a46c0ec8Sopenharmony_ci 273a46c0ec8Sopenharmony_ci if (memcmp(tmp, slot->changed_axes, sizeof(tmp)) == 0) { 274a46c0ec8Sopenharmony_ci axes = slot->axes; 275a46c0ec8Sopenharmony_ci goto out; 276a46c0ec8Sopenharmony_ci } 277a46c0ec8Sopenharmony_ci 278a46c0ec8Sopenharmony_ci if (bit_is_set(slot->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_X) || 279a46c0ec8Sopenharmony_ci bit_is_set(slot->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_Y)) { 280a46c0ec8Sopenharmony_ci slot->axes.point.x = libevdev_get_slot_value(device->evdev, 281a46c0ec8Sopenharmony_ci slot->index, 282a46c0ec8Sopenharmony_ci ABS_MT_POSITION_X); 283a46c0ec8Sopenharmony_ci slot->axes.point.y = libevdev_get_slot_value(device->evdev, 284a46c0ec8Sopenharmony_ci slot->index, 285a46c0ec8Sopenharmony_ci ABS_MT_POSITION_Y); 286a46c0ec8Sopenharmony_ci } 287a46c0ec8Sopenharmony_ci 288a46c0ec8Sopenharmony_ci if (bit_is_set(slot->changed_axes, 289a46c0ec8Sopenharmony_ci LIBINPUT_TABLET_TOOL_AXIS_ROTATION_Z)) { 290a46c0ec8Sopenharmony_ci int angle = libevdev_get_slot_value(device->evdev, 291a46c0ec8Sopenharmony_ci slot->index, 292a46c0ec8Sopenharmony_ci ABS_MT_ORIENTATION); 293a46c0ec8Sopenharmony_ci /* The kernel gives us ±90 degrees off neutral */ 294a46c0ec8Sopenharmony_ci slot->axes.rotation = (360 - angle) % 360; 295a46c0ec8Sopenharmony_ci } 296a46c0ec8Sopenharmony_ci 297a46c0ec8Sopenharmony_ci if (bit_is_set(slot->changed_axes, 298a46c0ec8Sopenharmony_ci LIBINPUT_TABLET_TOOL_AXIS_SIZE_MAJOR) || 299a46c0ec8Sopenharmony_ci bit_is_set(slot->changed_axes, 300a46c0ec8Sopenharmony_ci LIBINPUT_TABLET_TOOL_AXIS_SIZE_MINOR)) { 301a46c0ec8Sopenharmony_ci int major, minor; 302a46c0ec8Sopenharmony_ci unsigned int rmajor, rminor; 303a46c0ec8Sopenharmony_ci 304a46c0ec8Sopenharmony_ci major = libevdev_get_slot_value(device->evdev, 305a46c0ec8Sopenharmony_ci slot->index, 306a46c0ec8Sopenharmony_ci ABS_MT_TOUCH_MAJOR); 307a46c0ec8Sopenharmony_ci minor = libevdev_get_slot_value(device->evdev, 308a46c0ec8Sopenharmony_ci slot->index, 309a46c0ec8Sopenharmony_ci ABS_MT_TOUCH_MINOR); 310a46c0ec8Sopenharmony_ci rmajor = libevdev_get_abs_resolution(device->evdev, ABS_MT_TOUCH_MAJOR); 311a46c0ec8Sopenharmony_ci rminor = libevdev_get_abs_resolution(device->evdev, ABS_MT_TOUCH_MINOR); 312a46c0ec8Sopenharmony_ci slot->axes.size.major = (double)major/rmajor; 313a46c0ec8Sopenharmony_ci slot->axes.size.minor = (double)minor/rminor; 314a46c0ec8Sopenharmony_ci } 315a46c0ec8Sopenharmony_ci 316a46c0ec8Sopenharmony_ci axes.point = slot->axes.point; 317a46c0ec8Sopenharmony_ci axes.rotation = slot->axes.rotation; 318a46c0ec8Sopenharmony_ci axes.size = slot->axes.size; 319a46c0ec8Sopenharmony_ci 320a46c0ec8Sopenharmony_ci delta.x = slot->axes.point.x - slot->last_point.x; 321a46c0ec8Sopenharmony_ci delta.y = slot->axes.point.y - slot->last_point.y; 322a46c0ec8Sopenharmony_ci axes.delta = filter_dispatch(device->pointer.filter, &delta, tool, time); 323a46c0ec8Sopenharmony_ci 324a46c0ec8Sopenharmony_ci rc = true; 325a46c0ec8Sopenharmony_ciout: 326a46c0ec8Sopenharmony_ci *axes_out = axes; 327a46c0ec8Sopenharmony_ci return rc; 328a46c0ec8Sopenharmony_ci 329a46c0ec8Sopenharmony_ci} 330a46c0ec8Sopenharmony_ci 331a46c0ec8Sopenharmony_cistatic void 332a46c0ec8Sopenharmony_citotem_slot_mark_all_axes_changed(struct totem_dispatch *totem, 333a46c0ec8Sopenharmony_ci struct totem_slot *slot, 334a46c0ec8Sopenharmony_ci struct libinput_tablet_tool *tool) 335a46c0ec8Sopenharmony_ci{ 336a46c0ec8Sopenharmony_ci static_assert(sizeof(slot->changed_axes) == 337a46c0ec8Sopenharmony_ci sizeof(tool->axis_caps), 338a46c0ec8Sopenharmony_ci "Mismatching array sizes"); 339a46c0ec8Sopenharmony_ci 340a46c0ec8Sopenharmony_ci memcpy(slot->changed_axes, 341a46c0ec8Sopenharmony_ci tool->axis_caps, 342a46c0ec8Sopenharmony_ci sizeof(slot->changed_axes)); 343a46c0ec8Sopenharmony_ci} 344a46c0ec8Sopenharmony_ci 345a46c0ec8Sopenharmony_cistatic inline void 346a46c0ec8Sopenharmony_citotem_slot_reset_changed_axes(struct totem_dispatch *totem, 347a46c0ec8Sopenharmony_ci struct totem_slot *slot) 348a46c0ec8Sopenharmony_ci{ 349a46c0ec8Sopenharmony_ci memset(slot->changed_axes, 0, sizeof(slot->changed_axes)); 350a46c0ec8Sopenharmony_ci} 351a46c0ec8Sopenharmony_ci 352a46c0ec8Sopenharmony_cistatic inline void 353a46c0ec8Sopenharmony_cislot_axes_initialize(struct totem_dispatch *totem, 354a46c0ec8Sopenharmony_ci struct totem_slot *slot) 355a46c0ec8Sopenharmony_ci{ 356a46c0ec8Sopenharmony_ci struct evdev_device *device = totem->device; 357a46c0ec8Sopenharmony_ci 358a46c0ec8Sopenharmony_ci slot->axes.point.x = libevdev_get_slot_value(device->evdev, 359a46c0ec8Sopenharmony_ci slot->index, 360a46c0ec8Sopenharmony_ci ABS_MT_POSITION_X); 361a46c0ec8Sopenharmony_ci slot->axes.point.y = libevdev_get_slot_value(device->evdev, 362a46c0ec8Sopenharmony_ci slot->index, 363a46c0ec8Sopenharmony_ci ABS_MT_POSITION_Y); 364a46c0ec8Sopenharmony_ci slot->last_point.x = slot->axes.point.x; 365a46c0ec8Sopenharmony_ci slot->last_point.y = slot->axes.point.y; 366a46c0ec8Sopenharmony_ci} 367a46c0ec8Sopenharmony_ci 368a46c0ec8Sopenharmony_cistatic enum totem_slot_state 369a46c0ec8Sopenharmony_citotem_handle_slot_state(struct totem_dispatch *totem, 370a46c0ec8Sopenharmony_ci struct totem_slot *slot, 371a46c0ec8Sopenharmony_ci uint64_t time) 372a46c0ec8Sopenharmony_ci{ 373a46c0ec8Sopenharmony_ci struct evdev_device *device = totem->device; 374a46c0ec8Sopenharmony_ci struct tablet_axes axes; 375a46c0ec8Sopenharmony_ci enum libinput_tablet_tool_tip_state tip_state; 376a46c0ec8Sopenharmony_ci bool updated; 377a46c0ec8Sopenharmony_ci 378a46c0ec8Sopenharmony_ci switch (slot->state) { 379a46c0ec8Sopenharmony_ci case SLOT_STATE_BEGIN: 380a46c0ec8Sopenharmony_ci if (!slot->tool) 381a46c0ec8Sopenharmony_ci slot->tool = totem_new_tool(totem); 382a46c0ec8Sopenharmony_ci slot_axes_initialize(totem, slot); 383a46c0ec8Sopenharmony_ci totem_slot_mark_all_axes_changed(totem, slot, slot->tool); 384a46c0ec8Sopenharmony_ci break; 385a46c0ec8Sopenharmony_ci case SLOT_STATE_UPDATE: 386a46c0ec8Sopenharmony_ci case SLOT_STATE_END: 387a46c0ec8Sopenharmony_ci assert(slot->tool); 388a46c0ec8Sopenharmony_ci break; 389a46c0ec8Sopenharmony_ci case SLOT_STATE_NONE: 390a46c0ec8Sopenharmony_ci return SLOT_STATE_NONE; 391a46c0ec8Sopenharmony_ci } 392a46c0ec8Sopenharmony_ci 393a46c0ec8Sopenharmony_ci tip_state = LIBINPUT_TABLET_TOOL_TIP_UP; 394a46c0ec8Sopenharmony_ci updated = totem_slot_fetch_axes(totem, slot, slot->tool, &axes, time); 395a46c0ec8Sopenharmony_ci 396a46c0ec8Sopenharmony_ci switch (slot->state) { 397a46c0ec8Sopenharmony_ci case SLOT_STATE_BEGIN: 398a46c0ec8Sopenharmony_ci tip_state = LIBINPUT_TABLET_TOOL_TIP_DOWN; 399a46c0ec8Sopenharmony_ci tablet_notify_proximity(&device->base, 400a46c0ec8Sopenharmony_ci time, 401a46c0ec8Sopenharmony_ci slot->tool, 402a46c0ec8Sopenharmony_ci LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN, 403a46c0ec8Sopenharmony_ci slot->changed_axes, 404a46c0ec8Sopenharmony_ci &axes); 405a46c0ec8Sopenharmony_ci totem_slot_reset_changed_axes(totem, slot); 406a46c0ec8Sopenharmony_ci tablet_notify_tip(&device->base, 407a46c0ec8Sopenharmony_ci time, 408a46c0ec8Sopenharmony_ci slot->tool, 409a46c0ec8Sopenharmony_ci tip_state, 410a46c0ec8Sopenharmony_ci slot->changed_axes, 411a46c0ec8Sopenharmony_ci &axes); 412a46c0ec8Sopenharmony_ci slot->state = SLOT_STATE_UPDATE; 413a46c0ec8Sopenharmony_ci break; 414a46c0ec8Sopenharmony_ci case SLOT_STATE_UPDATE: 415a46c0ec8Sopenharmony_ci tip_state = LIBINPUT_TABLET_TOOL_TIP_DOWN; 416a46c0ec8Sopenharmony_ci if (updated) { 417a46c0ec8Sopenharmony_ci tablet_notify_axis(&device->base, 418a46c0ec8Sopenharmony_ci time, 419a46c0ec8Sopenharmony_ci slot->tool, 420a46c0ec8Sopenharmony_ci tip_state, 421a46c0ec8Sopenharmony_ci slot->changed_axes, 422a46c0ec8Sopenharmony_ci &axes); 423a46c0ec8Sopenharmony_ci } 424a46c0ec8Sopenharmony_ci break; 425a46c0ec8Sopenharmony_ci case SLOT_STATE_END: 426a46c0ec8Sopenharmony_ci /* prox out is handled after button events */ 427a46c0ec8Sopenharmony_ci break; 428a46c0ec8Sopenharmony_ci case SLOT_STATE_NONE: 429a46c0ec8Sopenharmony_ci abort(); 430a46c0ec8Sopenharmony_ci break; 431a46c0ec8Sopenharmony_ci } 432a46c0ec8Sopenharmony_ci 433a46c0ec8Sopenharmony_ci /* We only have one button but possibly multiple totems. It's not 434a46c0ec8Sopenharmony_ci * clear how the firmware will work, so for now we just handle the 435a46c0ec8Sopenharmony_ci * button state in the first slot. 436a46c0ec8Sopenharmony_ci * 437a46c0ec8Sopenharmony_ci * Due to the design of the totem we're also less fancy about 438a46c0ec8Sopenharmony_ci * button handling than the tablet code. Worst case, you might get 439a46c0ec8Sopenharmony_ci * tip up before button up but meh. 440a46c0ec8Sopenharmony_ci */ 441a46c0ec8Sopenharmony_ci if (totem->button_state_now != totem->button_state_previous) { 442a46c0ec8Sopenharmony_ci enum libinput_button_state btn_state; 443a46c0ec8Sopenharmony_ci 444a46c0ec8Sopenharmony_ci if (totem->button_state_now) 445a46c0ec8Sopenharmony_ci btn_state = LIBINPUT_BUTTON_STATE_PRESSED; 446a46c0ec8Sopenharmony_ci else 447a46c0ec8Sopenharmony_ci btn_state = LIBINPUT_BUTTON_STATE_RELEASED; 448a46c0ec8Sopenharmony_ci 449a46c0ec8Sopenharmony_ci tablet_notify_button(&device->base, 450a46c0ec8Sopenharmony_ci time, 451a46c0ec8Sopenharmony_ci slot->tool, 452a46c0ec8Sopenharmony_ci tip_state, 453a46c0ec8Sopenharmony_ci &axes, 454a46c0ec8Sopenharmony_ci BTN_0, 455a46c0ec8Sopenharmony_ci btn_state); 456a46c0ec8Sopenharmony_ci 457a46c0ec8Sopenharmony_ci totem->button_state_previous = totem->button_state_now; 458a46c0ec8Sopenharmony_ci } 459a46c0ec8Sopenharmony_ci 460a46c0ec8Sopenharmony_ci switch(slot->state) { 461a46c0ec8Sopenharmony_ci case SLOT_STATE_BEGIN: 462a46c0ec8Sopenharmony_ci case SLOT_STATE_UPDATE: 463a46c0ec8Sopenharmony_ci break; 464a46c0ec8Sopenharmony_ci case SLOT_STATE_END: 465a46c0ec8Sopenharmony_ci tip_state = LIBINPUT_TABLET_TOOL_TIP_UP; 466a46c0ec8Sopenharmony_ci tablet_notify_tip(&device->base, 467a46c0ec8Sopenharmony_ci time, 468a46c0ec8Sopenharmony_ci slot->tool, 469a46c0ec8Sopenharmony_ci tip_state, 470a46c0ec8Sopenharmony_ci slot->changed_axes, 471a46c0ec8Sopenharmony_ci &axes); 472a46c0ec8Sopenharmony_ci totem_slot_reset_changed_axes(totem, slot); 473a46c0ec8Sopenharmony_ci tablet_notify_proximity(&device->base, 474a46c0ec8Sopenharmony_ci time, 475a46c0ec8Sopenharmony_ci slot->tool, 476a46c0ec8Sopenharmony_ci LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT, 477a46c0ec8Sopenharmony_ci slot->changed_axes, 478a46c0ec8Sopenharmony_ci &axes); 479a46c0ec8Sopenharmony_ci slot->state = SLOT_STATE_NONE; 480a46c0ec8Sopenharmony_ci break; 481a46c0ec8Sopenharmony_ci case SLOT_STATE_NONE: 482a46c0ec8Sopenharmony_ci abort(); 483a46c0ec8Sopenharmony_ci break; 484a46c0ec8Sopenharmony_ci } 485a46c0ec8Sopenharmony_ci 486a46c0ec8Sopenharmony_ci slot->last_point = slot->axes.point; 487a46c0ec8Sopenharmony_ci totem_slot_reset_changed_axes(totem, slot); 488a46c0ec8Sopenharmony_ci 489a46c0ec8Sopenharmony_ci return slot->state; 490a46c0ec8Sopenharmony_ci} 491a46c0ec8Sopenharmony_ci 492a46c0ec8Sopenharmony_cistatic enum totem_slot_state 493a46c0ec8Sopenharmony_citotem_handle_state(struct totem_dispatch *totem, 494a46c0ec8Sopenharmony_ci uint64_t time) 495a46c0ec8Sopenharmony_ci{ 496a46c0ec8Sopenharmony_ci enum totem_slot_state global_state = SLOT_STATE_NONE; 497a46c0ec8Sopenharmony_ci 498a46c0ec8Sopenharmony_ci for (size_t i = 0; i < totem->nslots; i++) { 499a46c0ec8Sopenharmony_ci enum totem_slot_state s; 500a46c0ec8Sopenharmony_ci 501a46c0ec8Sopenharmony_ci s = totem_handle_slot_state(totem, 502a46c0ec8Sopenharmony_ci &totem->slots[i], 503a46c0ec8Sopenharmony_ci time); 504a46c0ec8Sopenharmony_ci 505a46c0ec8Sopenharmony_ci /* If one slot is active, the totem is active */ 506a46c0ec8Sopenharmony_ci if (s != SLOT_STATE_NONE) 507a46c0ec8Sopenharmony_ci global_state = SLOT_STATE_UPDATE; 508a46c0ec8Sopenharmony_ci } 509a46c0ec8Sopenharmony_ci 510a46c0ec8Sopenharmony_ci return global_state; 511a46c0ec8Sopenharmony_ci} 512a46c0ec8Sopenharmony_ci 513a46c0ec8Sopenharmony_cistatic void 514a46c0ec8Sopenharmony_citotem_interface_process(struct evdev_dispatch *dispatch, 515a46c0ec8Sopenharmony_ci struct evdev_device *device, 516a46c0ec8Sopenharmony_ci struct input_event *e, 517a46c0ec8Sopenharmony_ci uint64_t time) 518a46c0ec8Sopenharmony_ci{ 519a46c0ec8Sopenharmony_ci struct totem_dispatch *totem = totem_dispatch(dispatch); 520a46c0ec8Sopenharmony_ci enum totem_slot_state global_state; 521a46c0ec8Sopenharmony_ci bool enable_touch; 522a46c0ec8Sopenharmony_ci 523a46c0ec8Sopenharmony_ci switch(e->type) { 524a46c0ec8Sopenharmony_ci case EV_ABS: 525a46c0ec8Sopenharmony_ci totem_process_abs(totem, device, e, time); 526a46c0ec8Sopenharmony_ci break; 527a46c0ec8Sopenharmony_ci case EV_KEY: 528a46c0ec8Sopenharmony_ci totem_process_key(totem, device, e, time); 529a46c0ec8Sopenharmony_ci break; 530a46c0ec8Sopenharmony_ci case EV_MSC: 531a46c0ec8Sopenharmony_ci /* timestamp, ignore */ 532a46c0ec8Sopenharmony_ci break; 533a46c0ec8Sopenharmony_ci case EV_SYN: 534a46c0ec8Sopenharmony_ci global_state = totem_handle_state(totem, time); 535a46c0ec8Sopenharmony_ci enable_touch = (global_state == SLOT_STATE_NONE); 536a46c0ec8Sopenharmony_ci totem_set_touch_device_enabled(totem, 537a46c0ec8Sopenharmony_ci enable_touch, 538a46c0ec8Sopenharmony_ci time); 539a46c0ec8Sopenharmony_ci break; 540a46c0ec8Sopenharmony_ci default: 541a46c0ec8Sopenharmony_ci evdev_log_error(device, 542a46c0ec8Sopenharmony_ci "Unexpected event type %s (%#x)\n", 543a46c0ec8Sopenharmony_ci libevdev_event_type_get_name(e->type), 544a46c0ec8Sopenharmony_ci e->type); 545a46c0ec8Sopenharmony_ci break; 546a46c0ec8Sopenharmony_ci } 547a46c0ec8Sopenharmony_ci} 548a46c0ec8Sopenharmony_ci 549a46c0ec8Sopenharmony_cistatic void 550a46c0ec8Sopenharmony_citotem_interface_suspend(struct evdev_dispatch *dispatch, 551a46c0ec8Sopenharmony_ci struct evdev_device *device) 552a46c0ec8Sopenharmony_ci{ 553a46c0ec8Sopenharmony_ci struct totem_dispatch *totem = totem_dispatch(dispatch); 554a46c0ec8Sopenharmony_ci uint64_t now = libinput_now(evdev_libinput_context(device)); 555a46c0ec8Sopenharmony_ci 556a46c0ec8Sopenharmony_ci for (size_t i = 0; i < totem->nslots; i++) { 557a46c0ec8Sopenharmony_ci struct totem_slot *slot = &totem->slots[i]; 558a46c0ec8Sopenharmony_ci struct tablet_axes axes; 559a46c0ec8Sopenharmony_ci enum libinput_tablet_tool_tip_state tip_state; 560a46c0ec8Sopenharmony_ci 561a46c0ec8Sopenharmony_ci /* If we never initialized a tool, we can skip everything */ 562a46c0ec8Sopenharmony_ci if (!slot->tool) 563a46c0ec8Sopenharmony_ci continue; 564a46c0ec8Sopenharmony_ci 565a46c0ec8Sopenharmony_ci totem_slot_fetch_axes(totem, slot, slot->tool, &axes, now); 566a46c0ec8Sopenharmony_ci totem_slot_reset_changed_axes(totem, slot); 567a46c0ec8Sopenharmony_ci 568a46c0ec8Sopenharmony_ci if (slot->state == SLOT_STATE_NONE) 569a46c0ec8Sopenharmony_ci tip_state = LIBINPUT_TABLET_TOOL_TIP_UP; 570a46c0ec8Sopenharmony_ci else 571a46c0ec8Sopenharmony_ci tip_state = LIBINPUT_TABLET_TOOL_TIP_DOWN; 572a46c0ec8Sopenharmony_ci 573a46c0ec8Sopenharmony_ci if (totem->button_state_now) { 574a46c0ec8Sopenharmony_ci tablet_notify_button(&device->base, 575a46c0ec8Sopenharmony_ci now, 576a46c0ec8Sopenharmony_ci slot->tool, 577a46c0ec8Sopenharmony_ci tip_state, 578a46c0ec8Sopenharmony_ci &axes, 579a46c0ec8Sopenharmony_ci BTN_0, 580a46c0ec8Sopenharmony_ci LIBINPUT_BUTTON_STATE_RELEASED); 581a46c0ec8Sopenharmony_ci 582a46c0ec8Sopenharmony_ci totem->button_state_now = false; 583a46c0ec8Sopenharmony_ci totem->button_state_previous = false; 584a46c0ec8Sopenharmony_ci } 585a46c0ec8Sopenharmony_ci 586a46c0ec8Sopenharmony_ci if (slot->state != SLOT_STATE_NONE) { 587a46c0ec8Sopenharmony_ci tablet_notify_tip(&device->base, 588a46c0ec8Sopenharmony_ci now, 589a46c0ec8Sopenharmony_ci slot->tool, 590a46c0ec8Sopenharmony_ci LIBINPUT_TABLET_TOOL_TIP_UP, 591a46c0ec8Sopenharmony_ci slot->changed_axes, 592a46c0ec8Sopenharmony_ci &axes); 593a46c0ec8Sopenharmony_ci } 594a46c0ec8Sopenharmony_ci tablet_notify_proximity(&device->base, 595a46c0ec8Sopenharmony_ci now, 596a46c0ec8Sopenharmony_ci slot->tool, 597a46c0ec8Sopenharmony_ci LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT, 598a46c0ec8Sopenharmony_ci slot->changed_axes, 599a46c0ec8Sopenharmony_ci &axes); 600a46c0ec8Sopenharmony_ci } 601a46c0ec8Sopenharmony_ci totem_set_touch_device_enabled(totem, true, now); 602a46c0ec8Sopenharmony_ci} 603a46c0ec8Sopenharmony_ci 604a46c0ec8Sopenharmony_cistatic void 605a46c0ec8Sopenharmony_citotem_interface_destroy(struct evdev_dispatch *dispatch) 606a46c0ec8Sopenharmony_ci{ 607a46c0ec8Sopenharmony_ci struct totem_dispatch *totem = totem_dispatch(dispatch); 608a46c0ec8Sopenharmony_ci 609a46c0ec8Sopenharmony_ci free(totem->slots); 610a46c0ec8Sopenharmony_ci free(totem); 611a46c0ec8Sopenharmony_ci} 612a46c0ec8Sopenharmony_ci 613a46c0ec8Sopenharmony_cistatic void 614a46c0ec8Sopenharmony_citotem_interface_device_added(struct evdev_device *device, 615a46c0ec8Sopenharmony_ci struct evdev_device *added_device) 616a46c0ec8Sopenharmony_ci{ 617a46c0ec8Sopenharmony_ci struct totem_dispatch *totem = totem_dispatch(device->dispatch); 618a46c0ec8Sopenharmony_ci struct libinput_device_group *g1, *g2; 619a46c0ec8Sopenharmony_ci 620a46c0ec8Sopenharmony_ci if ((evdev_device_get_id_vendor(added_device) != 621a46c0ec8Sopenharmony_ci evdev_device_get_id_vendor(device)) || 622a46c0ec8Sopenharmony_ci (evdev_device_get_id_product(added_device) != 623a46c0ec8Sopenharmony_ci evdev_device_get_id_product(device))) 624a46c0ec8Sopenharmony_ci return; 625a46c0ec8Sopenharmony_ci 626a46c0ec8Sopenharmony_ci /* virtual devices don't have device groups, so check for that 627a46c0ec8Sopenharmony_ci libinput replay */ 628a46c0ec8Sopenharmony_ci g1 = libinput_device_get_device_group(&device->base); 629a46c0ec8Sopenharmony_ci g2 = libinput_device_get_device_group(&added_device->base); 630a46c0ec8Sopenharmony_ci if (g1 && g2 && g1->identifier != g2->identifier) 631a46c0ec8Sopenharmony_ci return; 632a46c0ec8Sopenharmony_ci 633a46c0ec8Sopenharmony_ci if (totem->touch_device != NULL) { 634a46c0ec8Sopenharmony_ci evdev_log_bug_libinput(device, 635a46c0ec8Sopenharmony_ci "already has a paired touch device, ignoring (%s)\n", 636a46c0ec8Sopenharmony_ci added_device->devname); 637a46c0ec8Sopenharmony_ci return; 638a46c0ec8Sopenharmony_ci } 639a46c0ec8Sopenharmony_ci 640a46c0ec8Sopenharmony_ci totem->touch_device = added_device; 641a46c0ec8Sopenharmony_ci evdev_log_info(device, "%s: is the totem touch device\n", added_device->devname); 642a46c0ec8Sopenharmony_ci} 643a46c0ec8Sopenharmony_ci 644a46c0ec8Sopenharmony_cistatic void 645a46c0ec8Sopenharmony_citotem_interface_device_removed(struct evdev_device *device, 646a46c0ec8Sopenharmony_ci struct evdev_device *removed_device) 647a46c0ec8Sopenharmony_ci{ 648a46c0ec8Sopenharmony_ci struct totem_dispatch *totem = totem_dispatch(device->dispatch); 649a46c0ec8Sopenharmony_ci 650a46c0ec8Sopenharmony_ci if (totem->touch_device != removed_device) 651a46c0ec8Sopenharmony_ci return; 652a46c0ec8Sopenharmony_ci 653a46c0ec8Sopenharmony_ci totem_set_touch_device_enabled(totem, true, 654a46c0ec8Sopenharmony_ci libinput_now(evdev_libinput_context(device))); 655a46c0ec8Sopenharmony_ci totem->touch_device = NULL; 656a46c0ec8Sopenharmony_ci} 657a46c0ec8Sopenharmony_ci 658a46c0ec8Sopenharmony_cistatic void 659a46c0ec8Sopenharmony_citotem_interface_initial_proximity(struct evdev_device *device, 660a46c0ec8Sopenharmony_ci struct evdev_dispatch *dispatch) 661a46c0ec8Sopenharmony_ci{ 662a46c0ec8Sopenharmony_ci struct totem_dispatch *totem = totem_dispatch(dispatch); 663a46c0ec8Sopenharmony_ci uint64_t now = libinput_now(evdev_libinput_context(device)); 664a46c0ec8Sopenharmony_ci bool enable_touch = true; 665a46c0ec8Sopenharmony_ci 666a46c0ec8Sopenharmony_ci for (size_t i = 0; i < totem->nslots; i++) { 667a46c0ec8Sopenharmony_ci struct totem_slot *slot = &totem->slots[i]; 668a46c0ec8Sopenharmony_ci struct tablet_axes axes; 669a46c0ec8Sopenharmony_ci int tracking_id; 670a46c0ec8Sopenharmony_ci 671a46c0ec8Sopenharmony_ci tracking_id = libevdev_get_slot_value(device->evdev, 672a46c0ec8Sopenharmony_ci i, 673a46c0ec8Sopenharmony_ci ABS_MT_TRACKING_ID); 674a46c0ec8Sopenharmony_ci if (tracking_id == -1) 675a46c0ec8Sopenharmony_ci continue; 676a46c0ec8Sopenharmony_ci 677a46c0ec8Sopenharmony_ci slot->tool = totem_new_tool(totem); 678a46c0ec8Sopenharmony_ci slot_axes_initialize(totem, slot); 679a46c0ec8Sopenharmony_ci totem_slot_mark_all_axes_changed(totem, slot, slot->tool); 680a46c0ec8Sopenharmony_ci totem_slot_fetch_axes(totem, slot, slot->tool, &axes, now); 681a46c0ec8Sopenharmony_ci tablet_notify_proximity(&device->base, 682a46c0ec8Sopenharmony_ci now, 683a46c0ec8Sopenharmony_ci slot->tool, 684a46c0ec8Sopenharmony_ci LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN, 685a46c0ec8Sopenharmony_ci slot->changed_axes, 686a46c0ec8Sopenharmony_ci &axes); 687a46c0ec8Sopenharmony_ci totem_slot_reset_changed_axes(totem, slot); 688a46c0ec8Sopenharmony_ci tablet_notify_tip(&device->base, 689a46c0ec8Sopenharmony_ci now, 690a46c0ec8Sopenharmony_ci slot->tool, 691a46c0ec8Sopenharmony_ci LIBINPUT_TABLET_TOOL_TIP_DOWN, 692a46c0ec8Sopenharmony_ci slot->changed_axes, 693a46c0ec8Sopenharmony_ci &axes); 694a46c0ec8Sopenharmony_ci slot->state = SLOT_STATE_UPDATE; 695a46c0ec8Sopenharmony_ci enable_touch = false; 696a46c0ec8Sopenharmony_ci } 697a46c0ec8Sopenharmony_ci 698a46c0ec8Sopenharmony_ci totem_set_touch_device_enabled(totem, enable_touch, now); 699a46c0ec8Sopenharmony_ci} 700a46c0ec8Sopenharmony_ci 701a46c0ec8Sopenharmony_cistruct evdev_dispatch_interface totem_interface = { 702a46c0ec8Sopenharmony_ci .process = totem_interface_process, 703a46c0ec8Sopenharmony_ci .suspend = totem_interface_suspend, 704a46c0ec8Sopenharmony_ci .remove = NULL, 705a46c0ec8Sopenharmony_ci .destroy = totem_interface_destroy, 706a46c0ec8Sopenharmony_ci .device_added = totem_interface_device_added, 707a46c0ec8Sopenharmony_ci .device_removed = totem_interface_device_removed, 708a46c0ec8Sopenharmony_ci .device_suspended = totem_interface_device_removed, /* treat as remove */ 709a46c0ec8Sopenharmony_ci .device_resumed = totem_interface_device_added, /* treat as add */ 710a46c0ec8Sopenharmony_ci .post_added = totem_interface_initial_proximity, 711a46c0ec8Sopenharmony_ci .touch_arbitration_toggle = NULL, 712a46c0ec8Sopenharmony_ci .touch_arbitration_update_rect = NULL, 713a46c0ec8Sopenharmony_ci .get_switch_state = NULL, 714a46c0ec8Sopenharmony_ci}; 715a46c0ec8Sopenharmony_ci 716a46c0ec8Sopenharmony_cistatic bool 717a46c0ec8Sopenharmony_citotem_reject_device(struct evdev_device *device) 718a46c0ec8Sopenharmony_ci{ 719a46c0ec8Sopenharmony_ci struct libevdev *evdev = device->evdev; 720a46c0ec8Sopenharmony_ci bool has_xy, has_slot, has_tool_dial, has_size, has_touch_size; 721a46c0ec8Sopenharmony_ci double w, h; 722a46c0ec8Sopenharmony_ci 723a46c0ec8Sopenharmony_ci has_xy = libevdev_has_event_code(evdev, EV_ABS, ABS_MT_POSITION_X) && 724a46c0ec8Sopenharmony_ci libevdev_has_event_code(evdev, EV_ABS, ABS_MT_POSITION_Y); 725a46c0ec8Sopenharmony_ci has_slot = libevdev_has_event_code(evdev, EV_ABS, ABS_MT_SLOT); 726a46c0ec8Sopenharmony_ci has_tool_dial = libevdev_has_event_code(evdev, EV_ABS, ABS_MT_TOOL_TYPE) && 727a46c0ec8Sopenharmony_ci libevdev_get_abs_maximum(evdev, ABS_MT_TOOL_TYPE) >= MT_TOOL_DIAL; 728a46c0ec8Sopenharmony_ci has_size = evdev_device_get_size(device, &w, &h) == 0; 729a46c0ec8Sopenharmony_ci has_touch_size = 730a46c0ec8Sopenharmony_ci libevdev_get_abs_resolution(device->evdev, ABS_MT_TOUCH_MAJOR) > 0 || 731a46c0ec8Sopenharmony_ci libevdev_get_abs_resolution(device->evdev, ABS_MT_TOUCH_MINOR) > 0; 732a46c0ec8Sopenharmony_ci 733a46c0ec8Sopenharmony_ci if (has_xy && has_slot && has_tool_dial && has_size && has_touch_size) 734a46c0ec8Sopenharmony_ci return false; 735a46c0ec8Sopenharmony_ci 736a46c0ec8Sopenharmony_ci evdev_log_bug_libinput(device, 737a46c0ec8Sopenharmony_ci "missing totem capabilities:%s%s%s%s%s. " 738a46c0ec8Sopenharmony_ci "Ignoring this device.\n", 739a46c0ec8Sopenharmony_ci has_xy ? "" : " xy", 740a46c0ec8Sopenharmony_ci has_slot ? "" : " slot", 741a46c0ec8Sopenharmony_ci has_tool_dial ? "" : " dial", 742a46c0ec8Sopenharmony_ci has_size ? "" : " resolutions", 743a46c0ec8Sopenharmony_ci has_touch_size ? "" : " touch-size"); 744a46c0ec8Sopenharmony_ci return true; 745a46c0ec8Sopenharmony_ci} 746a46c0ec8Sopenharmony_ci 747a46c0ec8Sopenharmony_cistatic uint32_t 748a46c0ec8Sopenharmony_citotem_accel_config_get_profiles(struct libinput_device *libinput_device) 749a46c0ec8Sopenharmony_ci{ 750a46c0ec8Sopenharmony_ci return LIBINPUT_CONFIG_ACCEL_PROFILE_NONE; 751a46c0ec8Sopenharmony_ci} 752a46c0ec8Sopenharmony_ci 753a46c0ec8Sopenharmony_cistatic enum libinput_config_status 754a46c0ec8Sopenharmony_citotem_accel_config_set_profile(struct libinput_device *libinput_device, 755a46c0ec8Sopenharmony_ci enum libinput_config_accel_profile profile) 756a46c0ec8Sopenharmony_ci{ 757a46c0ec8Sopenharmony_ci return LIBINPUT_CONFIG_STATUS_UNSUPPORTED; 758a46c0ec8Sopenharmony_ci} 759a46c0ec8Sopenharmony_ci 760a46c0ec8Sopenharmony_cistatic enum libinput_config_accel_profile 761a46c0ec8Sopenharmony_citotem_accel_config_get_profile(struct libinput_device *libinput_device) 762a46c0ec8Sopenharmony_ci{ 763a46c0ec8Sopenharmony_ci return LIBINPUT_CONFIG_ACCEL_PROFILE_NONE; 764a46c0ec8Sopenharmony_ci} 765a46c0ec8Sopenharmony_ci 766a46c0ec8Sopenharmony_cistatic enum libinput_config_accel_profile 767a46c0ec8Sopenharmony_citotem_accel_config_get_default_profile(struct libinput_device *libinput_device) 768a46c0ec8Sopenharmony_ci{ 769a46c0ec8Sopenharmony_ci return LIBINPUT_CONFIG_ACCEL_PROFILE_NONE; 770a46c0ec8Sopenharmony_ci} 771a46c0ec8Sopenharmony_ci 772a46c0ec8Sopenharmony_cistatic int 773a46c0ec8Sopenharmony_citotem_init_accel(struct totem_dispatch *totem, struct evdev_device *device) 774a46c0ec8Sopenharmony_ci{ 775a46c0ec8Sopenharmony_ci const struct input_absinfo *x, *y; 776a46c0ec8Sopenharmony_ci struct motion_filter *filter; 777a46c0ec8Sopenharmony_ci 778a46c0ec8Sopenharmony_ci x = device->abs.absinfo_x; 779a46c0ec8Sopenharmony_ci y = device->abs.absinfo_y; 780a46c0ec8Sopenharmony_ci 781a46c0ec8Sopenharmony_ci /* same filter as the tablet */ 782a46c0ec8Sopenharmony_ci filter = create_pointer_accelerator_filter_tablet(x->resolution, 783a46c0ec8Sopenharmony_ci y->resolution); 784a46c0ec8Sopenharmony_ci if (!filter) 785a46c0ec8Sopenharmony_ci return -1; 786a46c0ec8Sopenharmony_ci 787a46c0ec8Sopenharmony_ci evdev_device_init_pointer_acceleration(device, filter); 788a46c0ec8Sopenharmony_ci 789a46c0ec8Sopenharmony_ci /* we override the profile hooks for accel configuration with hooks 790a46c0ec8Sopenharmony_ci * that don't allow selection of profiles */ 791a46c0ec8Sopenharmony_ci device->pointer.config.get_profiles = totem_accel_config_get_profiles; 792a46c0ec8Sopenharmony_ci device->pointer.config.set_profile = totem_accel_config_set_profile; 793a46c0ec8Sopenharmony_ci device->pointer.config.get_profile = totem_accel_config_get_profile; 794a46c0ec8Sopenharmony_ci device->pointer.config.get_default_profile = totem_accel_config_get_default_profile; 795a46c0ec8Sopenharmony_ci 796a46c0ec8Sopenharmony_ci return 0; 797a46c0ec8Sopenharmony_ci} 798a46c0ec8Sopenharmony_ci 799a46c0ec8Sopenharmony_cistruct evdev_dispatch * 800a46c0ec8Sopenharmony_cievdev_totem_create(struct evdev_device *device) 801a46c0ec8Sopenharmony_ci{ 802a46c0ec8Sopenharmony_ci struct totem_dispatch *totem; 803a46c0ec8Sopenharmony_ci struct totem_slot *slots; 804a46c0ec8Sopenharmony_ci int num_slots; 805a46c0ec8Sopenharmony_ci 806a46c0ec8Sopenharmony_ci if (totem_reject_device(device)) 807a46c0ec8Sopenharmony_ci return NULL; 808a46c0ec8Sopenharmony_ci 809a46c0ec8Sopenharmony_ci totem = zalloc(sizeof *totem); 810a46c0ec8Sopenharmony_ci totem->device = device; 811a46c0ec8Sopenharmony_ci totem->base.dispatch_type = DISPATCH_TOTEM; 812a46c0ec8Sopenharmony_ci totem->base.interface = &totem_interface; 813a46c0ec8Sopenharmony_ci 814a46c0ec8Sopenharmony_ci num_slots = libevdev_get_num_slots(device->evdev); 815a46c0ec8Sopenharmony_ci if (num_slots <= 0) 816a46c0ec8Sopenharmony_ci goto error; 817a46c0ec8Sopenharmony_ci 818a46c0ec8Sopenharmony_ci totem->slot = libevdev_get_current_slot(device->evdev); 819a46c0ec8Sopenharmony_ci slots = zalloc(num_slots * sizeof(*totem->slots)); 820a46c0ec8Sopenharmony_ci 821a46c0ec8Sopenharmony_ci for (int slot = 0; slot < num_slots; ++slot) { 822a46c0ec8Sopenharmony_ci slots[slot].index = slot; 823a46c0ec8Sopenharmony_ci } 824a46c0ec8Sopenharmony_ci 825a46c0ec8Sopenharmony_ci totem->slots = slots; 826a46c0ec8Sopenharmony_ci totem->nslots = num_slots; 827a46c0ec8Sopenharmony_ci 828a46c0ec8Sopenharmony_ci evdev_init_sendevents(device, &totem->base); 829a46c0ec8Sopenharmony_ci totem_init_accel(totem, device); 830a46c0ec8Sopenharmony_ci 831a46c0ec8Sopenharmony_ci return &totem->base; 832a46c0ec8Sopenharmony_cierror: 833a46c0ec8Sopenharmony_ci totem_interface_destroy(&totem->base); 834a46c0ec8Sopenharmony_ci return NULL; 835a46c0ec8Sopenharmony_ci} 836