Something went wrong. Try again.
Monorepo for Aesthetic.Computer aesthetic.computer
Something went wrong. Try again.
C
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153// surface-audit.c — trackpad multitouch regression harness.//// Replays a synthetic MT-B event stream through the surface tracker in// input.c and checks the contact set it produces. This is the regression// backbone for playing the trackpad as a surface: the drum head needs every// finger, since the resting ones damp the modes the striking one excites,// so a dropped or misattributed contact is an audible bug, not a cosmetic// one. The harness includes input.c directly to reach its statics.//// Build: cc -O2 -I ../src surface-audit.c -lm -o /tmp/surface-audit// Run: /tmp/surface-audit//// PASS = every check below. Linux only (evdev headers).
#include "input.c"
static ACInput *I;
static void feed(int type, int code, int value) { struct input_event ev = { .type = type, .code = code, .value = value }; if (type == EV_ABS) surface_abs(&I->surface, &ev); else if (type == EV_SYN && code == SYN_REPORT) surface_sync(I);}
#define SLOT(n) feed(EV_ABS, ABS_MT_SLOT, n)#define ID(n) feed(EV_ABS, ABS_MT_TRACKING_ID, n)#define X(n) feed(EV_ABS, ABS_MT_POSITION_X, n)#define Y(n) feed(EV_ABS, ABS_MT_POSITION_Y, n)#define SYN() feed(EV_SYN, SYN_REPORT, 0)
// Synaptics ranges from a ThinkPad pad, the first target hardware.#define PAD_X0 1266#define PAD_X1 5676#define PAD_Y0 1096#define PAD_Y1 4758#define PAD_CX ((PAD_X0 + PAD_X1) / 2)#define PAD_CY ((PAD_Y0 + PAD_Y1) / 2)
static int fails = 0;
static void check(const char *what, int got, int want) { if (got != want) { printf(" FAIL %s: got %d want %d\n", what, got, want); fails++; } else printf(" ok %s = %d\n", what, got);}
static void checkf(const char *what, float got, float want) { if (fabsf(got - want) > 0.002f) { printf(" FAIL %s: got %.4f want %.4f\n", what, got, want); fails++; } else printf(" ok %s = %.3f\n", what, got);}
static void advanced(const char *what, int before, int now) { if (now > before) printf(" ok %s: %d -> %d\n", what, before, now); else { printf(" FAIL %s: stuck at %d\n", what, now); fails++; }}
int main(void) { I = calloc(1, sizeof(ACInput)); I->scale = 1; I->screen_w = 1920; I->screen_h = 1080; I->pointer_x = 500; I->pointer_y = 500; ACTouchSurface *s = &I->surface; s->fd_index = 0; s->has_slots = 1; s->x_min = PAD_X0; s->x_max = PAD_X1; s->y_min = PAD_Y0; s->y_max = PAD_Y1; s->x_res = 42; s->y_res = 42; surface_clear(s); s->aspect = input_touch_aspect(I);
printf("pad aspect drives the membrane boundary:\n"); checkf("aspect", s->aspect, (float)(PAD_X1 - PAD_X0) / (float)(PAD_Y1 - PAD_Y0));
printf("\none finger down, dead center:\n"); SLOT(0); ID(77); X(PAD_CX); Y(PAD_CY); SYN(); check("contacts", s->contacts, 1); ACTouchSlot pts[MAX_TOUCH_SLOTS]; int n = input_touch_contacts(I, pts, MAX_TOUCH_SLOTS); check("snapshot", n, 1); checkf("x", pts[0].x, 0.5f); checkf("y", pts[0].y, 0.5f);
printf("\nsecond finger rests at a corner:\n"); SLOT(1); ID(78); X(PAD_X0); Y(PAD_Y0); SYN(); check("contacts", s->contacts, 2); check("snapshot", input_touch_contacts(I, pts, MAX_TOUCH_SLOTS), 2); checkf("corner x", pts[1].x, 0.0f); checkf("corner y", pts[1].y, 0.0f);
printf("\na resting finger must not drag the pointer:\n"); int px = I->pointer_x; SLOT(1); X(PAD_X0 + 134); SYN(); check("pointer held", I->pointer_x, px);
printf("\nthe primary finger does move it:\n"); SLOT(0); X(PAD_CX + 420); SYN(); advanced("pointer", px, I->pointer_x);
printf("\nprimary lifts — handoff without a jump:\n"); px = I->pointer_x; SLOT(0); ID(-1); SYN(); check("contacts", s->contacts, 1); check("pointer held", I->pointer_x, px); check("primary reassigned", s->primary_id, 78);
printf("\nthe surviving finger now drives it:\n"); SLOT(1); X(PAD_X0 + 1134); SYN(); advanced("pointer", px, I->pointer_x);
printf("\nall fingers up:\n"); SLOT(1); ID(-1); SYN(); check("contacts", s->contacts, 0); check("snapshot", input_touch_contacts(I, pts, MAX_TOUCH_SLOTS), 0); check("primary cleared", s->primary_id, -1);
printf("\na slot past the array is discarded, not written through:\n"); SLOT(MAX_TOUCH_SLOTS + 3); ID(90); X(3000); Y(3000); SYN(); check("contacts", s->contacts, 0);
printf("\na contact is withheld until it has both coordinates:\n"); SLOT(2); ID(91); SYN(); check("id alone", s->contacts, 0); X(3000); SYN(); check("x only", s->contacts, 0); Y(3000); SYN(); check("x and y", s->contacts, 1);
printf("\ncoordinates clamp to the pad:\n"); SLOT(2); X(PAD_X1 + 9999); Y(PAD_Y0 - 5000); SYN(); input_touch_contacts(I, pts, MAX_TOUCH_SLOTS); checkf("clamped x", pts[0].x, 1.0f); checkf("clamped y", pts[0].y, 0.0f);
// A drum reads `generation` to know the hand changed. Counting contacts // alone could not see one finger land as another lifted inside a single // report — same count, different hand — and an instrument polling per // frame would swallow that strike entirely. printf("\none finger replacing another in one report is a change:\n"); SLOT(2); ID(-1); SLOT(3); ID(92); X(PAD_CX); Y(PAD_CY); SYN(); check("contacts", s->contacts, 1); int gen_swap = s->generation; SLOT(3); ID(-1); SLOT(4); ID(93); X(PAD_CX); Y(PAD_CY); SYN(); check("still one contact", s->contacts, 1); advanced("generation", gen_swap, s->generation);
printf("\nan unchanged hand does not bump generation:\n"); int gen_still = s->generation; SYN(); check("generation held", s->generation, gen_still);
printf("\n%s (%d failure%s)\n", fails ? "FAILED" : "PASSED", fails, fails == 1 ? "" : "s"); return fails != 0;}