touchpad: don't allow taps in the top half of the palm exclusion zone.

Touches in the exclusion zone are ignored for palm detection and don't move
the cursor. Tapping however triggers before we know whether something is a
palm or not, so we get erroneous button clickst.

If a tap happens in the top half of the touchpad, within the palm exclusion
zones, ignore it for tap purposes. To avoid further complicating the state
machine simply pretend there was a movement > threshold on that finger. This
advances the tap state machine properly that no button events are sent for
this finger.

https://bugs.freedesktop.org/show_bug.cgi?id=89625

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
This commit is contained in:
Peter Hutterer 2015-04-15 15:21:08 +10:00
parent 7552cd04f7
commit 39f1125347
6 changed files with 244 additions and 58 deletions

View file

@ -23,6 +23,10 @@ screen, it is common for a finger to start inside an exclusion zone and move
rapidly across the touchpad. libinput detects such movements and avoids palm
detection on such touch sequences.
Each exclusion zone is divided into a top part and a bottom part. A touch
starting in the top part of the exclusion zone does not trigger a
tap (see @ref tapping).
In the diagram below, the exclusion zones are painted red.
Touch 'A' starts inside the exclusion zone and moves
almost vertically. It is considered a palm and ignored for cursor movement,
@ -31,6 +35,11 @@ despite moving out of the exclusion zone.
Touch 'B' starts inside the exclusion zone but moves horizontally out of the
zone. It is considered a valid touch and controls the cursor.
Touch 'C' occurs in the top part of the exclusion zone. Despite being a
tapping motion, it does not generate an emulated button event. Touch 'D'
likewise occurs within the exclusion zone but in the bottom half. libinput
will generate a button event for this touch.
@image html palm-detection.svg
@section trackpoint-disabling Palm detection during trackpoint use

View file

@ -2,14 +2,66 @@
<!-- 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"
version="1.1"
width="393.62857"
height="268.62857"
id="svg2">
id="svg2"
inkscape:version="0.91 r13725"
sodipodi:docname="palm-detection.svg">
<metadata
id="metadata3479">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1136"
id="namedview3477"
showgrid="false"
inkscape:zoom="3.5662625"
inkscape:cx="199.35048"
inkscape:cy="156.74673"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="svg2" />
<defs
id="defs4">
<marker
inkscape:stockid="Arrow1Lstart"
orient="auto"
refY="0.0"
refX="0.0"
id="marker4663"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4407"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
transform="scale(0.8) translate(12.5,0)" />
</marker>
<marker
refX="0"
refY="0"
@ -59,64 +111,111 @@
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" />
</marker>
</defs>
<g
transform="translate(343.95712,-527.33359)"
id="layer3"
style="display:inline">
<rect
width="386.42856"
height="261.42856"
x="-340.35712"
y="530.93359"
id="rect2858-0"
style="color:#000000;fill:#b3b3b3;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:7.20000076;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
<rect
width="65.281105"
height="254.3844"
x="-336.88608"
y="534.46918"
id="rect12924"
style="color:#000000;fill:#ff0000;fill-opacity:0.32017547;fill-rule:nonzero;stroke:none;stroke-width:3.5;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
<rect
width="65.281105"
height="254.3844"
x="-22.72864"
y="534.21661"
id="rect13482"
style="color:#000000;fill:#ff0000;fill-opacity:0.32017547;fill-rule:nonzero;stroke:none;stroke-width:3.5;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
<path
d="m 38.928571,67.914286 c 0,0 3.508205,24.810617 9.642857,57.857144 6.134651,33.04652 23.277202,79.68584 89.642852,90.35714"
transform="translate(-343.95712,527.33359)"
id="path13492"
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:6, 1;stroke-dashoffset:0;marker-mid:none;marker-end:url(#Arrow1Lend-2)" />
<text
x="-310.74283"
y="590.96222"
id="text13874"
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Utopia;-inkscape-font-specification:Utopia"><tspan
x="-310.74283"
y="590.96222"
id="tspan13876"
style="font-size:18px;font-family:Arial;-inkscape-font-specification:Arial">A</tspan></text>
<text
x="7.8971062"
y="626.08258"
id="text13874-8"
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Utopia;-inkscape-font-specification:Utopia"><tspan
x="7.8971062"
y="626.08258"
id="tspan13876-7"
style="font-size:18px;font-family:Arial;-inkscape-font-specification:Arial">B</tspan></text>
<path
d="m 347.5,90.414286 c 0,0 -28.20972,-6.408104 -85,-6.071429 -22.06971,0.130838 -66.07143,4.285715 -66.07143,4.285715"
transform="translate(-343.95712,527.33359)"
id="path13903"
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Lend-2)" />
</g>
<rect
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#b3b3b3;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:7.20000076;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker:none;enable-background:accumulate"
id="rect2858-0"
y="3.6000037"
x="3.6000032"
height="261.42856"
width="386.42856" />
<rect
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ff0000;fill-opacity:0.32017547;fill-rule:nonzero;stroke:none;stroke-width:3.5;marker:none;enable-background:accumulate"
id="rect12924"
y="7.1355872"
x="7.0710421"
height="254.3844"
width="65.281105" />
<rect
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#ff0000;fill-opacity:0.32017547;fill-rule:nonzero;stroke:none;stroke-width:3.5;marker:none;enable-background:accumulate"
id="rect13482"
y="6.8830237"
x="321.22849"
height="254.3844"
width="65.281105" />
<path
inkscape:connector-curvature="0"
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:6, 1;stroke-dashoffset:0;stroke-opacity:1;marker-mid:none;marker-end:url(#Arrow1Lend-2)"
id="path13492"
d="m 38.928571,67.914286 c 0,0 3.508205,24.810617 9.642857,57.857144 6.134651,33.04652 23.277202,79.68584 89.642852,90.35714" />
<rect
style="fill:#000000;fill-opacity:0.3559322;fill-rule:evenodd;stroke:none;stroke-width:3.30527353px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="rect3490"
width="65.272476"
height="136.21509"
x="7.0411549"
y="7.0411549" />
<text
sodipodi:linespacing="100%"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:100%;font-family:Utopia;-inkscape-font-specification:Utopia;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
xml:space="preserve"
id="text13874"
y="63.628628"
x="33.214291"><tspan
style="font-size:18px;font-family:Arial;-inkscape-font-specification:Arial"
id="tspan13876"
y="63.628628"
x="33.214291">A</tspan></text>
<rect
style="fill:#000000;fill-opacity:0.3559322;fill-rule:evenodd;stroke:none;stroke-width:3.30527353px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="rect3490-2"
width="65.272476"
height="136.21509"
x="321.23563"
y="6.7607527" />
<text
sodipodi:linespacing="100%"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:100%;font-family:Utopia;-inkscape-font-specification:Utopia;text-align:start;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none"
xml:space="preserve"
id="text13874-8"
y="98.748993"
x="351.85422"><tspan
style="font-size:18px;font-family:Arial;-inkscape-font-specification:Arial"
id="tspan13876-7"
y="98.748993"
x="351.85422">B</tspan></text>
<path
inkscape:connector-curvature="0"
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Lend-2)"
id="path13903"
d="m 347.5,90.414286 c 0,0 -28.20972,-6.408104 -85,-6.071429 -22.06971,0.130838 -66.07143,4.285715 -66.07143,4.285715" />
<g
transform="translate(343.95712,-527.33359)"
id="layer1"
style="display:inline" />
<text
sodipodi:linespacing="100%"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:100%;font-family:Utopia;-inkscape-font-specification:Utopia;text-align:start;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none"
xml:space="preserve"
id="text13874-8-1"
y="46.009491"
x="342.27759"><tspan
style="font-size:18px;font-family:Arial;-inkscape-font-specification:Arial"
id="tspan13876-7-9"
y="46.009491"
x="342.27759">C</tspan></text>
<text
sodipodi:linespacing="100%"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:100%;font-family:Utopia;-inkscape-font-specification:Utopia;text-align:start;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none"
xml:space="preserve"
id="text13874-8-1-4"
y="215.65927"
x="37.970726"><tspan
style="font-size:18px;font-family:Arial;-inkscape-font-specification:Arial"
id="tspan13876-7-9-5"
y="215.65927"
x="37.970726">D</tspan></text>
<circle
style="fill:#000000;fill-opacity:1;stroke:none;stroke-opacity:1"
id="path4401"
cx="-360.181"
cy="24.53549"
r="4.0658817"
transform="scale(-1,1)" />
<circle
style="fill:#000000;fill-opacity:1;stroke:none;stroke-opacity:1"
id="path4401-9"
cx="-36.452721"
cy="194.8819"
r="4.0658817"
transform="scale(-1,1)" />
</svg>

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

View file

@ -571,6 +571,14 @@ tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time)
t->tap.state = TAP_TOUCH_STATE_TOUCH;
t->tap.initial = t->point;
tp_tap_handle_event(tp, t, TAP_EVENT_TOUCH, time);
/* If we think this is a palm, pretend there's a
* motion event which will prevent tap clicks
* without requiring extra states in the FSM.
*/
if (tp_palm_tap_is_palm(tp, t))
tp_tap_handle_event(tp, t, TAP_EVENT_MOTION, time);
} else if (t->state == TOUCH_END) {
tp->tap.tap_finger_count--;
tp_tap_handle_event(tp, t, TAP_EVENT_RELEASE, time);

View file

@ -458,6 +458,24 @@ tp_touch_active(struct tp_dispatch *tp, struct tp_touch *t)
tp_edge_scroll_touch_active(tp, t);
}
bool
tp_palm_tap_is_palm(struct tp_dispatch *tp, struct tp_touch *t)
{
if (t->state != TOUCH_BEGIN)
return false;
if (t->point.x > tp->palm.left_edge &&
t->point.x < tp->palm.right_edge)
return false;
/* We're inside the left/right palm edge and in the northern half of
* the touchpad - this tap is a palm */
if (t->point.y < tp->palm.vert_center)
return true;
return false;
}
static void
tp_palm_detect(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
{
@ -1098,13 +1116,16 @@ static int
tp_init_palmdetect(struct tp_dispatch *tp,
struct evdev_device *device)
{
int width;
int width, height;
tp->palm.right_edge = INT_MAX;
tp->palm.left_edge = INT_MIN;
tp->palm.vert_center = INT_MIN;
width = abs(device->abs.absinfo_x->maximum -
device->abs.absinfo_x->minimum);
height = abs(device->abs.absinfo_y->maximum -
device->abs.absinfo_y->minimum);
/* Apple touchpads are always big enough to warrant palm detection */
if (evdev_device_get_id_vendor(device) != VENDOR_ID_APPLE) {
@ -1121,6 +1142,7 @@ tp_init_palmdetect(struct tp_dispatch *tp,
/* palm edges are 5% of the width on each side */
tp->palm.right_edge = device->abs.absinfo_x->maximum - width * 0.05;
tp->palm.left_edge = device->abs.absinfo_x->minimum + width * 0.05;
tp->palm.vert_center = device->abs.absinfo_y->minimum + height/2;
return 0;
}

View file

@ -261,6 +261,7 @@ struct tp_dispatch {
struct {
int32_t right_edge; /* in device coordinates */
int32_t left_edge; /* in device coordinates */
int32_t vert_center; /* in device coordinates */
} palm;
struct {
@ -387,4 +388,7 @@ tp_gesture_post_events(struct tp_dispatch *tp, uint64_t time);
void
tp_gesture_stop_twofinger_scroll(struct tp_dispatch *tp, uint64_t time);
bool
tp_palm_tap_is_palm(struct tp_dispatch *tp, struct tp_touch *t);
#endif

View file

@ -2626,6 +2626,49 @@ START_TEST(touchpad_palm_detect_no_palm_moving_into_edges)
}
END_TEST
START_TEST(touchpad_palm_detect_tap)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
if (!touchpad_has_palm_detect_size(dev))
return;
libinput_device_config_tap_set_enabled(dev->libinput_device,
LIBINPUT_CONFIG_TAP_ENABLED);
litest_drain_events(li);
litest_touch_down(dev, 0, 95, 5);
litest_touch_up(dev, 0);
litest_assert_empty_queue(li);
litest_touch_down(dev, 0, 5, 5);
litest_touch_up(dev, 0);
litest_assert_empty_queue(li);
litest_touch_down(dev, 0, 5, 90);
litest_touch_up(dev, 0);
litest_assert_button_event(li,
BTN_LEFT,
LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li,
BTN_LEFT,
LIBINPUT_BUTTON_STATE_RELEASED);
litest_assert_empty_queue(li);
litest_touch_down(dev, 0, 95, 90);
litest_touch_up(dev, 0);
litest_assert_button_event(li,
BTN_LEFT,
LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li,
BTN_LEFT,
LIBINPUT_BUTTON_STATE_RELEASED);
litest_assert_empty_queue(li);
}
END_TEST
START_TEST(touchpad_left_handed)
{
struct litest_device *dev = litest_current_device();
@ -3681,6 +3724,7 @@ int main(int argc, char **argv) {
litest_add("touchpad:palm", touchpad_palm_detect_palm_becomes_pointer, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("touchpad:palm", touchpad_palm_detect_palm_stays_palm, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("touchpad:palm", touchpad_palm_detect_no_palm_moving_into_edges, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("touchpad:palm", touchpad_palm_detect_tap, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("touchpad:left-handed", touchpad_left_handed, LITEST_TOUCHPAD|LITEST_BUTTON, LITEST_CLICKPAD);
litest_add("touchpad:left-handed", touchpad_left_handed_clickpad, LITEST_CLICKPAD, LITEST_APPLE_CLICKPAD);