diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-30 14:20:10 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:17 -0300 |
| commit | 17c0d06618085de8d0bbf8152750ffa862db0080 (patch) | |
| tree | 71a2d33dcf14e4e95387f3aa556e9952135de894 /src/pardes.zig | |
| parent | b546b578baadbd8fdd15b42988ad4d66c9c8ff21 (diff) | |
| download | pardes-17c0d06618085de8d0bbf8152750ffa862db0080.tar.gz pardes-17c0d06618085de8d0bbf8152750ffa862db0080.zip | |
A program that asked for focus reports (1004) hears CSI I when its pane takes the keyboard and CSI O when it gives it up, to another pane, a tag or another window
The core has a window-focus event now, from SDL's window focus and from
the tty's own focus reports (vaxis turns 1004 on outside); the detached
wire carries it: version 10. The test shell's ESC]777;mouse;focus;<1|0>
fakes the window's.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/pardes.zig')
| -rw-r--r-- | src/pardes.zig | 27 |
1 files changed, 27 insertions, 0 deletions
diff --git a/src/pardes.zig b/src/pardes.zig index dcf0bf55..1009d13d 100644 --- a/src/pardes.zig +++ b/src/pardes.zig @@ -3548,6 +3548,8 @@ pub const Event = union(enum) { /// The host pointer left the drawable area. Unlike an out-of-range motion, /// this must not clamp onto and preview the final grid cell. pointer_leave, + /// The window gained (true) or lost the host's keyboard focus. + focus: bool, tick, }; @@ -4322,6 +4324,10 @@ pub const Pardes = struct { /// A press a terminal's program took (mouse.programMouse): its drags /// and release are the program's too, wherever the pointer goes. mouse_grab: ?mouse.Grab = null, + /// Whether the host window has the keyboard (Event.focus), and the pane + /// whose program was last told it has it (reportFocus). + window_focused: bool = true, + focus_told: ?struct { id: usize, serial: u32 } = null, hover_col: u16 = 0, hover_row: u16 = 0, pointer_raw_col: u16 = 0, @@ -5007,6 +5013,25 @@ pub const Pardes = struct { } /// The column the keyboard is in: its tag's, or its pane's. + /// DECSET 1004: a program that asked is told `CSI I` when its pane + /// takes the keyboard (the active pane, its body, the window focused) + /// and `CSI O` when it gives it up, to another pane, a tag or header, + /// or another window. + fn reportFocus(p: *Pardes) void { + const want: @FieldType(Pardes, "focus_told") = blk: { + if (!p.window_focused or p.header_focus) break :blk null; + const pane = p.panes[p.active] orelse break :blk null; + if (pane.focus != .body) break :blk null; + break :blk .{ .id = p.active, .serial = pane.serial }; + }; + if (std.meta.eql(want, p.focus_told)) return; + if (p.focus_told) |old| if (p.panes[old.id]) |pane| { + if (pane.serial == old.serial and panes.terminal.reportsFocus(pane)) p.emitWrite(old.id, "\x1b[O"); + }; + if (want) |new| if (panes.terminal.reportsFocus(p.panes[new.id].?)) p.emitWrite(new.id, "\x1b[I"); + p.focus_told = want; + } + pub fn noteTyped(p: *Pardes) void { if (p.header_focus) { if (p.header_column) |c| p.setActiveColumn(c); @@ -5653,6 +5678,7 @@ pub const Pardes = struct { } pub fn update(p: *Pardes, ev: Event) void { + defer p.reportFocus(); // A tick with nothing animating is the one event that cannot change // the screen. p.needs_frame = p.needs_frame or ev != .tick; @@ -5785,6 +5811,7 @@ pub const Pardes = struct { .command => |line| _ = p.executeBuiltinLine(p.active, line), .pinch => |scale| p.ov_pinch_scale = scale, .touch_scroll => |delta| p.ov_touch_scroll_delta = delta, + .focus => |focused| p.window_focused = focused, .pointer_leave => { p.pointer_inside = false; p.pointer_body_hit = null; |
