Test palm rejection for add-page button taps
Move the draw-or-navigate choice into touchIntent() so the rule the canvas uses can be tested, and cover finger taps on the plus button: accepted after writing and while the pen hovers, rejected while the pen is down, for palm-sized contacts and right after pen activity. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GaoZtJQZwLXkEgWs8twCia
This commit is contained in:
parent
2760819466
commit
d2c6e617bb
3 changed files with 45 additions and 3 deletions
|
|
@ -16,7 +16,7 @@
|
|||
import { bounds, intersects, rectBeside, type Rect } from '$lib/model/layout';
|
||||
import { canInsert, freeSlots, freeSlotsOf, neighbor, type Dir, type Slot } from '$lib/model/tree';
|
||||
import { A4, PAGE_PRESETS, type Stroke } from '$lib/model/types';
|
||||
import { PalmRejector } from '$lib/ink/palm';
|
||||
import { PalmRejector, touchIntent } from '$lib/ink/palm';
|
||||
import { StrokeRecorder, hitStroke } from '$lib/ink/stroke';
|
||||
import { pageCssVars } from '$lib/editor/pageStyle';
|
||||
import { downloadCanvas } from './download';
|
||||
|
|
@ -301,7 +301,7 @@
|
|||
// pen-down, palm-sized contacts and right after pen use, but not for the 5 s pen session.
|
||||
const plus = target.closest<HTMLElement>('.ghost');
|
||||
if (e.pointerType === 'touch') {
|
||||
const decision = palm.evaluate(e, fingerInks && !plus ? 'draw' : 'navigate');
|
||||
const decision = palm.evaluate(e, touchIntent(fingerInks, !!plus));
|
||||
if (!decision.accept) return; // palm: ignore entirely
|
||||
touches.set(e.pointerId, p);
|
||||
if (touches.size >= 2) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { PalmRejector } from './palm';
|
||||
import { PalmRejector, touchIntent } from './palm';
|
||||
|
||||
const ev = (type: string, pointerType: string, extra: Partial<PointerEvent> = {}) =>
|
||||
({ type, pointerType, pointerId: pointerType === 'pen' ? 1 : 2, width: 10, height: 10, ...extra }) as PointerEvent;
|
||||
|
|
@ -53,4 +53,37 @@ describe('palm rejection', () => {
|
|||
it('allows finger ink again once the pen session ends', () => {
|
||||
expect(afterPen(5100).evaluate(touch(), 'draw').accept).toBe(true);
|
||||
});
|
||||
|
||||
describe('add-page button taps', () => {
|
||||
// With a pen in use fingers don't ink, but finger ink may still be on (before any pen).
|
||||
const tap = (palm: PalmRejector, extra: Partial<PointerEvent> = {}, fingerInks = false) =>
|
||||
palm.evaluate(touch(extra), touchIntent(fingerInks, true));
|
||||
|
||||
it('are handled as navigation even when fingers ink', () => {
|
||||
expect(touchIntent(true, true)).toBe('navigate');
|
||||
expect(touchIntent(false, true)).toBe('navigate');
|
||||
expect(touchIntent(true, false)).toBe('draw');
|
||||
expect(touchIntent(false, false)).toBe('navigate');
|
||||
});
|
||||
|
||||
it('are accepted a couple of seconds after writing', () => {
|
||||
expect(tap(afterPen(2000)).accept).toBe(true);
|
||||
expect(tap(afterPen(2000), {}, true).accept).toBe(true);
|
||||
});
|
||||
|
||||
it('are accepted while the pen hovers', () => {
|
||||
expect(tap(afterPen(2000, { leave: false })).accept).toBe(true);
|
||||
});
|
||||
|
||||
it('are rejected while the pen is down', () => {
|
||||
const palm = new PalmRejector();
|
||||
palm.track(ev('pointerdown', 'pen'));
|
||||
expect(tap(palm).accept).toBe(false);
|
||||
});
|
||||
|
||||
it('are rejected for a palm or right after the pen', () => {
|
||||
expect(tap(afterPen(2000), { width: 60, height: 40 }).accept).toBe(false);
|
||||
expect(tap(afterPen(50)).accept).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -27,6 +27,15 @@ const PALM_CONTACT_PX = 35;
|
|||
/** What an accepted touch would do: ink (draw/erase) or pan/zoom. */
|
||||
export type TouchIntent = 'draw' | 'navigate';
|
||||
|
||||
/**
|
||||
* Which policy a touch falls under. It only draws when finger ink is on and it
|
||||
* didn't land on a button; taps on buttons (e.g. add page) navigate, so they keep
|
||||
* working between pen strokes.
|
||||
*/
|
||||
export function touchIntent(fingerInks: boolean, onButton: boolean): TouchIntent {
|
||||
return fingerInks && !onButton ? 'draw' : 'navigate';
|
||||
}
|
||||
|
||||
export interface Decision {
|
||||
accept: boolean;
|
||||
reason: string;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue