From: Peter Hutterer Date: Tue, 18 Jun 2019 00:53:39 +0000 (+1000) Subject: touchpad: move tp_init_thumb and tp_thumb_detect to the thumb file X-Git-Tag: 1.13.901~1^2~20 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=9e27244e6c3b052824f3b66e81b5c64e02648099;p=platform%2Fupstream%2Flibinput.git touchpad: move tp_init_thumb and tp_thumb_detect to the thumb file Extracted from Matt Mayfield's thumb detection patches. Signed-off-by: Peter Hutterer --- diff --git a/src/evdev-mt-touchpad-thumb.c b/src/evdev-mt-touchpad-thumb.c index b207f02..3c9354c 100644 --- a/src/evdev-mt-touchpad-thumb.c +++ b/src/evdev-mt-touchpad-thumb.c @@ -25,8 +25,178 @@ #include "config.h" #include "evdev-mt-touchpad.h" +#define THUMB_MOVE_TIMEOUT ms2us(300) + bool tp_thumb_ignored(const struct tp_dispatch *tp, const struct tp_touch *t) { return t->thumb.state == THUMB_STATE_YES; } + +static inline const char* +thumb_state_to_str(enum tp_thumb_state state) +{ + switch(state){ + CASE_RETURN_STRING(THUMB_STATE_NO); + CASE_RETURN_STRING(THUMB_STATE_YES); + CASE_RETURN_STRING(THUMB_STATE_MAYBE); + } + + return NULL; +} + +void +tp_thumb_detect(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time) +{ + enum tp_thumb_state state = t->thumb.state; + + /* once a thumb, always a thumb, once ruled out always ruled out */ + if (!tp->thumb.detect_thumbs || + t->thumb.state != THUMB_STATE_MAYBE) + return; + + if (t->point.y < tp->thumb.upper_thumb_line) { + /* if a potential thumb is above the line, it won't ever + * label as thumb */ + t->thumb.state = THUMB_STATE_NO; + goto out; + } + + /* If the thumb moves by more than 7mm, it's not a resting thumb */ + if (t->state == TOUCH_BEGIN) { + t->thumb.initial = t->point; + } else if (t->state == TOUCH_UPDATE) { + struct device_float_coords delta; + struct phys_coords mm; + + delta = device_delta(t->point, t->thumb.initial); + mm = tp_phys_delta(tp, delta); + if (length_in_mm(mm) > 7) { + t->thumb.state = THUMB_STATE_NO; + goto out; + } + } + + /* If the finger is below the upper thumb line and we have another + * finger in the same area, neither finger is a thumb (unless we've + * already labeled it as such). + */ + if (t->point.y > tp->thumb.upper_thumb_line && + tp->nfingers_down > 1) { + struct tp_touch *other; + + tp_for_each_touch(tp, other) { + if (other->state != TOUCH_BEGIN && + other->state != TOUCH_UPDATE) + continue; + + if (other->point.y > tp->thumb.upper_thumb_line) { + t->thumb.state = THUMB_STATE_NO; + if (other->thumb.state == THUMB_STATE_MAYBE) + other->thumb.state = THUMB_STATE_NO; + break; + } + } + } + + /* Note: a thumb at the edge of the touchpad won't trigger the + * threshold, the surface area is usually too small. So we have a + * two-stage detection: pressure and time within the area. + * A finger that remains at the very bottom of the touchpad becomes + * a thumb. + */ + if (tp->thumb.use_pressure && + t->pressure > tp->thumb.pressure_threshold) { + t->thumb.state = THUMB_STATE_YES; + } else if (tp->thumb.use_size && + (t->major > tp->thumb.size_threshold) && + (t->minor < (tp->thumb.size_threshold * 0.6))) { + t->thumb.state = THUMB_STATE_YES; + } else if (t->point.y > tp->thumb.lower_thumb_line && + tp->scroll.method != LIBINPUT_CONFIG_SCROLL_EDGE && + t->thumb.first_touch_time + THUMB_MOVE_TIMEOUT < time) { + t->thumb.state = THUMB_STATE_YES; + } + + /* now what? we marked it as thumb, so: + * + * - pointer motion must ignore this touch + * - clickfinger must ignore this touch for finger count + * - software buttons are unaffected + * - edge scrolling unaffected + * - gestures: unaffected + * - tapping: honour thumb on begin, ignore it otherwise for now, + * this gets a tad complicated otherwise + */ +out: + if (t->thumb.state != state) + evdev_log_debug(tp->device, + "thumb state: touch %d, %s → %s\n", + t->index, + thumb_state_to_str(state), + thumb_state_to_str(t->thumb.state)); +} + +void +tp_init_thumb(struct tp_dispatch *tp) +{ + struct evdev_device *device = tp->device; + double w = 0.0, h = 0.0; + struct device_coords edges; + struct phys_coords mm = { 0.0, 0.0 }; + uint32_t threshold; + struct quirks_context *quirks; + struct quirks *q; + + if (!tp->buttons.is_clickpad) + return; + + /* if the touchpad is less than 50mm high, skip thumb detection. + * it's too small to meaningfully interact with a thumb on the + * touchpad */ + evdev_device_get_size(device, &w, &h); + if (h < 50) + return; + + tp->thumb.detect_thumbs = true; + tp->thumb.use_pressure = false; + tp->thumb.pressure_threshold = INT_MAX; + + /* detect thumbs by pressure in the bottom 15mm, detect thumbs by + * lingering in the bottom 8mm */ + mm.y = h * 0.85; + edges = evdev_device_mm_to_units(device, &mm); + tp->thumb.upper_thumb_line = edges.y; + + mm.y = h * 0.92; + edges = evdev_device_mm_to_units(device, &mm); + tp->thumb.lower_thumb_line = edges.y; + + quirks = evdev_libinput_context(device)->quirks; + q = quirks_fetch_for_device(quirks, device->udev_device); + + if (libevdev_has_event_code(device->evdev, EV_ABS, ABS_MT_PRESSURE)) { + if (quirks_get_uint32(q, + QUIRK_ATTR_THUMB_PRESSURE_THRESHOLD, + &threshold)) { + tp->thumb.use_pressure = true; + tp->thumb.pressure_threshold = threshold; + } + } + + if (libevdev_has_event_code(device->evdev, EV_ABS, ABS_MT_TOUCH_MAJOR)) { + if (quirks_get_uint32(q, + QUIRK_ATTR_THUMB_SIZE_THRESHOLD, + &threshold)) { + tp->thumb.use_size = true; + tp->thumb.size_threshold = threshold; + } + } + + quirks_unref(q); + + evdev_log_debug(device, + "thumb: enabled thumb detection (area%s%s)\n", + tp->thumb.use_pressure ? ", pressure" : "", + tp->thumb.use_size ? ", size" : ""); +} diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 51b7ef7..929de21 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -39,7 +39,6 @@ #define DEFAULT_TRACKPOINT_EVENT_TIMEOUT ms2us(40) #define DEFAULT_KEYBOARD_ACTIVITY_TIMEOUT_1 ms2us(200) #define DEFAULT_KEYBOARD_ACTIVITY_TIMEOUT_2 ms2us(500) -#define THUMB_MOVE_TIMEOUT ms2us(300) #define FAKE_FINGER_OVERFLOW (1 << 7) #define THUMB_IGNORE_SPEED_THRESHOLD 20 /* mm/s */ @@ -1156,110 +1155,6 @@ out: palm_state); } -static inline const char* -thumb_state_to_str(enum tp_thumb_state state) -{ - switch(state){ - CASE_RETURN_STRING(THUMB_STATE_NO); - CASE_RETURN_STRING(THUMB_STATE_YES); - CASE_RETURN_STRING(THUMB_STATE_MAYBE); - } - - return NULL; -} - -static void -tp_thumb_detect(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time) -{ - enum tp_thumb_state state = t->thumb.state; - - /* once a thumb, always a thumb, once ruled out always ruled out */ - if (!tp->thumb.detect_thumbs || - t->thumb.state != THUMB_STATE_MAYBE) - return; - - if (t->point.y < tp->thumb.upper_thumb_line) { - /* if a potential thumb is above the line, it won't ever - * label as thumb */ - t->thumb.state = THUMB_STATE_NO; - goto out; - } - - /* If the thumb moves by more than 7mm, it's not a resting thumb */ - if (t->state == TOUCH_BEGIN) { - t->thumb.initial = t->point; - } else if (t->state == TOUCH_UPDATE) { - struct device_float_coords delta; - struct phys_coords mm; - - delta = device_delta(t->point, t->thumb.initial); - mm = tp_phys_delta(tp, delta); - if (length_in_mm(mm) > 7) { - t->thumb.state = THUMB_STATE_NO; - goto out; - } - } - - /* If the finger is below the upper thumb line and we have another - * finger in the same area, neither finger is a thumb (unless we've - * already labeled it as such). - */ - if (t->point.y > tp->thumb.upper_thumb_line && - tp->nfingers_down > 1) { - struct tp_touch *other; - - tp_for_each_touch(tp, other) { - if (other->state != TOUCH_BEGIN && - other->state != TOUCH_UPDATE) - continue; - - if (other->point.y > tp->thumb.upper_thumb_line) { - t->thumb.state = THUMB_STATE_NO; - if (other->thumb.state == THUMB_STATE_MAYBE) - other->thumb.state = THUMB_STATE_NO; - break; - } - } - } - - /* Note: a thumb at the edge of the touchpad won't trigger the - * threshold, the surface area is usually too small. So we have a - * two-stage detection: pressure and time within the area. - * A finger that remains at the very bottom of the touchpad becomes - * a thumb. - */ - if (tp->thumb.use_pressure && - t->pressure > tp->thumb.pressure_threshold) { - t->thumb.state = THUMB_STATE_YES; - } else if (tp->thumb.use_size && - (t->major > tp->thumb.size_threshold) && - (t->minor < (tp->thumb.size_threshold * 0.6))) { - t->thumb.state = THUMB_STATE_YES; - } else if (t->point.y > tp->thumb.lower_thumb_line && - tp->scroll.method != LIBINPUT_CONFIG_SCROLL_EDGE && - t->thumb.first_touch_time + THUMB_MOVE_TIMEOUT < time) { - t->thumb.state = THUMB_STATE_YES; - } - - /* now what? we marked it as thumb, so: - * - * - pointer motion must ignore this touch - * - clickfinger must ignore this touch for finger count - * - software buttons are unaffected - * - edge scrolling unaffected - * - gestures: unaffected - * - tapping: honour thumb on begin, ignore it otherwise for now, - * this gets a tad complicated otherwise - */ -out: - if (t->thumb.state != state) - evdev_log_debug(tp->device, - "thumb state: touch %d, %s → %s\n", - t->index, - thumb_state_to_str(state), - thumb_state_to_str(t->thumb.state)); -} - static void tp_unhover_pressure(struct tp_dispatch *tp, uint64_t time) { @@ -3452,69 +3347,6 @@ tp_init_sendevents(struct tp_dispatch *tp, tp_keyboard_timeout, tp); } -static void -tp_init_thumb(struct tp_dispatch *tp) -{ - struct evdev_device *device = tp->device; - double w = 0.0, h = 0.0; - struct device_coords edges; - struct phys_coords mm = { 0.0, 0.0 }; - uint32_t threshold; - struct quirks_context *quirks; - struct quirks *q; - - if (!tp->buttons.is_clickpad) - return; - - /* if the touchpad is less than 50mm high, skip thumb detection. - * it's too small to meaningfully interact with a thumb on the - * touchpad */ - evdev_device_get_size(device, &w, &h); - if (h < 50) - return; - - tp->thumb.detect_thumbs = true; - tp->thumb.use_pressure = false; - tp->thumb.pressure_threshold = INT_MAX; - - /* detect thumbs by pressure in the bottom 15mm, detect thumbs by - * lingering in the bottom 8mm */ - mm.y = h * 0.85; - edges = evdev_device_mm_to_units(device, &mm); - tp->thumb.upper_thumb_line = edges.y; - - mm.y = h * 0.92; - edges = evdev_device_mm_to_units(device, &mm); - tp->thumb.lower_thumb_line = edges.y; - - quirks = evdev_libinput_context(device)->quirks; - q = quirks_fetch_for_device(quirks, device->udev_device); - - if (libevdev_has_event_code(device->evdev, EV_ABS, ABS_MT_PRESSURE)) { - if (quirks_get_uint32(q, - QUIRK_ATTR_THUMB_PRESSURE_THRESHOLD, - &threshold)) { - tp->thumb.use_pressure = true; - tp->thumb.pressure_threshold = threshold; - } - } - - if (libevdev_has_event_code(device->evdev, EV_ABS, ABS_MT_TOUCH_MAJOR)) { - if (quirks_get_uint32(q, - QUIRK_ATTR_THUMB_SIZE_THRESHOLD, - &threshold)) { - tp->thumb.use_size = true; - tp->thumb.size_threshold = threshold; - } - } - - quirks_unref(q); - - evdev_log_debug(device, - "thumb: enabled thumb detection (area%s%s)\n", - tp->thumb.use_pressure ? ", pressure" : "", - tp->thumb.use_size ? ", size" : ""); -} static bool tp_pass_sanity_check(struct tp_dispatch *tp, diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h index 9c2d1f4..74006b4 100644 --- a/src/evdev-mt-touchpad.h +++ b/src/evdev-mt-touchpad.h @@ -684,4 +684,10 @@ tp_clickpad_middlebutton_apply_config(struct evdev_device *device); bool tp_thumb_ignored(const struct tp_dispatch *tp, const struct tp_touch *t); +void +tp_thumb_detect(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time); + +void +tp_init_thumb(struct tp_dispatch *tp); + #endif