Skip to content

Recording & Playback ​

ZMouse can record mouse and keyboard events and replay them later with preserved timing.

How Recording Works ​

When you start recording, ZMouse installs Windows low-level hooks that capture:

  • Mouse movements
  • Mouse clicks (left, right, double)
  • Mouse scroll events
  • Keyboard key presses and releases

All events are timestamped relative to when recording started.

CLI Recording ​

Start Recording ​

> rec
  Recording started. Use 'stop' to finish.

While recording, ZMouse captures all system-wide mouse and keyboard input.

Stop Recording ​

> stop
  Recording stopped. 42 events captured.

Save to File ​

> save my_macro.json
  Saved 42 events to 'my_macro.json'

Load from File ​

> load my_macro.json
  Loaded 42 events from 'my_macro.json'

Playback ​

> play
  Playing 42 events...
  Playback complete.

HTTP API Recording ​

Check Status ​

bash
curl http://localhost:4000/api/recording/status
# {"recording":false,"events":0}

Start Recording ​

bash
curl -X POST http://localhost:4000/api/recording/start
# {"ok":true}

Stop Recording ​

bash
curl -X POST http://localhost:4000/api/recording/stop
# {"ok":true,"events":42}

Save Events ​

bash
curl -X POST http://localhost:4000/api/recording/save \
  -d '{"filename":"macro.json"}'
# {"ok":true,"events":42}

Load Events ​

bash
curl -X POST http://localhost:4000/api/recording/load \
  -d '{"filename":"macro.json"}'
# {"ok":true,"events":42}

Playback ​

bash
curl -X POST http://localhost:4000/api/recording/play
# {"ok":true}

Library API ​

zig
const zmouse = @import("zmouse");

// Initialize recorder
var recorder = zmouse.Recorder.init(allocator);
defer recorder.deinit();

// Start recording
try recorder.startRecording();

// ... user performs actions ...

// Stop recording
recorder.stopRecording();

// Get event count
const count = recorder.getEventCount();

// Get events
const events = recorder.getEvents();

// Save to file
try zmouse.storage.saveEvents(events, "macro.json", allocator);

// Load from file
const loaded = try zmouse.storage.loadEvents("macro.json", allocator);
defer allocator.free(loaded);

// Set events from loaded data
try recorder.setEvents(loaded);

// Clear events
recorder.clearEvents();

JSON Format ​

Events are stored in JSON format:

json
{
  "version": 1,
  "events": [
    {"t": 0, "type": "move", "x": 500, "y": 300},
    {"t": 150, "type": "left_down", "x": 500, "y": 300},
    {"t": 200, "type": "left_up", "x": 500, "y": 300},
    {"t": 500, "type": "key_down", "x": 0, "y": 0, "data": 65},
    {"t": 550, "type": "key_up", "x": 0, "y": 0, "data": 65}
  ]
}

Event Types ​

TypeDescription
moveMouse movement
left_downLeft mouse button pressed
left_upLeft mouse button released
right_downRight mouse button pressed
right_upRight mouse button released
wheelMouse scroll
key_downKeyboard key pressed
key_upKeyboard key released

Fields ​

FieldDescription
tTimestamp in milliseconds
typeEvent type
x, yMouse coordinates (0 for keyboard)
dataWheel delta or virtual key code

Architecture ​

┌─────────────────┐
│   Main Thread   │
│   (REPL/HTTP)   │
└────────┬────────┘
         │ startRecording()
         ▼
┌─────────────────┐
│  Hook Thread    │
│  (message pump) │
│                 │
│ WH_MOUSE_LL     │◄── System mouse events
│ WH_KEYBOARD_LL  │◄── System keyboard events
└────────┬────────┘
         │ appendEvent()
         ▼
┌─────────────────┐
│ Recorder.events │
│ (ArrayListUnmanaged)
└─────────────────┘

The hook thread runs a Windows message pump to receive low-level input events. Events are stored with timestamps for accurate playback.

Use Cases ​

  • Automation: Record repetitive tasks and replay them
  • Testing: Record UI interactions for automated testing
  • Macros: Create reusable input sequences
  • Remote control: Record on one machine, replay via HTTP API

Tips ​

  • Keep recordings short for reliability
  • Avoid recording sensitive keyboard input (passwords)
  • Test recordings before using in production
  • Playback timing is preserved from the original recording

Released under the MIT License.