summaryrefslogtreecommitdiff
path: root/src/deck.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-07-30 23:35:45 -0300
committerGabriel Schneider <[email protected]>2026-08-01 15:02:07 -0300
commit19f7322100062b7c1adcde3376063ce6c1d8c72d (patch)
treeb76347dffe0347c29a38b4cad6031678683dba74 /src/deck.zig
parent753d5451ca7d09dbc5ff44f3c2dcf9a47fb87f96 (diff)
downloadpardes-19f7322100062b7c1adcde3376063ce6c1d8c72d.tar.gz
pardes-19f7322100062b7c1adcde3376063ce6c1d8c72d.zip
structure: backends into src/{tty,gui,lsp}, pane kinds and builtins into their own files
The core now lies FLAT at src/ and every subdirectory is one backend, so a file being in no directory at all is what says it is core. Pane-kind bodies leave pardes.zig for term_pane.zig / file_pane.zig / output_pane.zig, leaving it the layout, the event/effect machine and the generic render loop. Builtins are one struct each in builtins.zig, and the enum is folded out of the file's own declaration list at comptime — a zig file IS a struct, so the list of builtins and the builtins themselves are the same text. Adding one is writing a struct. Key paths deliberately stay one table for the config pass. Pure refactor: no golden moved.
Diffstat (limited to 'src/deck.zig')
-rw-r--r--src/deck.zig204
1 files changed, 0 insertions, 204 deletions
diff --git a/src/deck.zig b/src/deck.zig
deleted file mode 100644
index 1859bae8..00000000
--- a/src/deck.zig
+++ /dev/null
@@ -1,204 +0,0 @@
-//! Steam Deck controls -> editor input, as a pure state machine: gui.zig
-//! feeds SDL gamepad events in and applies the returned actions (cursor
-//! moves, synthetic clicks, wheel ticks, keys, rumble), so the whole
-//! mapping replays off-device from deckcap recordings (test/deck/).
-//!
-//! Layout: right pad moves the pointer (relative, laptop-touchpad-style) and
-//! a firm press on it = select (button 1); left pad scrolls and a firm press
-//! = look (button 3); R2 = select, L2 = execute (button 2), L1 = look, dpad
-//! down/up = n/N, A = Enter, Y = Tab, the back paddles (L4/R4/L5/R5) toggle
-//! the terminal (Ctrl-b); execute, look and pad-clicks request a brief rumble
-//! ack. (The GUI mirrors this on the sticks: right stick = pointer, left
-//! stick = scroll.)
-
-const std = @import("std");
-
-// SDL_GamepadButton / SDL_GamepadAxis / touchpad indices (SDL3), verified
-// against real deck recordings (test/deck/*.zon) and the pinned SDL's
-// hidapi deck driver (touchpad 0 = left pad, 1 = right pad).
-pub const BTN_A = 0; // SOUTH
-pub const BTN_Y = 3; // NORTH
-pub const BTN_L1 = 9; // LEFT_SHOULDER
-pub const BTN_DPAD_UP = 11;
-pub const BTN_DPAD_DOWN = 12;
-// rear grip paddles (from a deckcap deckmap capture): the two-digit indices
-pub const BTN_R4 = 16;
-pub const BTN_L4 = 17;
-pub const BTN_R5 = 18;
-pub const BTN_L5 = 19;
-pub const AXIS_L2 = 4; // LEFT_TRIGGER, analog 0..32767
-pub const AXIS_R2 = 5; // RIGHT_TRIGGER
-pub const PAD_LEFT = 0;
-pub const PAD_RIGHT = 1;
-
-/// feel knobs: a full-pad finger sweep covers this many screen pixels
-/// (the deck's screen is 1280x800) / this many wheel ticks
-pub const POINTER_SCALE: f32 = 600.0;
-pub const SCROLL_SCALE: f32 = 24.0;
-/// the pinned SDL 3.4.4 deck driver skips upstream's pad-Y negation, so
-/// touch y arrives 0 = pad bottom; flip this when the sdl dep is bumped
-pub const PAD_Y_SIGN: f32 = -1.0;
-// analog triggers click at 30% and release at 20%: the gap keeps a value
-// hovering near one threshold from chattering press/release pairs
-pub const TRIG_PRESS: i16 = 9830;
-pub const TRIG_RELEASE: i16 = 6553;
-// a firm pad press (pressure 0..1) counts as a click, with the same release
-// hysteresis. Real light-touch drags read ~0.03 in captures, so this is well
-// clear of them; tune on-device against a real click capture.
-pub const PAD_CLICK_PRESS: f32 = 0.10;
-pub const PAD_CLICK_RELEASE: f32 = 0.06;
-
-pub const Input = union(enum) {
- button: struct { idx: u8, down: bool },
- axis: struct { idx: u8, value: i16 },
- touch: struct { pad: u8, phase: enum { down, motion, up }, x: f32, y: f32, pressure: f32 },
-};
-
-pub const Click = enum { select, execute, look }; // mouse buttons 1/2/3
-pub const Keytap = enum { n, cap_n, enter, tab, tty_toggle };
-
-pub const Action = union(enum) {
- move: struct { dx: f32, dy: f32 }, // pointer delta in screen pixels
- click: struct { which: Click, down: bool },
- wheel: i32, // whole ticks, positive = wheel_down
- key: Keytap,
- rumble,
-};
-
-pub const Deck = struct {
- rpad_on: bool = false,
- rpad_x: f32 = 0,
- rpad_y: f32 = 0,
- lpad_on: bool = false,
- lpad_y: f32 = 0,
- scroll: f32 = 0, // fractional wheel ticks carried between motions
- l2_held: bool = false,
- r2_held: bool = false,
- look_held: bool = false,
- rpad_click: bool = false, // firm-press click state, per pad (hysteresis)
- lpad_click: bool = false,
-
- pub fn feed(d: *Deck, in: Input, out: *[3]Action) usize {
- var n: usize = 0;
- switch (in) {
- .button => |b| switch (b.idx) {
- BTN_A => if (b.down) {
- out[0] = .{ .key = .enter };
- n = 1;
- },
- BTN_Y => if (b.down) {
- out[0] = .{ .key = .tab };
- n = 1;
- },
- BTN_DPAD_UP => if (b.down) {
- out[0] = .{ .key = .cap_n };
- n = 1;
- },
- BTN_DPAD_DOWN => if (b.down) {
- out[0] = .{ .key = .n };
- n = 1;
- },
- // any back paddle toggles the terminal (Ctrl-b), applied in gui.zig
- BTN_L4, BTN_R4, BTN_L5, BTN_R5 => if (b.down) {
- out[0] = .{ .key = .tty_toggle };
- n = 1;
- },
- BTN_L1 => {
- d.look_held = b.down;
- out[0] = .{ .click = .{ .which = .look, .down = b.down } };
- n = 1;
- if (b.down) {
- out[1] = .rumble;
- n = 2;
- }
- },
- else => {},
- },
- .axis => |a| {
- if (a.idx != AXIS_L2 and a.idx != AXIS_R2) return 0;
- const held = if (a.idx == AXIS_L2) &d.l2_held else &d.r2_held;
- const which: Click = if (a.idx == AXIS_L2) .execute else .select;
- if (!held.* and a.value >= TRIG_PRESS) {
- held.* = true;
- out[0] = .{ .click = .{ .which = which, .down = true } };
- n = 1;
- if (which == .execute) {
- out[1] = .rumble;
- n = 2;
- }
- } else if (held.* and a.value <= TRIG_RELEASE) {
- held.* = false;
- out[0] = .{ .click = .{ .which = which, .down = false } };
- n = 1;
- }
- },
- .touch => |t| {
- switch (t.pad) {
- PAD_RIGHT => switch (t.phase) {
- // a fresh touch only re-anchors — deltas start from the
- // landing point, so the pointer never jumps to it
- .down => {
- d.rpad_on = true;
- d.rpad_x = t.x;
- d.rpad_y = t.y;
- },
- .motion => if (d.rpad_on) {
- out[n] = .{ .move = .{
- .dx = (t.x - d.rpad_x) * POINTER_SCALE,
- .dy = (t.y - d.rpad_y) * PAD_Y_SIGN * POINTER_SCALE,
- } };
- n += 1;
- d.rpad_x = t.x;
- d.rpad_y = t.y;
- },
- .up => d.rpad_on = false,
- },
- PAD_LEFT => switch (t.phase) {
- .down => {
- d.lpad_on = true;
- d.lpad_y = t.y;
- },
- .motion => if (d.lpad_on) {
- d.scroll += (t.y - d.lpad_y) * PAD_Y_SIGN * SCROLL_SCALE;
- d.lpad_y = t.y;
- const ticks: i32 = @intFromFloat(d.scroll);
- if (ticks != 0) {
- d.scroll -= @floatFromInt(ticks);
- out[n] = .{ .wheel = ticks };
- n += 1;
- }
- },
- .up => d.lpad_on = false,
- },
- else => {},
- }
- // a firm press on either pad is a click: right pad -> select
- // (left button), left pad -> look (right button). The press
- // rumbles as click feedback, mirroring the stock driver (SDL
- // exposes no per-pad haptic, so it's a short whole-pad buzz).
- if (t.pad == PAD_RIGHT or t.pad == PAD_LEFT) {
- const which: Click = if (t.pad == PAD_RIGHT) .select else .look;
- const held = if (t.pad == PAD_RIGHT) &d.rpad_click else &d.lpad_click;
- if (t.phase == .up) {
- if (held.*) {
- held.* = false;
- out[n] = .{ .click = .{ .which = which, .down = false } };
- n += 1;
- }
- } else if (!held.* and t.pressure >= PAD_CLICK_PRESS) {
- held.* = true;
- out[n] = .{ .click = .{ .which = which, .down = true } };
- n += 1;
- out[n] = .rumble;
- n += 1;
- } else if (held.* and t.pressure <= PAD_CLICK_RELEASE) {
- held.* = false;
- out[n] = .{ .click = .{ .which = which, .down = false } };
- n += 1;
- }
- }
- },
- }
- return n;
- }
-};