- Crear src/utils/time.zig para centralizar helpers de tiempo (timestamp, milliTimestamp, nanoTimestamp).
- Reemplazar std.io.fixedBufferStream por std.Io.Writer.fixed.
- Migrar de std.fs.cwd() a std.Io.Dir.cwd() y actualizar firmas de lectura/escritura.
- Reemplazar std.Thread.sleep por std.posix.system.nanosleep.
- Corregir capturas descartadas en switches (text_input => {}).
- Actualizar tests y ejemplos para compatibilidad con std.Io y nuevos helpers.
- Actualizar build.zig.zon a 0.16.0.
Co-Authored-By: Gemini <noreply@google.com>
177 lines
6.2 KiB
Zig
177 lines
6.2 KiB
Zig
//! Macro Demo - Demonstrates the macro recording system
|
|
//!
|
|
//! Press:
|
|
//! - R: Start/stop recording
|
|
//! - P: Play back recorded macro
|
|
//! - S: Save macro to file
|
|
//! - L: Load macro from file
|
|
//! - ESC: Quit
|
|
//!
|
|
//! Type any keys while recording to capture them.
|
|
|
|
const std = @import("std");
|
|
const zcatgui = @import("zcatgui");
|
|
|
|
const Framebuffer = zcatgui.render.Framebuffer;
|
|
const SoftwareRenderer = zcatgui.render.SoftwareRenderer;
|
|
const Sdl2Backend = zcatgui.backend.Sdl2Backend;
|
|
const MacroRecorder = zcatgui.MacroRecorder;
|
|
const MacroPlayer = zcatgui.MacroPlayer;
|
|
const Color = zcatgui.Color;
|
|
const Command = zcatgui.Command;
|
|
const KeyEvent = zcatgui.KeyEvent;
|
|
|
|
pub fn main() !void {
|
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
|
defer _ = gpa.deinit();
|
|
const allocator = gpa.allocator();
|
|
|
|
// Initialize backend
|
|
var backend = try Sdl2Backend.init("zcatgui - Macro Demo", 800, 600);
|
|
defer backend.deinit();
|
|
|
|
// Create framebuffer
|
|
var fb = try Framebuffer.init(allocator, 800, 600);
|
|
defer fb.deinit();
|
|
|
|
// Create renderer
|
|
var renderer = SoftwareRenderer.init(&fb);
|
|
|
|
// Create macro recorder
|
|
var recorder = MacroRecorder.init(allocator);
|
|
defer recorder.deinit();
|
|
|
|
// State
|
|
var running = true;
|
|
var last_keys: [10]KeyEvent = undefined;
|
|
var last_key_count: usize = 0;
|
|
var status_message: []const u8 = "Press R to start recording";
|
|
|
|
// Event injection function for playback
|
|
const inject = struct {
|
|
var injected_count: usize = 0;
|
|
|
|
fn injectKey(key: KeyEvent) void {
|
|
_ = key;
|
|
injected_count += 1;
|
|
std.debug.print("Injected key #{d}\n", .{injected_count});
|
|
}
|
|
}.injectKey;
|
|
|
|
while (running) {
|
|
// Poll events
|
|
while (backend.pollEvent()) |event| {
|
|
switch (event) {
|
|
.quit => running = false,
|
|
|
|
.key => |key| {
|
|
if (!key.pressed) continue;
|
|
|
|
// Record if recording
|
|
recorder.record(key);
|
|
|
|
// Store for display
|
|
if (last_key_count < last_keys.len) {
|
|
last_keys[last_key_count] = key;
|
|
last_key_count += 1;
|
|
} else {
|
|
// Shift left
|
|
for (0..last_keys.len - 1) |i| {
|
|
last_keys[i] = last_keys[i + 1];
|
|
}
|
|
last_keys[last_keys.len - 1] = key;
|
|
}
|
|
|
|
// Handle special keys
|
|
switch (key.key) {
|
|
.escape => running = false,
|
|
|
|
.r => {
|
|
if (recorder.isRecording()) {
|
|
_ = recorder.stop();
|
|
status_message = "Recording stopped";
|
|
std.debug.print("Stopped recording. {d} events captured.\n", .{recorder.eventCount()});
|
|
} else {
|
|
recorder.start();
|
|
status_message = "Recording...";
|
|
std.debug.print("Started recording.\n", .{});
|
|
}
|
|
},
|
|
|
|
.p => {
|
|
if (!recorder.isRecording() and recorder.eventCount() > 0) {
|
|
status_message = "Playing back...";
|
|
std.debug.print("Playing back {d} events.\n", .{recorder.eventCount()});
|
|
MacroPlayer.play(recorder.stop(), inject);
|
|
status_message = "Playback complete";
|
|
}
|
|
},
|
|
|
|
.s => {
|
|
if (recorder.eventCount() > 0) {
|
|
recorder.save(std.Options.debug_io, "macro.zcm") catch |err| {
|
|
std.debug.print("Save failed: {}\n", .{err});
|
|
};
|
|
status_message = "Saved to macro.zcm";
|
|
std.debug.print("Saved macro to macro.zcm\n", .{});
|
|
}
|
|
},
|
|
|
|
.l => {
|
|
recorder.load(std.Options.debug_io, "macro.zcm") catch |err| {
|
|
std.debug.print("Load failed: {}\n", .{err});
|
|
};
|
|
status_message = "Loaded from macro.zcm";
|
|
std.debug.print("Loaded macro: {d} events\n", .{recorder.eventCount()});
|
|
},
|
|
|
|
else => {},
|
|
}
|
|
},
|
|
|
|
.resize => |size| {
|
|
try fb.resize(size.width, size.height);
|
|
},
|
|
|
|
else => {},
|
|
}
|
|
}
|
|
|
|
// Clear
|
|
renderer.clear(Color.background);
|
|
|
|
// Draw title area
|
|
renderer.execute(Command.rect(0, 0, fb.width, 50, Color.rgb(40, 40, 40)));
|
|
|
|
// Draw status
|
|
const status_color = if (recorder.isRecording()) Color.danger else Color.foreground;
|
|
renderer.execute(Command.rect(10, 60, 200, 20, status_color));
|
|
|
|
// Draw event count
|
|
renderer.execute(Command.rect(10, 90, @intCast(recorder.eventCount() * 10), 20, Color.primary));
|
|
|
|
// Draw last keys as blocks
|
|
for (0..last_key_count) |i| {
|
|
const x: i32 = @intCast(10 + i * 50);
|
|
renderer.execute(Command.rect(x, 150, 40, 40, Color.secondary));
|
|
}
|
|
|
|
// Draw instructions area
|
|
renderer.execute(Command.rect(10, 250, 400, 120, Color.rgb(35, 35, 35)));
|
|
// Text would go here with a proper font
|
|
|
|
// Recording indicator
|
|
if (recorder.isRecording()) {
|
|
renderer.execute(Command.rect(@as(i32, @intCast(fb.width)) - 30, 10, 20, 20, Color.danger));
|
|
}
|
|
|
|
// Present
|
|
backend.present(&fb);
|
|
|
|
// Cap at ~60 FPS
|
|
const ts = std.posix.timespec{ .sec = 0, .nsec = 16 * std.time.ns_per_ms };
|
|
_ = std.posix.system.nanosleep(&ts, null);
|
|
}
|
|
|
|
std.debug.print("Final status: {s}\n", .{status_message});
|
|
}
|