Mods
Mods are the building blocks of a Foresight pipeline. Import everything with:
import fs8.mods;
Everything lives in the fs8 namespace. Full signatures are in the
API Reference.
Quick reference
| Mod | Category | What it does |
|---|---|---|
intercept |
Event provider | Reads kernel input devices and feeds events into the pipeline. |
io_manager |
Event provider | Poll-based fd readiness watcher; wakes the pipeline. |
input_manager |
Event provider | Owns devices, resolves queries, tracks hotplug. |
idle_detector |
Event provider | Detects pipeline idle and broadcasts an event. |
scheduler |
Event provider | Timer-based event scheduling via timerfd. |
replay |
Event provider | Plays back captured events from a file. |
output |
Output | Writes events to an fd (stdout by default). |
uinput |
Output | Creates virtual devices under /dev/uinput. |
router |
Output | Routes events to outputs by capability. |
emit / schedule_emit |
Output | Synthesize events (emit[press(...)]). |
type_string |
Output | Type text into the current app via xkb. |
capture |
Output | Buffer events and flush to a file on idle. |
replace / put |
Transformer | Rewrite one key/chord into another sequence. |
abs2rel |
Transformer | Absolute (tablet) to relative (mouse) movement. |
pen2mice |
Transformer | Pen buttons/tools to mouse clicks. |
pen2touch |
Transformer | Pen events to touch events. |
pressure2mouse_clicks |
Transformer | Pen pressure to mouse clicks by threshold. |
mouse_to_scroll |
Transformer | Mouse movement to scroll-wheel events. |
smooth |
Transformer | Mouse smoothing: lerp, low_pass_filter, kalman_filter. |
momentum_scroll |
Transformer | Inertial scrolling after input stops. |
scale_pen / scale_move |
Transformer | Scale pen or mouse movement by a factor. |
debounce |
Filter | Drop events arriving too soon after the same code. |
drop_* (30+ variants) |
Filter | Drop big jumps, init moves, fast repeats, etc. |
enforce_key_state |
Filter | Enforce valid key state transitions. |
sanitizer / diagnostics |
Filter | Pre-built filter groups for common bad events. |
on |
Control flow | Run actions while a condition is true. |
once |
Control flow | Fire once when a condition switches on. |
held / on_held |
Control flow | True while keys are held; gate with decider. |
hold_mod |
Control flow | Run a mod while modifiers are held; tap re-emits. |
pressed / pressed_any |
Condition | True when specific keys are down. |
keydown / keyup |
Condition | Match a key press or release event. |
longtime_released |
Condition | True when a key has been released for a while. |
limit_mouse_travel |
Condition | True while mouse travel stays under a limit. |
multi_click |
Condition | Double/triple click detection. |
swipe_* |
Condition | Swipe detection (left/right/up/down). |
led_on / led_off |
Condition | Keyboard LED state conditions. |
op |
Condition | Boolean combinators (&, \|, !). |
modes / switch_mode |
Control flow | Vim-like modes/layers. |
on_fail |
Control flow | Invoke an action when a condition fails. |
stopper |
Control flow | Exit the pipeline on demand. |
typed / timed_typed |
Condition | Match what the user is typing. |
keys_state |
State | Track the current state of every key. |
led_state / led_toggle |
State | Track keyboard LED state. |
mouse_history |
State | Track current/previous mouse positions. |
quantifier / mice_quantifier |
State | Threshold-step accumulation for movement. |
var_type |
State | Typed pipeline variables (context["name"]). |
startup_key_releases |
State | Sync pipeline with physical keyboard on launch. |
device (11 variants) |
Condition | Filter by which device an event came from. |
run |
Utility | Wrap functions as mods/callbacks. |
record |
Utility | Record events into a buffer for replay. |
group_mod |
Utility | Run a tuple of mods as a single mod. |
benchmark |
Utility | Measure mod performance (latency, percentiles). |
singleton |
Utility | Prevent multiple pipeline instances. |
live_view |
Output | Terminal event display for foresight replay --live. |
Event providers
These put events into the pipeline.
intercept
Query-driven event provider. Reads kernel devices matching device_queryes
and feeds their events in.
intercept[keyboard | required | grab, mouse | grab]
Needs io_manager and input_manager in the pipeline.
io_manager
Poll-based fd readiness manager. Registers file descriptors, waits for events, and dispatches each ready fd to its handler. Supports idle timeout.
input_manager
Owns and monitors discovered evdev devices. Resolves queries, tracks hotplug
via udev, answers "which device did this event come from?". Does NOT provide
events itself -- intercept is the event provider.
idle_detector
Detects pipeline idle (no events for a configurable period) and broadcasts an
idle special event. Supports repeat patterns: once,
consistent<PeriodUs>, exponential<BaseUs>.
scheduler
Timer-based event scheduler using timerfd registered with io_manager.
Required by momentum_scroll.
replay
Reads captured events from a file and injects them into the pipeline.
Auto-detects format (binary or evtest text). Returns exit when exhausted.
Output
output
Writes events to a file descriptor (stdout by default). The library-side redirect.
uinput
Creates virtual devices under /dev/uinput that events can be written to.
Can clone a physical device's capabilities into a virtual device.
uinput // creates a virtual device and writes events to it
router
Routes events to specific output devices by capability. Uses a hash-based lookup table.
router[caps::mouse >> uinput, caps::keyboard >> keyboard_pipeline]
emit / schedule_emit
Synthesize events. Build event sequences with press(...), down(...),
up(...), keypress(...), turn_led_on(...), turn_led_off(...).
emit[press(KEY_LEFTMETA, KEY_TAB)]
schedule_emit + press(BTN_RIGHT)
type_string
Type text into the current application via xkb how2type.
type_string("hello world")
capture
Buffer events in memory and flush to a file during idle periods. Supports
daily, hourly, weekly, monthly, uptime-based, single-file, and manual
rotation. Output formats: capture_binary_format (raw .fs8) and
capture_evtest_format (human-readable .evtest.fs8).
Transformers
replace / put
Rewrite one key/chord into another sequence. On press, replacements are emitted in order; on release, they are emitted in reverse order.
replace[KEY_D, KEY_LEFTMETA, KEY_LEFTCTRL, KEY_RIGHT]
put[KEY_A] // rewrite the current event's code to KEY_A
abs2rel
Convert absolute events (drawing tablets) into relative events (mouse).
pen2mice
Translate a pen tablet's buttons/tools into mouse clicks.
pen2touch
Convert pen events to touch events.
pressure2mouse_clicks
Convert pen pressure into mouse clicks based on a threshold.
mouse_to_scroll
Convert mouse movement into scroll-wheel events. Pure transformer with no
condition of its own -- gate it with hold_mod.
on_held[KEY_CAPSLOCK, BTN_MIDDLE, context | kalman_filter[0.3f] | mouse_to_scroll]
Requires mice_quantifier in the pipeline.
smooth
Mouse movement smoothing. Three strategies:
lerp[max_steps, easing] // interpolate with easing (default: easeOutQuad)
low_pass_filter[alpha] // exponential moving average
kalman_filter[q, r] // 1D Kalman filter per axis
All require mouse_history placed before them in the pipeline.
momentum_scroll
Inertial scrolling after input stops. Tracks velocity and schedules momentum
events via scheduler. Requires scheduler in the pipeline.
scale_pen / scale_move
Scale movement events by a factor.
on[held[KEY_LEFTSHIFT], context | scale_move[0.5f] | scale_pen[0.5f]]
autocomplete
Watch typed patterns of the form PREFIX<TAG>COMPLETION and auto-complete
them. In trigger mode, fires on a trigger keypress; in auto_mode, fires as
soon as the prefix is fully typed.
Filters
debounce
Drop events that arrive too soon after a previous event of the same code. For
EV_KEY, a fast second press and its release are dropped (faulty double-clicks,
bouncing keys). For other event types, every event within the window is dropped.
debounce[BTN_LEFT, BTN_RIGHT]
debounce[{.type = EV_ABS, .code = ABS_X}]
drop_* family
Over 30 variants for filtering bad or unwanted events:
| Mod | What it drops |
|---|---|
drop_big_jumps |
Large mouse movements |
drop_init_moves |
Initial mouse movements after connect |
drop_start_moves |
Mouse moves at the start of an action |
drop_mouse_moves |
All mouse movement events |
drop_zero_mouse_moves |
Mouse moves with zero delta |
drop_mouse_clicks |
Mouse button events |
drop_fast_repeats |
Fast auto-repeat events |
drop_adjacent_repeats |
Consecutive duplicate events |
drop_adjacent_syns |
Consecutive SYN_REPORTs |
drop_fast_left_clicks |
Fast left-click press+release |
drop_fast_right_clicks |
Fast right-click press+release |
drop_fast_double_clicks |
Fast double-click sequences |
drop_keys[...] |
Specific key events |
drop_repeats_of[...] |
Auto-repeat (value 2) of specific keys |
drop_caps[...] |
Events matching specific device capabilities |
drop_abs |
All absolute axis events |
drop_tablet |
All tablet events |
drop_caps |
CapsLock-related events |
drop_msc_scan |
MSC_SCAN events |
drop_late_syn |
Empty sync packets after long idle |
drop_pen_out_of_bounds |
Pen ABS values outside device bounds |
drop_orphan_abs |
ABS position events before any tool press |
drop_missing_syns |
Events when SYN_REPORT framing is broken |
drop_event |
Returns drop_event (any event) |
exit_pipeline |
Returns exit (stops the pipeline) |
enforce_key_state
Enforce valid key state transitions: no orphan releases, no repeats without prior press, no double presses.
sanitizer / diagnostics / sieve
Pre-built filter groups:
sanitizer-- all default checks, silent dropdiagnostics-- same checks, log only (no drop)sieve-- drop bad events and log each one
Conditions and control flow
on / once
on[cond, ...actions] runs actions while a condition is true (toggles
on/off). once[cond, ...actions] fires only when the condition switches on.
on[pressed[BTN_RIGHT], drop_start_moves]
once[pressed[KEY_CAPSLOCK, KEY_LEFTSHIFT, KEY_ESC], exit_pipeline]
// Sub-pipeline inside on:
on[pressed[KEY_CAPSLOCK] | led_off[LED_CAPSL],
context | abs2rel | pen2mice | router[mouse >> uinput]]
pressed / pressed_any
True when specific key(s) are currently down.
pressed[KEY_A]
pressed_any[BTN_LEFT, BTN_RIGHT]
keydown / keyup
Match a key press or release event (edge-triggered, not level).
keydown[KEY_X]
keyup[BTN_LEFT]
held / on_held
held[key] is true while a key is held (suppresses auto-repeat).
held[key, decider] gates whether the held key is swallowed or emitted.
on_held[modifier, key, mod] runs a mod while modifier keys are held. A quick
tap re-emits as a real press+release; a hold swallows the release.
on[held[KEY_LEFTSHIFT], context | scale_move[0.5f]]
on_held[KEY_CAPSLOCK, BTN_MIDDLE, context | mouse_to_scroll]
hold_mod
Run a mod while modifier keys are held. Quick taps re-emit as real press+release, holds swallow the release.
hold_mod[KEY_CAPSLOCK, BTN_MIDDLE, mouse_to_scroll]
longtime_released
True when a key has been released for a while.
limit_mouse_travel
True while mouse travel stays under a limit.
once[limit_mouse_travel[pressed[KEY_CAPSLOCK], 50] & keyup[BTN_LEFT],
schedule_emit + press(BTN_RIGHT)]
multi_click / double_click / triple_click
Double/triple click detection. Requires keys_state in the pipeline.
once[pressed[BTN_MIDDLE] & triple_click, emit[press(KEY_LEFTMETA, KEY_TAB)]]
swipe_*
Swipe detection: swipe_left, swipe_right, swipe_up, swipe_down.
Requires swipe_detector in the pipeline.
on[pressed_any[KEY_CAPSLOCK, BTN_MIDDLE] & pressed[BTN_LEFT],
context
| on[swipe_right, emit[press(KEY_LEFTCTRL, KEY_LEFTMETA, KEY_RIGHT)]]
| on[swipe_left, emit[press(KEY_LEFTCTRL, KEY_LEFTMETA, KEY_LEFT)]]]
led_on / led_off
Conditions based on keyboard LED state. Requires led_state in the pipeline.
on[pressed[KEY_CAPSLOCK] | led_off[LED_CAPSL], ...]
op
Boolean combinators. op is an empty and; op | condition is the
idiomatic way to start a condition.
op & pressed[KEY_A] & pressed[KEY_B]
op | pressed[KEY_F1]
!always_disable
modes / switch_mode
Vim-like modes/layers. Cycles through mod pipelines when a trigger condition is true.
modes[multi_click[KEY_RIGHTCTRL],
context, // Mode 0: empty
context // Mode 1: express
| replace[KEY_D, KEY_LEFTMETA, KEY_LEFTCTRL, KEY_RIGHT]
| on[pressed[KEY_ESC], switch_mode[0]]]
on_fail
When a condition check fails, invoke a side-effect action.
on_fail[condition, action, extra...]
stopper
Exit the pipeline on demand. Call stopper.stop() to set the flag; the next
event causes the pipeline to return exit.
State
keys_state
Tracks the current state of every key via a bitset. Provides is_pressed(),
is_pressed_any(), is_released(), release_all(). Seeds from the device's
EVIOCGKEY bitmap on connect.
led_state / led_toggle
led_state tracks keyboard LED state (CapsLock, NumLock, ScrollLock).
led_toggle flips the CapsLock mode. Also provides capslock_off,
numlock_off, scrolllock_off.
mouse_history
Tracks current/previous mouse positions in a circular buffer. Updated on
EV_REL events, pushed on EV_SYN. Required by smoothing mods (lerp,
low_pass_filter, kalman_filter).
quantifier / mice_quantifier
Threshold-step accumulation for movement. quantifier works for a single
event code; mice_quantifier tracks both X and Y axes. Required by
mouse_to_scroll.
var_type
Typed pipeline variables. Share values between mods via context["name"]
lookup.
startup_key_releases
On device connect, queries the EVIOCGKEY bitmap and releases any held keys.
Useful when the pipeline is launched by a key press.
Device conditions
The device mod provides conditions and filters based on which device an
event came from:
| Mod | What it does |
|---|---|
from_device |
True if event is from a specific device node |
from_stdin |
True if event is from stdin (redirect mode) |
self_emitted |
True if event was synthesized by this pipeline |
from_chained |
True if event is from another foresight process |
device_is |
Check device identity |
only_device |
Drop events not from the specified device |
drop_device |
Drop events from a specific device |
drop_origin |
Drop events by source ID |
drop_self |
Drop synthesized + owned events |
drop_owned |
Drop only events from owned uinput devices |
drop_emitted |
Drop only synthesized events |
Utility
run (lambda)
Wrap one or more functions so they can be used as mods or callbacks.
on[pressed[KEY_A], run([](Context auto& ctx) { /* ... */ })]
record
Record events into a buffer for later replay or inspection. Provides
events(), count(), any(), all(), filter(), keys().
group_mod
Run a tuple of mods as a single mod. If any mod returns drop_event, the
event is dropped.
benchmark
Performance measurement wrapper. Records call count, total/average/min/max latency, standard deviation, and percentiles (p50/p95/p99).
singleton
Prevent multiple instances of the same pipeline from running concurrently. Uses a Linux abstract Unix socket.
live_view
Terminal event display. condensed_view_output aggregates mouse movements by
direction and tracks keyboard hold durations. Used by
foresight replay --live.
Context actions
Mods return a context_action to communicate intent:
| Action | Meaning |
|---|---|
next |
Pass the event to the next mod. |
drop_event |
Drop this event. |
recovery |
Restart / enter watch mode. |
exit |
Exit the pipeline. |