/* * Copyright © 2014 Red Hat, Inc. * * Permission to use, copy, modify, distribute, and sell this software and * its documentation for any purpose is hereby granted without fee, provided * that the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of the copyright holders not be used in * advertising or publicity pertaining to distribution of the software * without specific, written prior permission. The copyright holders make * no representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied warranty. * * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef EVDEV_MT_TOUCHPAD_H #define EVDEV_MT_TOUCHPAD_H #include #include "evdev.h" #include "filter.h" #include "timer.h" #define TOUCHPAD_HISTORY_LENGTH 4 #define TOUCHPAD_MIN_SAMPLES 4 #define VENDOR_ID_APPLE 0x5ac enum touchpad_event { TOUCHPAD_EVENT_NONE = 0, TOUCHPAD_EVENT_MOTION = (1 << 0), TOUCHPAD_EVENT_BUTTON_PRESS = (1 << 1), TOUCHPAD_EVENT_BUTTON_RELEASE = (1 << 2), }; enum touchpad_model { MODEL_UNKNOWN = 0, MODEL_SYNAPTICS, MODEL_ALPS, MODEL_APPLETOUCH, MODEL_ELANTECH, MODEL_UNIBODY_MACBOOK }; enum touch_state { TOUCH_NONE = 0, TOUCH_BEGIN, TOUCH_UPDATE, TOUCH_END }; enum button_event { BUTTON_EVENT_IN_BOTTOM_R = 30, BUTTON_EVENT_IN_BOTTOM_L, BUTTON_EVENT_IN_TOP_R, BUTTON_EVENT_IN_TOP_M, BUTTON_EVENT_IN_TOP_L, BUTTON_EVENT_IN_AREA, BUTTON_EVENT_UP, BUTTON_EVENT_PRESS, BUTTON_EVENT_RELEASE, BUTTON_EVENT_TIMEOUT, }; enum button_state { BUTTON_STATE_NONE, BUTTON_STATE_AREA, BUTTON_STATE_BOTTOM, BUTTON_STATE_TOP, BUTTON_STATE_TOP_NEW, BUTTON_STATE_TOP_TO_IGNORE, BUTTON_STATE_IGNORE, }; enum tp_tap_state { TAP_STATE_IDLE = 4, TAP_STATE_TOUCH, TAP_STATE_HOLD, TAP_STATE_TAPPED, TAP_STATE_TOUCH_2, TAP_STATE_TOUCH_2_HOLD, TAP_STATE_TOUCH_3, TAP_STATE_TOUCH_3_HOLD, TAP_STATE_DRAGGING_OR_DOUBLETAP, TAP_STATE_DRAGGING, TAP_STATE_DRAGGING_WAIT, TAP_STATE_DRAGGING_2, TAP_STATE_DEAD, /**< finger count exceeded */ }; enum tp_tap_touch_state { TAP_TOUCH_STATE_IDLE = 16, /**< not in touch */ TAP_TOUCH_STATE_TOUCH, /**< touching, may tap */ TAP_TOUCH_STATE_DEAD, /**< exceeded motion/timeout */ }; /* For edge scrolling, so we only care about right and bottom */ enum tp_edge { EDGE_NONE = 0, EDGE_RIGHT = (1 << 0), EDGE_BOTTOM = (1 << 1), }; enum tp_edge_scroll_touch_state { EDGE_SCROLL_TOUCH_STATE_NONE, EDGE_SCROLL_TOUCH_STATE_EDGE_NEW, EDGE_SCROLL_TOUCH_STATE_EDGE, EDGE_SCROLL_TOUCH_STATE_AREA, }; struct tp_motion { int32_t x; int32_t y; }; struct tp_touch { struct tp_dispatch *tp; enum touch_state state; bool dirty; bool is_pointer; /* the pointer-controlling touch */ int32_t x; int32_t y; uint64_t millis; struct { struct tp_motion samples[TOUCHPAD_HISTORY_LENGTH]; unsigned int index; unsigned int count; } history; struct { int32_t center_x; int32_t center_y; } hysteresis; /* A pinned touchpoint is the one that pressed the physical button * on a clickpad. After the release, it won't move until the center * moves more than a threshold away from the original coordinates */ struct { bool is_pinned; int32_t center_x; int32_t center_y; } pinned; /* Software-button state and timeout if applicable */ struct { enum button_state state; /* We use button_event here so we can use == on events */ enum button_event curr; struct libinput_timer timer; } button; struct { enum tp_tap_touch_state state; } tap; struct { enum tp_edge_scroll_touch_state state; uint32_t edge; int direction; double threshold; struct libinput_timer timer; } scroll; struct { bool is_palm; int32_t x, y; /* first coordinates if is_palm == true */ uint32_t time; /* first timestamp if is_palm == true */ } palm; }; struct tp_dispatch { struct evdev_dispatch base; struct evdev_device *device; unsigned int nfingers_down; /* number of fingers down */ unsigned int old_nfingers_down; /* previous no fingers down */ unsigned int slot; /* current slot */ bool has_mt; bool semi_mt; enum touchpad_model model; unsigned int real_touches; /* number of slots */ unsigned int ntouches; /* no slots inc. fakes */ struct tp_touch *touches; /* len == ntouches */ unsigned int fake_touches; /* fake touch mask */ struct { int32_t margin_x; int32_t margin_y; } hysteresis; struct { double x_scale_coeff; double y_scale_coeff; } accel; struct { bool is_clickpad; /* true for clickpads */ bool has_topbuttons; bool use_clickfinger; /* number of fingers decides button number */ bool click_pending; uint32_t state; uint32_t old_state; uint32_t motion_dist; /* for pinned touches */ unsigned int active; /* currently active button, for release event */ bool active_is_topbutton; /* is active a top button? */ /* Only used for clickpads. The software button areas are * always 2 horizontal stripes across the touchpad. * The buttons are split according to the edge settings. */ struct { int32_t top_edge; int32_t rightbutton_left_edge; } bottom_area; struct { int32_t bottom_edge; int32_t rightbutton_left_edge; int32_t leftbutton_right_edge; } top_area; struct evdev_device *trackpoint; } buttons; /* physical buttons */ struct { struct libinput_device_config_scroll_method config_method; enum libinput_config_scroll_method method; int32_t right_edge; int32_t bottom_edge; } scroll; enum touchpad_event queued; struct { struct libinput_device_config_tap config; bool enabled; bool suspended; struct libinput_timer timer; enum tp_tap_state state; uint32_t buttons_pressed; } tap; struct { int32_t right_edge; int32_t left_edge; } palm; struct { struct libinput_device_config_send_events config; enum libinput_config_send_events_mode current_mode; bool trackpoint_active; struct libinput_event_listener trackpoint_listener; struct libinput_timer trackpoint_timer; } sendevents; }; #define tp_for_each_touch(_tp, _t) \ for (unsigned int _i = 0; _i < (_tp)->ntouches && (_t = &(_tp)->touches[_i]); _i++) void tp_get_delta(struct tp_touch *t, double *dx, double *dy); void tp_set_pointer(struct tp_dispatch *tp, struct tp_touch *t); void tp_filter_motion(struct tp_dispatch *tp, double *dx, double *dy, double *dx_unaccel, double *dy_unaccel, uint64_t time); int tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time); int tp_init_tap(struct tp_dispatch *tp); void tp_destroy_tap(struct tp_dispatch *tp); int tp_init_buttons(struct tp_dispatch *tp, struct evdev_device *device); void tp_init_softbuttons(struct tp_dispatch *tp, struct evdev_device *device, double topbutton_size_mult); void tp_destroy_buttons(struct tp_dispatch *tp); int tp_process_button(struct tp_dispatch *tp, const struct input_event *e, uint64_t time); void tp_release_all_buttons(struct tp_dispatch *tp, uint64_t time); int tp_post_button_events(struct tp_dispatch *tp, uint64_t time); int tp_button_handle_state(struct tp_dispatch *tp, uint64_t time); int tp_button_touch_active(struct tp_dispatch *tp, struct tp_touch *t); bool tp_button_is_inside_softbutton_area(struct tp_dispatch *tp, struct tp_touch *t); void tp_release_all_taps(struct tp_dispatch *tp, uint64_t time); void tp_tap_suspend(struct tp_dispatch *tp, uint64_t time); void tp_tap_resume(struct tp_dispatch *tp, uint64_t time); bool tp_tap_dragging(struct tp_dispatch *tp); int tp_edge_scroll_init(struct tp_dispatch *tp, struct evdev_device *device); void tp_destroy_edge_scroll(struct tp_dispatch *tp); void tp_edge_scroll_handle_state(struct tp_dispatch *tp, uint64_t time); int tp_edge_scroll_post_events(struct tp_dispatch *tp, uint64_t time); void tp_edge_scroll_stop_events(struct tp_dispatch *tp, uint64_t time); int tp_edge_scroll_touch_active(struct tp_dispatch *tp, struct tp_touch *t); #endif