mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-03-25 09:30:47 +01:00
Merge branch 'thumb-detect-improvements'
This commit is contained in:
commit
988f31fc4a
10 changed files with 496 additions and 81 deletions
|
|
@ -39,6 +39,7 @@ diagram_files = \
|
|||
$(srcdir)/svg/pinch-gestures.svg \
|
||||
$(srcdir)/svg/swipe-gestures.svg \
|
||||
$(srcdir)/svg/tap-n-drag.svg \
|
||||
$(srcdir)/svg/thumb-detection.svg \
|
||||
$(srcdir)/svg/top-software-buttons.svg \
|
||||
$(srcdir)/svg/touchscreen-gestures.svg \
|
||||
$(srcdir)/svg/twofinger-scrolling.svg
|
||||
|
|
|
|||
|
|
@ -80,4 +80,32 @@ Notable behaviors of libinput's disable-while-typing feature:
|
|||
- Physical buttons work even while the touchpad is disabled. This includes
|
||||
software-emulated buttons.
|
||||
|
||||
@section thumb-detection Thumb detection
|
||||
|
||||
Many users rest their thumb on the touchpad while using the index finger to
|
||||
move the finger around. For clicks, often the thumb is used rather than the
|
||||
finger. The thumb should otherwise be ignored as a touch, i.e. it should not
|
||||
count towards @ref clickfinger and it should not cause a single-finger
|
||||
movement to trigger @ref twofinger_scrolling.
|
||||
|
||||
libinput uses two triggers for thumb detection: pressure and
|
||||
location. A touch exceeding a pressure threshold is considered a thumb if it
|
||||
is within the thumb detection zone.
|
||||
|
||||
@note "Pressure" on touchpads is synonymous with "contact area", a large
|
||||
touch surface area has a higher pressure and thus hints at a thumb or palm
|
||||
touching the surface.
|
||||
|
||||
Pressure readings are unreliable at the far bottom of the touchpad as a
|
||||
thumb hanging mostly off the touchpad will have a small surface area.
|
||||
libinput has a definitive thumb zone where any touch is considered a resting
|
||||
thumb.
|
||||
|
||||
@image html thumb-detection.svg
|
||||
|
||||
The picture above shows the two detection areas. In the larger (light red)
|
||||
area, a touch is labelled as thumb when it exceeds a device-specific
|
||||
pressure threshold. In the lower (dark red) area, a touch is labelled as
|
||||
thumb if it remains in that area for a time without moving outside.
|
||||
|
||||
*/
|
||||
|
|
|
|||
116
doc/svg/thumb-detection.svg
Normal file
116
doc/svg/thumb-detection.svg
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="89.829216mm"
|
||||
height="59.06765mm"
|
||||
viewBox="0 0 318.2925 209.29482"
|
||||
id="svg4184"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="thumb-detection.svg">
|
||||
<defs
|
||||
id="defs4186" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1.979899"
|
||||
inkscape:cx="270.39655"
|
||||
inkscape:cy="139.75035"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1136"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0" />
|
||||
<metadata
|
||||
id="metadata4189">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-257.99662,-299.41313)">
|
||||
<rect
|
||||
width="313.09872"
|
||||
height="167.89594"
|
||||
x="260.59351"
|
||||
y="302.01001"
|
||||
id="rect2858-0"
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#b3b3b3;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:5.19376326;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker:none;enable-background:accumulate" />
|
||||
<rect
|
||||
style="opacity:0.92000002;fill:#7b0000;fill-opacity:0.2983426;stroke:#000000;stroke-width:0.97031647;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="rect4788"
|
||||
width="307.88782"
|
||||
height="45.628574"
|
||||
x="262.8418"
|
||||
y="421.0347" />
|
||||
<rect
|
||||
y="445.40848"
|
||||
x="262.68912"
|
||||
height="21.407471"
|
||||
width="308.19318"
|
||||
id="rect4149"
|
||||
style="opacity:0.92000002;fill:#7b0000;fill-opacity:0.2983426;stroke:#000000;stroke-width:0.66495597;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||
<g
|
||||
id="g4151">
|
||||
<path
|
||||
sodipodi:nodetypes="sszzzcss"
|
||||
d="m 353.70196,495.15765 c -24.01774,-7.29937 -29.0012,-10.10221 -30.51977,-10.54973 -10.67294,-3.14527 -18.27051,-5.54063 -23.77758,-13.4704 -5.50707,-7.92977 -5.34967,-20.78347 8.87612,-26.31604 14.2258,-5.53257 39.34351,8.79597 60.13061,16.16341 20.7871,7.36744 33.04563,11.44545 39.33422,13.87551 -8.10022,18.05041 -7.22129,21.15857 -10.11054,33.34117 -0.0481,0.20261 -17.87459,-5.12433 -43.93306,-13.04392 z"
|
||||
id="path2824-1-1-3"
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffccaa;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.00100005;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker:none;enable-background:accumulate"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccccc"
|
||||
d="m 324.44991,483.39364 c -10.67294,-1.94747 -17.88441,-5.64478 -21.62691,-8.75386 -8.11652,-9.03765 -6.31775,-15.03428 -3.3272,-13.99784 8.90495,-0.9097 30.20384,9.01528 33.86042,10.17935 -5.80268,11.37909 -1.08919,13.70271 -8.90631,12.57235 z"
|
||||
id="path2824-7-1-4-3"
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.92000002;fill:#ffe6d5;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.2;marker:none;enable-background:accumulate"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(0.79657897,0.11742288,-0.14814182,0.631399,276.6631,-158.96703)"
|
||||
id="g3663-9-5">
|
||||
<path
|
||||
d="m 388.57143,893.79076 -57.14285,-130 c 0,0 -30.0247,-58.84827 4.28571,-70.00001 27.07438,-8.79984 37.32196,9.59496 40,14.64286 27.54455,51.91936 84.64285,173.21429 84.64285,173.21429 l -0.71428,0 -71.07143,12.14286 z"
|
||||
id="path2820-6-6"
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 360.32021,827.78041 c -15.74169,-35.7991 -29.44655,-66.92657 -30.45523,-69.17214 -7.08929,-15.78239 -10.8761,-32.88254 -9.6176,-43.43026 1.39575,-11.69796 7.19746,-18.50389 18.22574,-21.38044 5.18218,-1.35169 8.54724,-1.76827 12.41155,-1.53649 4.43642,0.26609 6.95929,0.93715 11.03011,2.93391 3.93491,1.9301 8.0085,5.56248 10.68932,9.53159 3.68818,5.46055 26.56068,50.9623 49.57778,98.62829 16.60192,34.38082 37.06388,77.41994 36.89013,77.59369 -0.13286,0.13286 -69.01932,11.92114 -69.66286,11.92114 -0.27909,0 -12.00972,-26.24842 -29.08894,-65.08929 z"
|
||||
id="path2824-1-1"
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ffccaa;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.002;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker:none;enable-background:accumulate"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 334.75785,756.75053 c -7.08929,-15.78239 -10.28437,-26.89033 -9.02587,-37.43805 1.39575,-11.69796 5.8085,-16.73613 16.83678,-19.61268 12.44766,-3.59459 20.03902,-1.91353 27.39013,8.75815 11.42622,25.66382 13.40166,29.05484 15.06365,35.48866 -0.13286,0.13286 -42.89663,15.49027 -44.57776,16.18518 -1.72922,0.71479 -4.94789,-2.09377 -5.68693,-3.38126 z"
|
||||
id="path2824-7-1-4"
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.92000002;fill:#ffe6d5;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.2;marker:none;enable-background:accumulate"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.3 KiB |
|
|
@ -807,7 +807,8 @@ tp_check_clickfinger_distance(struct tp_dispatch *tp,
|
|||
if (!t1 || !t2)
|
||||
return 0;
|
||||
|
||||
if (t1->is_thumb || t2->is_thumb)
|
||||
if (t1->thumb.state == THUMB_STATE_YES ||
|
||||
t2->thumb.state == THUMB_STATE_YES)
|
||||
return 0;
|
||||
|
||||
x = abs(t1->point.x - t2->point.x);
|
||||
|
|
@ -869,6 +870,9 @@ tp_clickfinger_set_button(struct tp_dispatch *tp)
|
|||
if (t->state != TOUCH_BEGIN && t->state != TOUCH_UPDATE)
|
||||
continue;
|
||||
|
||||
if (t->thumb.state == THUMB_STATE_YES)
|
||||
continue;
|
||||
|
||||
if (!first)
|
||||
first = t;
|
||||
else if (!second)
|
||||
|
|
@ -899,9 +903,8 @@ out:
|
|||
case 0:
|
||||
case 1: button = BTN_LEFT; break;
|
||||
case 2: button = BTN_RIGHT; break;
|
||||
case 3: button = BTN_MIDDLE; break;
|
||||
default:
|
||||
button = 0;
|
||||
button = BTN_MIDDLE; break;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -740,7 +740,7 @@ tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time)
|
|||
/* The simple version: if a touch is a thumb on
|
||||
* begin we ignore it. All other thumb touches
|
||||
* follow the normal tap state for now */
|
||||
if (t->is_thumb) {
|
||||
if (t->thumb.state == THUMB_STATE_YES) {
|
||||
t->tap.is_thumb = true;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -772,7 +772,7 @@ tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time)
|
|||
|
||||
tp_tap_handle_event(tp, t, TAP_EVENT_MOTION, time);
|
||||
} else if (tp->tap.state != TAP_STATE_IDLE &&
|
||||
t->is_thumb &&
|
||||
t->thumb.state == THUMB_STATE_YES &&
|
||||
!t->tap.is_thumb) {
|
||||
tp_tap_handle_event(tp, t, TAP_EVENT_THUMB, time);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -208,7 +208,8 @@ tp_begin_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
|
|||
t->millis = time;
|
||||
tp->nfingers_down++;
|
||||
t->palm.time = time;
|
||||
t->is_thumb = false;
|
||||
t->thumb.state = THUMB_STATE_MAYBE;
|
||||
t->thumb.first_touch_time = time;
|
||||
t->tap.is_thumb = false;
|
||||
assert(tp->nfingers_down >= 1);
|
||||
}
|
||||
|
|
@ -314,6 +315,8 @@ tp_process_absolute(struct tp_dispatch *tp,
|
|||
break;
|
||||
case ABS_MT_PRESSURE:
|
||||
t->pressure = e->value;
|
||||
t->dirty = true;
|
||||
tp->queued |= TOUCHPAD_EVENT_MOTION;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -499,7 +502,7 @@ tp_touch_active(struct tp_dispatch *tp, struct tp_touch *t)
|
|||
return (t->state == TOUCH_BEGIN || t->state == TOUCH_UPDATE) &&
|
||||
t->palm.state == PALM_NONE &&
|
||||
!t->pinned.is_pinned &&
|
||||
!t->is_thumb &&
|
||||
t->thumb.state != THUMB_STATE_YES &&
|
||||
tp_button_touch_active(tp, t) &&
|
||||
tp_edge_scroll_touch_active(tp, t);
|
||||
}
|
||||
|
|
@ -642,20 +645,63 @@ out:
|
|||
t->palm.state == PALM_TYPING ? "typing" : "trackpoint");
|
||||
}
|
||||
|
||||
static void
|
||||
tp_thumb_detect(struct tp_dispatch *tp, struct tp_touch *t)
|
||||
static inline const char*
|
||||
thumb_state_to_str(enum tp_thumb_state state)
|
||||
{
|
||||
/* once a thumb, always a thumb */
|
||||
if (!tp->thumb.detect_thumbs || t->is_thumb)
|
||||
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 normalized_coords normalized;
|
||||
|
||||
delta = device_delta(t->point, t->thumb.initial);
|
||||
normalized = tp_normalize_delta(tp, delta);
|
||||
if (normalized_length(normalized) >
|
||||
TP_MM_TO_DPI_NORMALIZED(7)) {
|
||||
t->thumb.state = THUMB_STATE_NO;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Note: a thumb at the edge of the touchpad won't trigger the
|
||||
* threshold, the surface area is usually too small.
|
||||
* 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 (t->pressure < tp->thumb.threshold)
|
||||
return;
|
||||
|
||||
t->is_thumb = true;
|
||||
if (t->pressure > tp->thumb.threshold)
|
||||
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 + 300 < time)
|
||||
t->thumb.state = THUMB_STATE_YES;
|
||||
|
||||
/* now what? we marked it as thumb, so:
|
||||
*
|
||||
|
|
@ -667,6 +713,12 @@ tp_thumb_detect(struct tp_dispatch *tp, struct tp_touch *t)
|
|||
* - tapping: honour thumb on begin, ignore it otherwise for now,
|
||||
* this gets a tad complicated otherwise
|
||||
*/
|
||||
out:
|
||||
if (t->thumb.state != state)
|
||||
log_debug(tp_libinput_context(tp),
|
||||
"thumb state: %s → %s\n",
|
||||
thumb_state_to_str(state),
|
||||
thumb_state_to_str(t->thumb.state));
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -760,6 +812,48 @@ tp_unhover_touches(struct tp_dispatch *tp, uint64_t time)
|
|||
|
||||
}
|
||||
|
||||
static inline void
|
||||
tp_position_fake_touches(struct tp_dispatch *tp)
|
||||
{
|
||||
struct tp_touch *t;
|
||||
struct tp_touch *topmost = NULL;
|
||||
unsigned int start, i;
|
||||
|
||||
if (tp_fake_finger_count(tp) <= tp->num_slots)
|
||||
return;
|
||||
|
||||
/* We have at least one fake touch down. Find the top-most real
|
||||
* touch and copy its coordinates over to to all fake touches.
|
||||
* This is more reliable than just taking the first touch.
|
||||
*/
|
||||
for (i = 0; i < tp->num_slots; i++) {
|
||||
t = tp_get_touch(tp, i);
|
||||
if (t->state == TOUCH_END ||
|
||||
t->state == TOUCH_NONE)
|
||||
continue;
|
||||
|
||||
if (topmost == NULL || t->point.y < topmost->point.y)
|
||||
topmost = t;
|
||||
}
|
||||
|
||||
if (!topmost) {
|
||||
log_bug_libinput(tp_libinput_context(tp),
|
||||
"Unable to find topmost touch\n");
|
||||
return;
|
||||
}
|
||||
|
||||
start = tp->has_mt ? tp->num_slots : 1;
|
||||
for (i = start; i < tp->ntouches; i++) {
|
||||
t = tp_get_touch(tp, i);
|
||||
if (t->state == TOUCH_NONE)
|
||||
continue;
|
||||
|
||||
t->point = topmost->point;
|
||||
if (!t->dirty)
|
||||
t->dirty = topmost->dirty;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool
|
||||
tp_need_motion_history_reset(struct tp_dispatch *tp)
|
||||
{
|
||||
|
|
@ -782,13 +876,13 @@ static void
|
|||
tp_process_state(struct tp_dispatch *tp, uint64_t time)
|
||||
{
|
||||
struct tp_touch *t;
|
||||
struct tp_touch *first = tp_get_touch(tp, 0);
|
||||
unsigned int i;
|
||||
bool restart_filter = false;
|
||||
bool want_motion_reset;
|
||||
|
||||
tp_process_fake_touches(tp, time);
|
||||
tp_unhover_touches(tp, time);
|
||||
tp_position_fake_touches(tp);
|
||||
|
||||
want_motion_reset = tp_need_motion_history_reset(tp);
|
||||
|
||||
|
|
@ -803,16 +897,10 @@ tp_process_state(struct tp_dispatch *tp, uint64_t time)
|
|||
t->quirks.reset_motion_history = false;
|
||||
}
|
||||
|
||||
if (i >= tp->num_slots && t->state != TOUCH_NONE) {
|
||||
t->point = first->point;
|
||||
if (!t->dirty)
|
||||
t->dirty = first->dirty;
|
||||
}
|
||||
|
||||
if (!t->dirty)
|
||||
continue;
|
||||
|
||||
tp_thumb_detect(tp, t);
|
||||
tp_thumb_detect(tp, t, time);
|
||||
tp_palm_detect(tp, t, time);
|
||||
|
||||
tp_motion_hysteresis(tp, t);
|
||||
|
|
@ -1635,6 +1723,13 @@ tp_init_thumb(struct tp_dispatch *tp)
|
|||
{
|
||||
struct evdev_device *device = tp->device;
|
||||
const struct input_absinfo *abs;
|
||||
double w = 0.0, h = 0.0;
|
||||
int xres, yres;
|
||||
int ymax;
|
||||
double threshold;
|
||||
|
||||
if (!tp->buttons.is_clickpad)
|
||||
return 0;
|
||||
|
||||
abs = libevdev_get_abs_info(device->evdev, ABS_MT_PRESSURE);
|
||||
if (!abs)
|
||||
|
|
@ -1643,14 +1738,33 @@ tp_init_thumb(struct tp_dispatch *tp)
|
|||
if (abs->maximum - abs->minimum < 255)
|
||||
return 0;
|
||||
|
||||
/* The touchpads we looked at so far have a clear thumb threshold of
|
||||
* ~100, you don't reach that with a normal finger interaction.
|
||||
/* 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 0;
|
||||
|
||||
/* Our reference touchpad is the T440s with 42x42 resolution.
|
||||
* Higher-res touchpads exhibit higher pressure for the same
|
||||
* interaction. On the T440s, the threshold value is 100, you don't
|
||||
* reach that with a normal finger interaction.
|
||||
* Note: "thumb" means massive touch that should not interact, not
|
||||
* "using the tip of my thumb for a pinch gestures".
|
||||
*/
|
||||
tp->thumb.threshold = 100;
|
||||
xres = tp->device->abs.absinfo_x->resolution;
|
||||
yres = tp->device->abs.absinfo_y->resolution;
|
||||
threshold = 100.0 * hypot(xres, yres)/hypot(42, 42);
|
||||
tp->thumb.threshold = max(100, threshold);
|
||||
tp->thumb.detect_thumbs = true;
|
||||
|
||||
/* detect thumbs by pressure in the bottom 15mm, detect thumbs by
|
||||
* lingering in the bottom 8mm */
|
||||
ymax = tp->device->abs.absinfo_y->maximum;
|
||||
yres = tp->device->abs.absinfo_y->resolution;
|
||||
tp->thumb.upper_thumb_line = ymax - yres * 15;
|
||||
tp->thumb.lower_thumb_line = ymax - yres * 8;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -136,12 +136,17 @@ enum tp_gesture_2fg_state {
|
|||
GESTURE_2FG_STATE_PINCH,
|
||||
};
|
||||
|
||||
enum tp_thumb_state {
|
||||
THUMB_STATE_NO,
|
||||
THUMB_STATE_YES,
|
||||
THUMB_STATE_MAYBE,
|
||||
};
|
||||
|
||||
struct tp_touch {
|
||||
struct tp_dispatch *tp;
|
||||
enum touch_state state;
|
||||
bool has_ended; /* TRACKING_ID == -1 */
|
||||
bool dirty;
|
||||
bool is_thumb;
|
||||
struct device_coords point;
|
||||
uint64_t millis;
|
||||
int distance; /* distance == 0 means touch */
|
||||
|
|
@ -204,6 +209,12 @@ struct tp_touch {
|
|||
struct {
|
||||
struct device_coords initial;
|
||||
} gesture;
|
||||
|
||||
struct {
|
||||
enum tp_thumb_state state;
|
||||
uint64_t first_touch_time;
|
||||
struct device_coords initial;
|
||||
} thumb;
|
||||
};
|
||||
|
||||
struct tp_dispatch {
|
||||
|
|
@ -336,6 +347,8 @@ struct tp_dispatch {
|
|||
struct {
|
||||
bool detect_thumbs;
|
||||
int threshold;
|
||||
int upper_thumb_line;
|
||||
int lower_thumb_line;
|
||||
} thumb;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1231,6 +1231,9 @@ axis_replacement_value(struct axis_replacement *axes,
|
|||
{
|
||||
struct axis_replacement *axis = axes;
|
||||
|
||||
if (!axes)
|
||||
return false;
|
||||
|
||||
while (axis->evcode != -1) {
|
||||
if (axis->evcode == evcode) {
|
||||
*value = axis->value;
|
||||
|
|
@ -1275,9 +1278,6 @@ litest_auto_assign_value(struct litest_device *d,
|
|||
break;
|
||||
default:
|
||||
value = -1;
|
||||
if (!axes)
|
||||
break;
|
||||
|
||||
if (!axis_replacement_value(axes, ev->code, &value) &&
|
||||
d->interface->get_axis_default)
|
||||
d->interface->get_axis_default(d, ev->code, &value);
|
||||
|
|
|
|||
|
|
@ -288,6 +288,7 @@ START_TEST(touchpad_4fg_clickfinger)
|
|||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
struct libinput_event *event;
|
||||
|
||||
if (libevdev_get_num_slots(dev->evdev) < 4)
|
||||
return;
|
||||
|
|
@ -311,6 +312,18 @@ START_TEST(touchpad_4fg_clickfinger)
|
|||
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_wait_for_event(li);
|
||||
event = libinput_get_event(li);
|
||||
litest_is_button_event(event,
|
||||
BTN_MIDDLE,
|
||||
LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
libinput_event_destroy(event);
|
||||
event = libinput_get_event(li);
|
||||
litest_is_button_event(event,
|
||||
BTN_MIDDLE,
|
||||
LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
libinput_event_destroy(event);
|
||||
|
||||
litest_assert_empty_queue(li);
|
||||
}
|
||||
END_TEST
|
||||
|
|
@ -319,6 +332,7 @@ START_TEST(touchpad_4fg_clickfinger_btntool_2slots)
|
|||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
struct libinput_event *event;
|
||||
|
||||
if (libevdev_get_num_slots(dev->evdev) >= 3 ||
|
||||
!libevdev_has_event_code(dev->evdev, EV_KEY, BTN_TOOL_QUADTAP))
|
||||
|
|
@ -343,7 +357,17 @@ START_TEST(touchpad_4fg_clickfinger_btntool_2slots)
|
|||
litest_touch_up(dev, 0);
|
||||
litest_touch_up(dev, 1);
|
||||
|
||||
libinput_dispatch(li);
|
||||
litest_wait_for_event(li);
|
||||
event = libinput_get_event(li);
|
||||
litest_is_button_event(event,
|
||||
BTN_MIDDLE,
|
||||
LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
libinput_event_destroy(event);
|
||||
event = libinput_get_event(li);
|
||||
litest_is_button_event(event,
|
||||
BTN_MIDDLE,
|
||||
LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
libinput_event_destroy(event);
|
||||
|
||||
litest_assert_empty_queue(li);
|
||||
}
|
||||
|
|
@ -353,8 +377,10 @@ START_TEST(touchpad_4fg_clickfinger_btntool_3slots)
|
|||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
struct libinput_event *event;
|
||||
|
||||
if (libevdev_get_num_slots(dev->evdev) != 3 ||
|
||||
if (libevdev_get_num_slots(dev->evdev) >= 4 ||
|
||||
libevdev_get_num_slots(dev->evdev) < 3 ||
|
||||
!libevdev_has_event_code(dev->evdev, EV_KEY, BTN_TOOL_TRIPLETAP))
|
||||
return;
|
||||
|
||||
|
|
@ -381,6 +407,18 @@ START_TEST(touchpad_4fg_clickfinger_btntool_3slots)
|
|||
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_wait_for_event(li);
|
||||
event = libinput_get_event(li);
|
||||
litest_is_button_event(event,
|
||||
BTN_MIDDLE,
|
||||
LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
libinput_event_destroy(event);
|
||||
event = libinput_get_event(li);
|
||||
litest_is_button_event(event,
|
||||
BTN_MIDDLE,
|
||||
LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
libinput_event_destroy(event);
|
||||
|
||||
litest_assert_empty_queue(li);
|
||||
}
|
||||
END_TEST
|
||||
|
|
@ -682,6 +720,66 @@ START_TEST(touchpad_area_to_clickfinger_method_while_down)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(touchpad_clickfinger_3fg_tool_position)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
|
||||
enable_clickfinger(dev);
|
||||
litest_drain_events(li);
|
||||
|
||||
/* one in thumb area, one in normal area. spread is wide so the two
|
||||
* real fingers don't count together. we expect a 2-finger click */
|
||||
litest_touch_down(dev, 0, 5, 99);
|
||||
litest_touch_down(dev, 1, 90, 15);
|
||||
litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 0);
|
||||
litest_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, 1);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_event(dev, EV_KEY, BTN_LEFT, 1);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
litest_event(dev, EV_KEY, BTN_LEFT, 0);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_assert_button_event(li, BTN_RIGHT,
|
||||
LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
litest_assert_button_event(li, BTN_RIGHT,
|
||||
LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(touchpad_clickfinger_4fg_tool_position)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
|
||||
enable_clickfinger(dev);
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_touch_down(dev, 0, 5, 99);
|
||||
litest_touch_down(dev, 1, 90, 15);
|
||||
litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 0);
|
||||
litest_event(dev, EV_KEY, BTN_TOOL_QUADTAP, 1);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_event(dev, EV_KEY, BTN_LEFT, 1);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
litest_event(dev, EV_KEY, BTN_LEFT, 0);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_assert_button_event(li,
|
||||
BTN_MIDDLE,
|
||||
LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
litest_assert_button_event(li,
|
||||
BTN_MIDDLE,
|
||||
LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(touchpad_btn_left)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
|
|
@ -1422,6 +1520,10 @@ litest_setup_tests(void)
|
|||
litest_add("touchpad:clickfinger", touchpad_area_to_clickfinger_method, LITEST_CLICKPAD, LITEST_ANY);
|
||||
litest_add("touchpad:clickfinger",
|
||||
touchpad_area_to_clickfinger_method_while_down, LITEST_CLICKPAD, LITEST_ANY);
|
||||
/* run those two for the T440 one only so we don't have to worry
|
||||
* about small touchpads messing with thumb detection expectations */
|
||||
litest_add_for_device("touchpad:clickfinger", touchpad_clickfinger_3fg_tool_position, LITEST_SYNAPTICS_TOPBUTTONPAD);
|
||||
litest_add_for_device("touchpad:clickfinger", touchpad_clickfinger_4fg_tool_position, LITEST_SYNAPTICS_TOPBUTTONPAD);
|
||||
|
||||
litest_add("touchpad:click", touchpad_click_defaults_clickfinger, LITEST_APPLE_CLICKPAD, LITEST_ANY);
|
||||
litest_add("touchpad:click", touchpad_click_defaults_btnarea, LITEST_CLICKPAD, LITEST_APPLE_CLICKPAD);
|
||||
|
|
|
|||
134
test/touchpad.c
134
test/touchpad.c
|
|
@ -2893,7 +2893,15 @@ END_TEST
|
|||
static int
|
||||
has_thumb_detect(struct litest_device *dev)
|
||||
{
|
||||
return libevdev_has_event_code(dev->evdev, EV_ABS, ABS_MT_PRESSURE);
|
||||
double w, h;
|
||||
|
||||
if (!libevdev_has_event_code(dev->evdev, EV_ABS, ABS_MT_PRESSURE))
|
||||
return 0;
|
||||
|
||||
if (libinput_device_get_size(dev->libinput_device, &w, &h) != 0)
|
||||
return 0;
|
||||
|
||||
return h >= 50.0;
|
||||
}
|
||||
|
||||
START_TEST(touchpad_thumb_begin_no_motion)
|
||||
|
|
@ -2901,7 +2909,7 @@ START_TEST(touchpad_thumb_begin_no_motion)
|
|||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
struct axis_replacement axes[] = {
|
||||
{ ABS_MT_PRESSURE, 100 },
|
||||
{ ABS_MT_PRESSURE, 190 },
|
||||
{ -1, 0 }
|
||||
};
|
||||
|
||||
|
|
@ -2912,8 +2920,8 @@ START_TEST(touchpad_thumb_begin_no_motion)
|
|||
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_touch_down_extended(dev, 0, 50, 50, axes);
|
||||
litest_touch_move_to(dev, 0, 50, 50, 80, 50, 10, 0);
|
||||
litest_touch_down_extended(dev, 0, 50, 99, axes);
|
||||
litest_touch_move_to(dev, 0, 50, 99, 80, 99, 10, 0);
|
||||
litest_touch_up(dev, 0);
|
||||
|
||||
litest_assert_empty_queue(li);
|
||||
|
|
@ -2925,29 +2933,54 @@ START_TEST(touchpad_thumb_update_no_motion)
|
|||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
struct axis_replacement axes[] = {
|
||||
{ ABS_MT_PRESSURE, 100 },
|
||||
{ ABS_MT_PRESSURE, 190 },
|
||||
{ -1, 0 }
|
||||
};
|
||||
|
||||
litest_disable_tap(dev->libinput_device);
|
||||
enable_clickfinger(dev);
|
||||
|
||||
if (!has_thumb_detect(dev))
|
||||
return;
|
||||
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_touch_down(dev, 0, 50, 50);
|
||||
litest_touch_move_to(dev, 0, 50, 50, 60, 50, 10, 0);
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
|
||||
|
||||
litest_touch_move_extended(dev, 0, 65, 50, axes);
|
||||
litest_touch_move_to(dev, 0, 65, 50, 80, 50, 10, 0);
|
||||
litest_touch_down(dev, 0, 59, 99);
|
||||
litest_touch_move_extended(dev, 0, 59, 99, axes);
|
||||
litest_touch_move_to(dev, 0, 60, 99, 80, 99, 10, 0);
|
||||
litest_touch_up(dev, 0);
|
||||
|
||||
litest_assert_empty_queue(li);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(touchpad_thumb_moving)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
struct axis_replacement axes[] = {
|
||||
{ ABS_MT_PRESSURE, 190 },
|
||||
{ -1, 0 }
|
||||
};
|
||||
|
||||
litest_disable_tap(dev->libinput_device);
|
||||
enable_clickfinger(dev);
|
||||
|
||||
if (!has_thumb_detect(dev))
|
||||
return;
|
||||
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_touch_down(dev, 0, 50, 99);
|
||||
litest_touch_move_to(dev, 0, 50, 99, 60, 99, 10, 0);
|
||||
litest_touch_move_extended(dev, 0, 65, 99, axes);
|
||||
litest_touch_move_to(dev, 0, 65, 99, 80, 99, 10, 0);
|
||||
litest_touch_up(dev, 0);
|
||||
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(touchpad_thumb_clickfinger)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
|
|
@ -2955,7 +2988,7 @@ START_TEST(touchpad_thumb_clickfinger)
|
|||
struct libinput_event *event;
|
||||
struct libinput_event_pointer *ptrev;
|
||||
struct axis_replacement axes[] = {
|
||||
{ ABS_MT_PRESSURE, 100 },
|
||||
{ ABS_MT_PRESSURE, 190 },
|
||||
{ -1, 0 }
|
||||
};
|
||||
|
||||
|
|
@ -2969,9 +3002,9 @@ START_TEST(touchpad_thumb_clickfinger)
|
|||
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_touch_down(dev, 0, 50, 50);
|
||||
litest_touch_down(dev, 1, 60, 50);
|
||||
litest_touch_move_extended(dev, 0, 55, 50, axes);
|
||||
litest_touch_down(dev, 0, 50, 99);
|
||||
litest_touch_down(dev, 1, 60, 99);
|
||||
litest_touch_move_extended(dev, 0, 55, 99, axes);
|
||||
litest_button_click(dev, BTN_LEFT, true);
|
||||
|
||||
libinput_dispatch(li);
|
||||
|
|
@ -2989,9 +3022,9 @@ START_TEST(touchpad_thumb_clickfinger)
|
|||
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_touch_down(dev, 0, 50, 50);
|
||||
litest_touch_down(dev, 1, 60, 50);
|
||||
litest_touch_move_extended(dev, 1, 65, 50, axes);
|
||||
litest_touch_down(dev, 0, 50, 99);
|
||||
litest_touch_down(dev, 1, 60, 99);
|
||||
litest_touch_move_extended(dev, 1, 65, 99, axes);
|
||||
litest_button_click(dev, BTN_LEFT, true);
|
||||
|
||||
libinput_dispatch(li);
|
||||
|
|
@ -3012,7 +3045,7 @@ START_TEST(touchpad_thumb_btnarea)
|
|||
struct libinput_event *event;
|
||||
struct libinput_event_pointer *ptrev;
|
||||
struct axis_replacement axes[] = {
|
||||
{ ABS_MT_PRESSURE, 100 },
|
||||
{ ABS_MT_PRESSURE, 190 },
|
||||
{ -1, 0 }
|
||||
};
|
||||
|
||||
|
|
@ -3026,8 +3059,8 @@ START_TEST(touchpad_thumb_btnarea)
|
|||
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_touch_down(dev, 0, 90, 95);
|
||||
litest_touch_move_extended(dev, 0, 95, 95, axes);
|
||||
litest_touch_down(dev, 0, 90, 99);
|
||||
litest_touch_move_extended(dev, 0, 95, 99, axes);
|
||||
litest_button_click(dev, BTN_LEFT, true);
|
||||
|
||||
/* button areas work as usual with a thumb */
|
||||
|
|
@ -3048,7 +3081,7 @@ START_TEST(touchpad_thumb_edgescroll)
|
|||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
struct axis_replacement axes[] = {
|
||||
{ ABS_MT_PRESSURE, 100 },
|
||||
{ ABS_MT_PRESSURE, 190 },
|
||||
{ -1, 0 }
|
||||
};
|
||||
|
||||
|
|
@ -3079,7 +3112,7 @@ START_TEST(touchpad_thumb_tap_begin)
|
|||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
struct axis_replacement axes[] = {
|
||||
{ ABS_MT_PRESSURE, 100 },
|
||||
{ ABS_MT_PRESSURE, 190 },
|
||||
{ -1, 0 }
|
||||
};
|
||||
|
||||
|
|
@ -3087,17 +3120,18 @@ START_TEST(touchpad_thumb_tap_begin)
|
|||
return;
|
||||
|
||||
litest_enable_tap(dev->libinput_device);
|
||||
enable_clickfinger(dev);
|
||||
litest_drain_events(li);
|
||||
|
||||
/* touch down is a thumb */
|
||||
litest_touch_down_extended(dev, 0, 50, 50, axes);
|
||||
litest_touch_down_extended(dev, 0, 50, 99, axes);
|
||||
litest_touch_up(dev, 0);
|
||||
litest_timeout_tap();
|
||||
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
/* make sure normal tap still works */
|
||||
litest_touch_down(dev, 0, 50, 50);
|
||||
litest_touch_down(dev, 0, 50, 99);
|
||||
litest_touch_up(dev, 0);
|
||||
litest_timeout_tap();
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_BUTTON);
|
||||
|
|
@ -3109,7 +3143,7 @@ START_TEST(touchpad_thumb_tap_touch)
|
|||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
struct axis_replacement axes[] = {
|
||||
{ ABS_MT_PRESSURE, 100 },
|
||||
{ ABS_MT_PRESSURE, 190 },
|
||||
{ -1, 0 }
|
||||
};
|
||||
|
||||
|
|
@ -3117,17 +3151,18 @@ START_TEST(touchpad_thumb_tap_touch)
|
|||
return;
|
||||
|
||||
litest_enable_tap(dev->libinput_device);
|
||||
enable_clickfinger(dev);
|
||||
litest_drain_events(li);
|
||||
|
||||
/* event after touch down is thumb */
|
||||
litest_touch_down(dev, 0, 50, 50);
|
||||
litest_touch_move_extended(dev, 0, 51, 50, axes);
|
||||
litest_touch_move_extended(dev, 0, 51, 99, axes);
|
||||
litest_touch_up(dev, 0);
|
||||
litest_timeout_tap();
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
/* make sure normal tap still works */
|
||||
litest_touch_down(dev, 0, 50, 50);
|
||||
litest_touch_down(dev, 0, 50, 99);
|
||||
litest_touch_up(dev, 0);
|
||||
litest_timeout_tap();
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_BUTTON);
|
||||
|
|
@ -3139,7 +3174,7 @@ START_TEST(touchpad_thumb_tap_hold)
|
|||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
struct axis_replacement axes[] = {
|
||||
{ ABS_MT_PRESSURE, 100 },
|
||||
{ ABS_MT_PRESSURE, 190 },
|
||||
{ -1, 0 }
|
||||
};
|
||||
|
||||
|
|
@ -3147,18 +3182,19 @@ START_TEST(touchpad_thumb_tap_hold)
|
|||
return;
|
||||
|
||||
litest_enable_tap(dev->libinput_device);
|
||||
enable_clickfinger(dev);
|
||||
litest_drain_events(li);
|
||||
|
||||
/* event in state HOLD is thumb */
|
||||
litest_touch_down(dev, 0, 50, 50);
|
||||
litest_touch_down(dev, 0, 50, 99);
|
||||
litest_timeout_tap();
|
||||
libinput_dispatch(li);
|
||||
litest_touch_move_extended(dev, 0, 51, 50, axes);
|
||||
litest_touch_move_extended(dev, 0, 51, 99, axes);
|
||||
litest_touch_up(dev, 0);
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
/* make sure normal tap still works */
|
||||
litest_touch_down(dev, 0, 50, 50);
|
||||
litest_touch_down(dev, 0, 50, 99);
|
||||
litest_touch_up(dev, 0);
|
||||
litest_timeout_tap();
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_BUTTON);
|
||||
|
|
@ -3170,7 +3206,7 @@ START_TEST(touchpad_thumb_tap_hold_2ndfg)
|
|||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
struct axis_replacement axes[] = {
|
||||
{ ABS_MT_PRESSURE, 100 },
|
||||
{ ABS_MT_PRESSURE, 190 },
|
||||
{ -1, 0 }
|
||||
};
|
||||
|
||||
|
|
@ -3178,13 +3214,14 @@ START_TEST(touchpad_thumb_tap_hold_2ndfg)
|
|||
return;
|
||||
|
||||
litest_enable_tap(dev->libinput_device);
|
||||
enable_clickfinger(dev);
|
||||
litest_drain_events(li);
|
||||
|
||||
/* event in state HOLD is thumb */
|
||||
litest_touch_down(dev, 0, 50, 50);
|
||||
litest_touch_down(dev, 0, 50, 99);
|
||||
litest_timeout_tap();
|
||||
libinput_dispatch(li);
|
||||
litest_touch_move_extended(dev, 0, 51, 50, axes);
|
||||
litest_touch_move_extended(dev, 0, 51, 99, axes);
|
||||
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
|
|
@ -3203,7 +3240,7 @@ START_TEST(touchpad_thumb_tap_hold_2ndfg)
|
|||
litest_assert_empty_queue(li);
|
||||
|
||||
/* make sure normal tap still works */
|
||||
litest_touch_down(dev, 0, 50, 50);
|
||||
litest_touch_down(dev, 0, 50, 99);
|
||||
litest_touch_up(dev, 0);
|
||||
litest_timeout_tap();
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_BUTTON);
|
||||
|
|
@ -3217,7 +3254,7 @@ START_TEST(touchpad_thumb_tap_hold_2ndfg_tap)
|
|||
struct libinput_event *event;
|
||||
struct libinput_event_pointer *ptrev;
|
||||
struct axis_replacement axes[] = {
|
||||
{ ABS_MT_PRESSURE, 100 },
|
||||
{ ABS_MT_PRESSURE, 190 },
|
||||
{ -1, 0 }
|
||||
};
|
||||
|
||||
|
|
@ -3228,10 +3265,10 @@ START_TEST(touchpad_thumb_tap_hold_2ndfg_tap)
|
|||
litest_drain_events(li);
|
||||
|
||||
/* event in state HOLD is thumb */
|
||||
litest_touch_down(dev, 0, 50, 50);
|
||||
litest_touch_down(dev, 0, 50, 99);
|
||||
litest_timeout_tap();
|
||||
libinput_dispatch(li);
|
||||
litest_touch_move_extended(dev, 0, 51, 50, axes);
|
||||
litest_touch_move_extended(dev, 0, 51, 99, axes);
|
||||
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
|
|
@ -3261,7 +3298,7 @@ START_TEST(touchpad_thumb_tap_hold_2ndfg_tap)
|
|||
libinput_event_destroy(libinput_event_pointer_get_base_event(ptrev));
|
||||
|
||||
/* make sure normal tap still works */
|
||||
litest_touch_down(dev, 0, 50, 50);
|
||||
litest_touch_down(dev, 0, 50, 99);
|
||||
litest_touch_up(dev, 0);
|
||||
litest_timeout_tap();
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_BUTTON);
|
||||
|
|
@ -3473,16 +3510,17 @@ litest_setup_tests(void)
|
|||
litest_add("touchpad:dwt", touchpad_dwt_enable_before_touch, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
litest_add("touchpad:dwt", touchpad_dwt_enable_during_tap, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
|
||||
litest_add("touchpad:thumb", touchpad_thumb_begin_no_motion, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
litest_add("touchpad:thumb", touchpad_thumb_update_no_motion, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
litest_add("touchpad:thumb", touchpad_thumb_begin_no_motion, LITEST_CLICKPAD, LITEST_ANY);
|
||||
litest_add("touchpad:thumb", touchpad_thumb_update_no_motion, LITEST_CLICKPAD, LITEST_ANY);
|
||||
litest_add("touchpad:thumb", touchpad_thumb_moving, LITEST_CLICKPAD, LITEST_ANY);
|
||||
litest_add("touchpad:thumb", touchpad_thumb_clickfinger, LITEST_CLICKPAD, LITEST_ANY);
|
||||
litest_add("touchpad:thumb", touchpad_thumb_btnarea, LITEST_CLICKPAD, LITEST_ANY);
|
||||
litest_add("touchpad:thumb", touchpad_thumb_edgescroll, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
litest_add("touchpad:thumb", touchpad_thumb_tap_begin, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
litest_add("touchpad:thumb", touchpad_thumb_tap_touch, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
litest_add("touchpad:thumb", touchpad_thumb_tap_hold, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
litest_add("touchpad:thumb", touchpad_thumb_tap_hold_2ndfg, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
|
||||
litest_add("touchpad:thumb", touchpad_thumb_tap_hold_2ndfg_tap, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
|
||||
litest_add("touchpad:thumb", touchpad_thumb_edgescroll, LITEST_CLICKPAD, LITEST_ANY);
|
||||
litest_add("touchpad:thumb", touchpad_thumb_tap_begin, LITEST_CLICKPAD, LITEST_ANY);
|
||||
litest_add("touchpad:thumb", touchpad_thumb_tap_touch, LITEST_CLICKPAD, LITEST_ANY);
|
||||
litest_add("touchpad:thumb", touchpad_thumb_tap_hold, LITEST_CLICKPAD, LITEST_ANY);
|
||||
litest_add("touchpad:thumb", touchpad_thumb_tap_hold_2ndfg, LITEST_CLICKPAD, LITEST_SINGLE_TOUCH);
|
||||
litest_add("touchpad:thumb", touchpad_thumb_tap_hold_2ndfg_tap, LITEST_CLICKPAD, LITEST_SINGLE_TOUCH);
|
||||
|
||||
litest_add_for_device("touchpad:bugs", touchpad_tool_tripletap_touch_count, LITEST_SYNAPTICS_TOPBUTTONPAD);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue