summaryrefslogtreecommitdiff
path: root/src/gui
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/gui.zig66
1 files changed, 54 insertions, 12 deletions
diff --git a/src/gui/gui.zig b/src/gui/gui.zig
index 045f22d9..4ce554f3 100644
--- a/src/gui/gui.zig
+++ b/src/gui/gui.zig
@@ -3139,8 +3139,8 @@ const StdinFeed = struct {
var seq_start: usize = 0;
while (seq_start < len) {
- // ESC]777;mouse;<down|up|motion>;<SDL button, 0 for none>;<x>;<y>BEL
- // ESC]777;mouse;wheel;<amount>;<x>;<y>BEL
+ // ESC]777;mouse;<down|up|motion>;<SDL button, 0 for none>;<x>;<y>[;<mods>]BEL
+ // ESC]777;mouse;wheel;<amount>;<x>;<y>[;<mods>]BEL
// A mouse event at window pixels, built as SDL would and run
// through dispatch, so a driver exercises the real pointer path
// (pixel to cell, tag and body hits). SGR mouse carries only cells.
@@ -3159,6 +3159,9 @@ const StdinFeed = struct {
const button = std.fmt.parseInt(u8, second, 10) catch 0;
const x = std.fmt.parseFloat(f32, parts.next() orelse "") catch 0;
const y = std.fmt.parseFloat(f32, parts.next() orelse "") catch 0;
+ // An optional fifth field holds modifiers as xterm
+ // counts them: shift 4, meta (alt) 8, ctrl 16.
+ const held = std.fmt.parseInt(u8, parts.next() orelse "0", 10) catch 0;
var sev = std.mem.zeroes(c.SDL_Event);
if (std.mem.eql(u8, kind, "wheel")) {
// ESC]777;mouse;wheel;<y, SDL's sign: up positive>;<x>;<y>BEL:
@@ -3181,7 +3184,14 @@ const StdinFeed = struct {
sev.button.x = x;
sev.button.y = y;
}
+ const before = c.SDL_GetModState();
+ var mods: c.SDL_Keymod = 0;
+ if (held & 4 != 0) mods |= c.SDL_KMOD_LSHIFT;
+ if (held & 8 != 0) mods |= c.SDL_KMOD_LALT;
+ if (held & 16 != 0) mods |= c.SDL_KMOD_LCTRL;
+ c.SDL_SetModState(mods);
dispatch(gp, in, &sev);
+ c.SDL_SetModState(before);
out.n_events += 1;
}
seq_start += mouse_prefix.len + end + 1;
@@ -3256,6 +3266,8 @@ const StdinFeed = struct {
.col = @intCast(@max(m.col, 0)),
.row = @intCast(@max(m.row, 0)),
.ctrl = m.mods.ctrl,
+ .shift = m.mods.shift,
+ .alt = m.mods.alt,
} });
out.n_events += 1;
}
@@ -3526,6 +3538,7 @@ fn dispatch(g: *Gui, in: *Input, sev: *const c.SDL_Event) void {
};
g.pointer_mapped = true;
g.pointer_cell = mc;
+ const mods = pointerMods();
in.post(.{
.mouse = .{
.button = button,
@@ -3535,7 +3548,9 @@ fn dispatch(g: *Gui, in: *Input, sev: *const c.SDL_Event) void {
.tag_hit = mc.tag_hit,
.body_hit = mc.body_hit,
.rule_above = mc.rule_above,
- .ctrl = (c.SDL_GetModState() & c.SDL_KMOD_CTRL) != 0,
+ .ctrl = mods.ctrl,
+ .shift = mods.shift,
+ .alt = mods.alt,
},
});
},
@@ -3559,6 +3574,7 @@ fn dispatch(g: *Gui, in: *Input, sev: *const c.SDL_Event) void {
};
g.pointer_mapped = true;
g.pointer_cell = mc;
+ const mods = pointerMods();
in.post(.{ .mouse = .{
.button = held orelse .none,
.kind = if (held != null) .drag else .motion,
@@ -3566,6 +3582,9 @@ fn dispatch(g: *Gui, in: *Input, sev: *const c.SDL_Event) void {
.row = mc.row,
.tag_hit = mc.tag_hit,
.body_hit = mc.body_hit,
+ .ctrl = mods.ctrl,
+ .shift = mods.shift,
+ .alt = mods.alt,
} });
},
c.SDL_EVENT_MOUSE_WHEEL => {
@@ -3581,7 +3600,7 @@ fn dispatch(g: *Gui, in: *Input, sev: *const c.SDL_Event) void {
};
g.pointer_mapped = true;
g.pointer_cell = mc;
- wheelAt(g, in, .{ .x = w.x, .y = w.y, .integer_y = w.integer_y }, mc);
+ wheelAt(g, in, .{ .x = w.x, .y = w.y, .integer_y = w.integer_y, .mods = pointerMods() }, mc);
},
c.SDL_EVENT_FINGER_DOWN, c.SDL_EVENT_FINGER_MOTION, c.SDL_EVENT_FINGER_UP, c.SDL_EVENT_FINGER_CANCELED => {
const f = sev.tfinger;
@@ -3913,16 +3932,16 @@ fn wheelAt(g: *Gui, in: *Input, w: WheelTurn, mc: MouseCell) void {
.pane = @intCast(id),
.delta_pixels = -w.y * @as(f32, @floatFromInt(g.cell_h)),
} });
- } else if (pane.isTerminal() and pardes.panes.terminal.ownsWheel(pane)) {
+ } else if (!w.mods.shift and pane.isTerminal() and pardes.panes.terminal.ownsWheel(pane)) {
// The program's (codex, htop, less): every whole
// turn goes to it, no glide, for nothing of ours
- // moves.
+ // moves. Shift keeps the wheel pardes's.
resetScroll(g);
g.program_wheel = accumulateWheelDelta(g.program_wheel, w.y);
while (g.program_wheel >= 1) : (g.program_wheel -= 1)
- in.post(.{ .mouse = .{ .button = .wheel_down, .kind = .press, .col = mc.col, .row = mc.row, .tag_hit = mc.tag_hit, .body_hit = mc.body_hit } });
+ in.post(.{ .mouse = .{ .button = .wheel_down, .kind = .press, .col = mc.col, .row = mc.row, .tag_hit = mc.tag_hit, .body_hit = mc.body_hit, .ctrl = w.mods.ctrl, .shift = w.mods.shift, .alt = w.mods.alt } });
while (g.program_wheel <= -1) : (g.program_wheel += 1)
- in.post(.{ .mouse = .{ .button = .wheel_up, .kind = .press, .col = mc.col, .row = mc.row, .tag_hit = mc.tag_hit, .body_hit = mc.body_hit } });
+ in.post(.{ .mouse = .{ .button = .wheel_up, .kind = .press, .col = mc.col, .row = mc.row, .tag_hit = mc.tag_hit, .body_hit = mc.body_hit, .ctrl = w.mods.ctrl, .shift = w.mods.shift, .alt = w.mods.alt } });
} else {
g.scroll_pane = id;
g.scroll_col = mc.col;
@@ -3938,9 +3957,9 @@ fn wheelAt(g: *Gui, in: *Input, w: WheelTurn, mc: MouseCell) void {
} else {
g.scroll_delta = accumulateWheelDelta(g.scroll_delta, w.y);
while (g.scroll_delta >= 1) : (g.scroll_delta -= 1)
- in.post(.{ .mouse = .{ .button = .wheel_down, .kind = .press, .col = mc.col, .row = mc.row, .tag_hit = mc.tag_hit, .body_hit = mc.body_hit } });
+ in.post(.{ .mouse = .{ .button = .wheel_down, .kind = .press, .col = mc.col, .row = mc.row, .tag_hit = mc.tag_hit, .body_hit = mc.body_hit, .ctrl = w.mods.ctrl, .shift = w.mods.shift, .alt = w.mods.alt } });
while (g.scroll_delta <= -1) : (g.scroll_delta += 1)
- in.post(.{ .mouse = .{ .button = .wheel_up, .kind = .press, .col = mc.col, .row = mc.row, .tag_hit = mc.tag_hit, .body_hit = mc.body_hit } });
+ in.post(.{ .mouse = .{ .button = .wheel_up, .kind = .press, .col = mc.col, .row = mc.row, .tag_hit = mc.tag_hit, .body_hit = mc.body_hit, .ctrl = w.mods.ctrl, .shift = w.mods.shift, .alt = w.mods.alt } });
}
}
if (w.x != 0) in.post(.{ .mouse = .{
@@ -3950,10 +3969,21 @@ fn wheelAt(g: *Gui, in: *Input, w: WheelTurn, mc: MouseCell) void {
.row = mc.row,
.tag_hit = mc.tag_hit,
.body_hit = mc.body_hit,
+ .ctrl = w.mods.ctrl,
+ .shift = w.mods.shift,
+ .alt = w.mods.alt,
} });
}
-const WheelTurn = struct { x: f32 = 0, y: f32 = 0, integer_y: i32 = 0 };
+const WheelTurn = struct { x: f32 = 0, y: f32 = 0, integer_y: i32 = 0, mods: PointerMods = .{} };
+
+/// The modifiers held with a pointer event, as the core's Mouse carries them.
+const PointerMods = struct { ctrl: bool = false, shift: bool = false, alt: bool = false };
+
+fn pointerMods() PointerMods {
+ const m = c.SDL_GetModState();
+ return .{ .ctrl = (m & c.SDL_KMOD_CTRL) != 0, .shift = (m & c.SDL_KMOD_SHIFT) != 0, .alt = (m & c.SDL_KMOD_ALT) != 0 };
+}
fn mouseCellWithGeometry(g: *const Gui, core: ?*const pardes.Pardes, x: f32, y: f32, geometry: WindowGeometry) ?MouseCell {
const physical = windowPointToPixels(geometry, x, y);
@@ -4934,6 +4964,7 @@ test "a wheel over codex in a terminal reaches its pty as the mouse reports it a
g.scroll_notch = 0;
g.program_wheel = 0;
g.glide = .{};
+ defer g.glide.deinit(gpa);
g.cell_h = 20;
var in: Input = .{ .core = core };
var sent: std.ArrayList(u8) = .empty;
@@ -4967,6 +4998,15 @@ test "a wheel over codex in a terminal reaches its pty as the mouse reports it a
try std.testing.expectEqualStrings("", try Sent.take(core, &sent));
wheelAt(&g, &in, .{ .y = 0.5 }, mc);
try std.testing.expectEqualStrings("\x1b[<64;6;4M", try Sent.take(core, &sent));
+ // Alt is meta, 8; Shift keeps the turn pardes's own, a glide.
+ wheelAt(&g, &in, .{ .y = 1, .integer_y = 1, .mods = .{ .alt = true } }, mc);
+ try std.testing.expectEqualStrings("\x1b[<72;6;4M", try Sent.take(core, &sent));
+ wheelAt(&g, &in, .{ .y = 1, .integer_y = 1, .mods = .{ .shift = true } }, mc);
+ try std.testing.expectEqualStrings("", try Sent.take(core, &sent));
+ try std.testing.expectEqual(@as(i32, -1), g.scroll_notch);
+ stepGlide(&g, core, gpa);
+ try std.testing.expectEqualStrings("", try Sent.take(core, &sent));
+ resetScroll(&g);
// Its sign-in screen: mouse off, alternate scroll on, so arrow keys.
core.update(.{ .output = .{ .pane = 0, .bytes = "\x1b[?1006l\x1b[?1003l\x1b[?1002l\x1b[?1000l\x1b[?1007h" } });
_ = try Sent.take(core, &sent);
@@ -5171,7 +5211,8 @@ fn stepGlide(g: *Gui, core: *pardes.Pardes, gpa: std.mem.Allocator) void {
const down = left > 0;
left += if (down) -1 else 1;
const was = pane.scroll();
- core.update(.{ .mouse = .{ .button = if (down) .wheel_down else .wheel_up, .kind = .press, .col = g.scroll_col, .row = g.scroll_row } });
+ // Shift: pardes's own scroll, never a program's wheel.
+ core.update(.{ .mouse = .{ .button = if (down) .wheel_down else .wheel_up, .kind = .press, .col = g.scroll_col, .row = g.scroll_row, .shift = true } });
if (pane.scroll() == was) break;
moved = true;
}
@@ -5344,6 +5385,7 @@ fn stepScroll(g: *Gui, core: *pardes.Pardes, gpa: std.mem.Allocator) void {
.kind = .press,
.col = g.scroll_col,
.row = g.scroll_row,
+ .shift = true, // pardes's own scroll, never a program's wheel
} });
if (pane.scroll() == was) {
resetScroll(g);