Skip to content

iskamag/touchtoy

Repository files navigation

A gesture-language interpreter for laptop touchpads. Raw touches come in via evdev straight from /dev/input/eventN (or a mouse fallback), get classified into gesture tokens by a CLOS pipeline, and feed a rule engine where sequences of gestures form a language

The formulas for the whole pipeline is written in docs/gesture-math.md; the spec which src/stroke.lisp implements

Run

(asdf:load-system :touchtoy)

;; the demo: a real-time sigil-dueling card game (see below)
(touchtoy:start-touchpad-game)                  ; on a touchpad
(touchtoy:start-game)                           ; mouse fallback (no touchpad needed)

;; tools
(touchtoy:start-touchpad-monitor)               ; terminal gesture printer + trail
(touchtoy:start-touchpad-canvas)                ; swap-on-scratch demo + water ripples
(touchtoy:start-touchpad-monitor :grab t)       ; exclusive grab
(touchtoy:start-monitor)                        ; mouse fallback monitor
(touchtoy:start-canvas)

ESC quits, R restarts the game. Touchpad access needs membership in the input group for /dev/input/eventN.

The demo — JESTURE: Sigil Duel

You vs the Jester. Your spellbook is a row of cards along the bottom; each card is a sigil, a sequence of gestures. Draw a card's sigil to cast it.

sigil (draw this) card effect
line Jab quick damage
corner (quarter-arc) Arc damage
circle Ward shield
half-scratch (the arrow) Pierce damage, ignores shield
scratch Reverse reflect the Jester's telegraphed spell
corner -> line Nova big damage (a two-gesture combo)
  • Energy regenerates in real time; the Jester casts on its own clock, act live.
  • Two fingers spread = Amplify the next cast; pinch = Surge energy; two-finger swipe scrolls the book (these stream live, not on lift).
  • Hold a finger in the bottom-left corner = Guard (the spec's reserved global zone) — halves the next hit.
  • Single sigils fire instantly; a combo (e.g. Nova) chains if you draw the next gesture within ~0.5 s, otherwise the partial incantation resolves on its own.

It is the framework's stress test: gesture language (sequenced sigils through the rule engine), speed (real-time energy + AI), liveness (streamed scroll/pinch), zones + modifier, and multitouch.

Gesture vocabulary

CLOS classes: dot, line, corner, circle, scratch, half-scratch, expand, shrink, pan, modifier. Protocol: gesture-kind, gesture-direction, gesture-from, gesture-to, gesture-bbox, gesture-inner.

Highlights of the corrected classifier (full detail in the math doc):

  • corner = a quarter-circle arc (per the spec), not a straight diagonal line.
  • scratch vs half-scratch is decided by the opening angle between the two arms, length-invariant. A scratch retraces; a half-scratch (the arrow / Aries ♈) mirrors.
  • one stroke can contain several tokens (vertices split it).
  • expand / shrink are isolated from translation and rotation by a similarity decomposition, so a multitouch swipe (pan) or orbit is never misread as a pinch.
  • dot vs modifier is decided by duration + concurrency: a brief stationary tap is a dot; a held one (or one held while another finger draws) is a modifier carrying its zone.

Liveness

Beyond the discrete on-lift tokens, the input layer streams a live channel while fingers are down: (:drag ...) for single-finger moves and (:scroll ...) / (:pinch …) for two fingers, so things can be dragged and scrolled in real time. A stroke the app consumes live is suppressed from the discrete stream.

Rules

(defrule name context pattern lambda-list &body body)

Pattern items: :keyword (exact kind), (var keyword) (typed bind), var (bind any). Rules are tried longest-pattern-first; the buffer is held while a prefix of some longer rule could still match, and a chord timeout (flush-buffer) resolves a partial sequence that has gone quiet.

(defrule swap :canvas ((a :tap-object) (b :tap-object) :scratch) (ga gb gs)
  (declare (ignore gs))
  (rotatef (tt-object-x (cdr ga)) (tt-object-x (cdr gb))))

Tests

(asdf:load-system :touchtoy)
(load "tests/test-classifier.lisp")
(touchtoy-tests:run-tests)

Covers every primitive, scratch/half-scratch (kind under jitter + inner shape on clean geometry), multitouch (expand/shrink and the swipe/orbit rejections), tap-vs-modifier, and two seeded hit-rate tests for imperfect scratches and arrows.

About

little demo for gesture recognition

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors