Macro Recorder | On Hax
Author: [Your Name] Date: April 16, 2026 Abstract This paper presents the design and implementation of a macro recording and playback system built with the Haxe programming language. Leveraging Haxe’s macro system and its cross-compilation abilities, the recorder captures low-level input events (mouse, keyboard) and replays them across multiple targets (Windows, macOS, Linux, and web). We discuss the architecture, event serialization, timing fidelity, and limitations imposed by sandboxed environments. The result is a lightweight, embeddable automation tool suitable for UI testing, repetitive task automation, and educational demonstrations of Haxe’s meta-programming. 1. Introduction Macro recorders capture user input for later replay. Traditional solutions (AutoHotkey, Sikuli, Python’s pynput ) are platform-specific or require heavy runtimes. Haxe offers a unique advantage: write once, compile to C++, JavaScript, Python, Lua, C#, and more . However, accessing system-level input hooks requires platform-native extensions.
Instead of interpreting events at runtime, we can embed the recorded macro as Haxe code using a build macro: macro recorder on hax
| Target | Capture Accuracy | Replay Jitter (avg) | Limitations | |------------|----------------|---------------------|---------------------------------| | Windows 11 | ±2 ms | ±4 ms | Needs admin for global hooks | | macOS 14 | ±3 ms | ±5 ms | Accessibility permission req. | | Linux (X11)| ±5 ms | ±7 ms | X11 record extension required | | Web (JS) | Not global | N/A | Only within canvas/iframe | Author: [Your Name] Date: April 16, 2026 Abstract
function replay(events:Array<MacroEvent>, speed:Float = 1.0):Void var i = 0; var startTime = haxe.Timer.stamp() * 1000; var timer = new haxe.Timer(1); // 1ms resolution timer.run = function() if (i >= events.length) timer.stop(); return; var now = (haxe.Timer.stamp() * 1000) - startTime; var targetTime = events[i].timestamp / speed; if (now >= targetTime) simulateEvent(events[i]); i++; ; The result is a lightweight, embeddable automation tool
class Recorder static var events: Array<MacroEvent> = []; static var startTime: Int; public static function start():Void startTime = haxe.Timer.stamp() * 1000; InputHook.onMouseMove = (x, y) -> var now = (haxe.Timer.stamp() * 1000) - startTime; events.push(MouseMove(x, y, now)); ; // ... similar for keys/buttons
// Macro that reads a JSON macro file and generates a function static macro function embedMacro(path:String):Expr var json = sys.io.File.getContent(path); var events:Array<MacroEvent> = haxe.Json.parse(json); var exprBlocks = []; for (e in events) exprBlocks.push(macro simulateEvent($ve)); exprBlocks.push(macro haxe.Timer.delay(..., $ve.timestamp)); // simplified return macro $bexprBlocks;
This generates a replay function with zero runtime parsing overhead. We tested the macro recorder on three platforms: