int tp_init_buttons(struct tp_dispatch *tp, struct evdev_device *device) { struct libinput *libinput = tp_libinput_context(tp); struct tp_touch *t; const struct input_absinfo *absinfo_x, *absinfo_y; tp->buttons.is_clickpad = libevdev_has_property(device->evdev, INPUT_PROP_BUTTONPAD); tp->buttons.has_topbuttons = libevdev_has_property(device->evdev, INPUT_PROP_TOPBUTTONPAD); if (libevdev_has_event_code(device->evdev, EV_KEY, BTN_MIDDLE) || libevdev_has_event_code(device->evdev, EV_KEY, BTN_RIGHT)) { if (tp->buttons.is_clickpad) log_bug_kernel(libinput, "%s: clickpad advertising right button\n", device->devname); } else if (libevdev_has_event_code(device->evdev, EV_KEY, BTN_LEFT) && !tp->buttons.is_clickpad && libevdev_get_id_vendor(device->evdev) != VENDOR_ID_APPLE) { log_bug_kernel(libinput, "%s: non clickpad without right button?\n", device->devname); } absinfo_x = device->abs.absinfo_x; absinfo_y = device->abs.absinfo_y; /* pinned-finger motion threshold, see tp_unpin_finger. */ tp->buttons.motion_dist.x_scale_coeff = 1.0/absinfo_x->resolution; tp->buttons.motion_dist.y_scale_coeff = 1.0/absinfo_y->resolution; tp->buttons.config_method.get_methods = tp_button_config_click_get_methods; tp->buttons.config_method.set_method = tp_button_config_click_set_method; tp->buttons.config_method.get_method = tp_button_config_click_get_method; tp->buttons.config_method.get_default_method = tp_button_config_click_get_default_method; tp->device->base.config.click_method = &tp->buttons.config_method; tp->buttons.click_method = tp_click_get_default_method(tp); tp_switch_click_method(tp); tp_init_top_softbuttons(tp, device, 1.0); tp_init_middlebutton_emulation(tp, device); tp_for_each_touch(tp, t) { t->button.state = BUTTON_STATE_NONE; libinput_timer_init(&t->button.timer, tp_libinput_context(tp), tp_button_handle_timeout, t); }
int tp_process_button(struct tp_dispatch *tp, const struct input_event *e, uint64_t time) { struct libinput *libinput = tp_libinput_context(tp); uint32_t mask = 1 << (e->code - BTN_LEFT); /* Ignore other buttons on clickpads */ if (tp->buttons.is_clickpad && e->code != BTN_LEFT) { log_bug_kernel(libinput, "received %s button event on a clickpad\n", libevdev_event_code_get_name(EV_KEY, e->code)); return 0; } if (e->value) { tp->buttons.state |= mask; tp->queued |= TOUCHPAD_EVENT_BUTTON_PRESS; } else { tp->buttons.state &= ~mask; tp->queued |= TOUCHPAD_EVENT_BUTTON_RELEASE; } return 0; }
static void tp_edge_scroll_handle_edge_new(struct tp_dispatch *tp, struct tp_touch *t, enum scroll_event event) { struct libinput *libinput = tp_libinput_context(tp); switch (event) { case SCROLL_EVENT_TOUCH: log_bug_libinput(libinput, "unexpected scroll event %d in edge new state\n", event); break; case SCROLL_EVENT_MOTION: t->scroll.edge &= tp_touch_get_edge(tp, t); if (!t->scroll.edge) tp_edge_scroll_set_state(tp, t, EDGE_SCROLL_TOUCH_STATE_AREA); break; case SCROLL_EVENT_RELEASE: tp_edge_scroll_set_state(tp, t, EDGE_SCROLL_TOUCH_STATE_NONE); break; case SCROLL_EVENT_TIMEOUT: case SCROLL_EVENT_POSTED: tp_edge_scroll_set_state(tp, t, EDGE_SCROLL_TOUCH_STATE_EDGE); break; } }
static void tp_edge_scroll_handle_event(struct tp_dispatch *tp, struct tp_touch *t, enum scroll_event event) { struct libinput *libinput = tp_libinput_context(tp); enum tp_edge_scroll_touch_state current = t->scroll.edge_state; switch (current) { case EDGE_SCROLL_TOUCH_STATE_NONE: tp_edge_scroll_handle_none(tp, t, event); break; case EDGE_SCROLL_TOUCH_STATE_EDGE_NEW: tp_edge_scroll_handle_edge_new(tp, t, event); break; case EDGE_SCROLL_TOUCH_STATE_EDGE: tp_edge_scroll_handle_edge(tp, t, event); break; case EDGE_SCROLL_TOUCH_STATE_AREA: tp_edge_scroll_handle_area(tp, t, event); break; } log_debug(libinput, "edge state: %s → %s → %s\n", edge_state_to_str(current), edge_event_to_str(event), edge_state_to_str(t->scroll.edge_state)); }
static void tp_edge_scroll_handle_edge(struct tp_dispatch *tp, struct tp_touch *t, enum scroll_event event) { struct libinput *libinput = tp_libinput_context(tp); switch (event) { case SCROLL_EVENT_TOUCH: case SCROLL_EVENT_TIMEOUT: log_bug_libinput(libinput, "unexpected scroll event %d in edge state\n", event); break; case SCROLL_EVENT_MOTION: /* If started at the bottom right, decide in which dir to scroll */ if (t->scroll.edge == (EDGE_RIGHT | EDGE_BOTTOM)) { t->scroll.edge &= tp_touch_get_edge(tp, t); if (!t->scroll.edge) tp_edge_scroll_set_state(tp, t, EDGE_SCROLL_TOUCH_STATE_AREA); } break; case SCROLL_EVENT_RELEASE: tp_edge_scroll_set_state(tp, t, EDGE_SCROLL_TOUCH_STATE_NONE); break; case SCROLL_EVENT_POSTED: break; } }
static void tp_edge_scroll_handle_none(struct tp_dispatch *tp, struct tp_touch *t, enum scroll_event event) { struct libinput *libinput = tp_libinput_context(tp); switch (event) { case SCROLL_EVENT_TOUCH: if (tp_touch_get_edge(tp, t)) { tp_edge_scroll_set_state(tp, t, EDGE_SCROLL_TOUCH_STATE_EDGE_NEW); } else { tp_edge_scroll_set_state(tp, t, EDGE_SCROLL_TOUCH_STATE_AREA); } break; case SCROLL_EVENT_MOTION: case SCROLL_EVENT_RELEASE: case SCROLL_EVENT_TIMEOUT: case SCROLL_EVENT_POSTED: log_bug_libinput(libinput, "unexpected scroll event %d in none state\n", event); break; } }
static void tp_tap_multitap_handle_event(struct tp_dispatch *tp, struct tp_touch *t, enum tap_event event, uint64_t time) { struct libinput *libinput = tp_libinput_context(tp); switch (event) { case TAP_EVENT_RELEASE: log_bug_libinput(libinput, "invalid tap event, no fingers are down\n"); break; case TAP_EVENT_TOUCH: tp->tap.state = TAP_STATE_MULTITAP_DOWN; tp->tap.multitap_last_time = time; tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_PRESSED); tp_tap_set_timer(tp, time); break; case TAP_EVENT_MOTION: log_bug_libinput(libinput, "invalid tap event, no fingers are down\n"); break; case TAP_EVENT_TIMEOUT: tp->tap.state = TAP_STATE_IDLE; tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_PRESSED); tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); break; case TAP_EVENT_BUTTON: tp->tap.state = TAP_STATE_IDLE; tp_tap_clear_timer(tp); break; case TAP_EVENT_THUMB: break; } }
static void tp_tap_tapped_handle_event(struct tp_dispatch *tp, struct tp_touch *t, enum tap_event event, uint64_t time) { struct libinput *libinput = tp_libinput_context(tp); switch (event) { case TAP_EVENT_MOTION: case TAP_EVENT_RELEASE: log_bug_libinput(libinput, "invalid tap event when fingers are up\n"); break; case TAP_EVENT_TOUCH: tp->tap.state = TAP_STATE_DRAGGING_OR_DOUBLETAP; tp_tap_set_timer(tp, time); break; case TAP_EVENT_TIMEOUT: tp->tap.state = TAP_STATE_IDLE; tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); break; case TAP_EVENT_BUTTON: tp->tap.state = TAP_STATE_DEAD; tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED); break; case TAP_EVENT_THUMB: break; } }
static void tp_tap_idle_handle_event(struct tp_dispatch *tp, struct tp_touch *t, enum tap_event event, uint64_t time) { struct libinput *libinput = tp_libinput_context(tp); switch (event) { case TAP_EVENT_TOUCH: tp->tap.state = TAP_STATE_TOUCH; tp_tap_set_timer(tp, time); break; case TAP_EVENT_RELEASE: break; case TAP_EVENT_MOTION: log_bug_libinput(libinput, "invalid tap event, no fingers are down\n"); break; case TAP_EVENT_TIMEOUT: break; case TAP_EVENT_BUTTON: tp->tap.state = TAP_STATE_DEAD; break; case TAP_EVENT_THUMB: log_bug_libinput(libinput, "invalid tap event, no fingers down, no thumb\n"); break; } }
int tp_edge_scroll_init(struct tp_dispatch *tp, struct evdev_device *device) { struct tp_touch *t; int edge_width, edge_height; /* 7mm edge size */ edge_width = device->abs.absinfo_x->resolution * 7; edge_height = device->abs.absinfo_y->resolution * 7; tp->scroll.right_edge = device->abs.absinfo_x->maximum - edge_width; tp->scroll.bottom_edge = device->abs.absinfo_y->maximum - edge_height; tp_for_each_touch(tp, t) { t->scroll.direction = -1; libinput_timer_init(&t->scroll.timer, tp_libinput_context(tp), tp_edge_scroll_handle_timeout, t); }
static void tp_button_handle_event(struct tp_dispatch *tp, struct tp_touch *t, enum button_event event, uint64_t time) { struct libinput *libinput = tp_libinput_context(tp); enum button_state current = t->button.state; switch(t->button.state) { case BUTTON_STATE_NONE: tp_button_none_handle_event(tp, t, event); break; case BUTTON_STATE_AREA: tp_button_area_handle_event(tp, t, event); break; case BUTTON_STATE_BOTTOM: tp_button_bottom_handle_event(tp, t, event); break; case BUTTON_STATE_TOP: tp_button_top_handle_event(tp, t, event); break; case BUTTON_STATE_TOP_NEW: tp_button_top_new_handle_event(tp, t, event); break; case BUTTON_STATE_TOP_TO_IGNORE: tp_button_top_to_ignore_handle_event(tp, t, event); break; case BUTTON_STATE_IGNORE: tp_button_ignore_handle_event(tp, t, event); break; } if (current != t->button.state) log_debug(libinput, "button state: from %s, event %s to %s\n", button_state_to_str(current), button_event_to_str(event), button_state_to_str(t->button.state)); }
static void tp_edge_scroll_handle_area(struct tp_dispatch *tp, struct tp_touch *t, enum scroll_event event) { struct libinput *libinput = tp_libinput_context(tp); switch (event) { case SCROLL_EVENT_TOUCH: case SCROLL_EVENT_TIMEOUT: case SCROLL_EVENT_POSTED: log_bug_libinput(libinput, "unexpected scroll event %d in area state\n", event); break; case SCROLL_EVENT_MOTION: break; case SCROLL_EVENT_RELEASE: tp_edge_scroll_set_state(tp, t, EDGE_SCROLL_TOUCH_STATE_NONE); break; } }
static void tp_tap_handle_event(struct tp_dispatch *tp, struct tp_touch *t, enum tap_event event, uint64_t time) { struct libinput *libinput = tp_libinput_context(tp); enum tp_tap_state current; current = tp->tap.state; switch(tp->tap.state) { case TAP_STATE_IDLE: tp_tap_idle_handle_event(tp, t, event, time); break; case TAP_STATE_TOUCH: tp_tap_touch_handle_event(tp, t, event, time); break; case TAP_STATE_HOLD: tp_tap_hold_handle_event(tp, t, event, time); break; case TAP_STATE_TAPPED: tp_tap_tapped_handle_event(tp, t, event, time); break; case TAP_STATE_TOUCH_2: tp_tap_touch2_handle_event(tp, t, event, time); break; case TAP_STATE_TOUCH_2_HOLD: tp_tap_touch2_hold_handle_event(tp, t, event, time); break; case TAP_STATE_TOUCH_3: tp_tap_touch3_handle_event(tp, t, event, time); break; case TAP_STATE_TOUCH_3_HOLD: tp_tap_touch3_hold_handle_event(tp, t, event, time); break; case TAP_STATE_DRAGGING_OR_DOUBLETAP: tp_tap_dragging_or_doubletap_handle_event(tp, t, event, time); break; case TAP_STATE_DRAGGING: tp_tap_dragging_handle_event(tp, t, event, time); break; case TAP_STATE_DRAGGING_WAIT: tp_tap_dragging_wait_handle_event(tp, t, event, time); break; case TAP_STATE_DRAGGING_OR_TAP: tp_tap_dragging_tap_handle_event(tp, t, event, time); break; case TAP_STATE_DRAGGING_2: tp_tap_dragging2_handle_event(tp, t, event, time); break; case TAP_STATE_MULTITAP: tp_tap_multitap_handle_event(tp, t, event, time); break; case TAP_STATE_MULTITAP_DOWN: tp_tap_multitap_down_handle_event(tp, t, event, time); break; case TAP_STATE_DEAD: tp_tap_dead_handle_event(tp, t, event, time); break; } if (tp->tap.state == TAP_STATE_IDLE || tp->tap.state == TAP_STATE_DEAD) tp_tap_clear_timer(tp); log_debug(libinput, "tap state: %s → %s → %s\n", tap_state_to_str(current), tap_event_to_str(event), tap_state_to_str(tp->tap.state)); }