diff options
Diffstat (limited to 'src/gui')
| -rw-r--r-- | src/gui/gui.zig | 66 |
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); |
