aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/libghostty-vt/src/terminal/c/mouse_event.zig
blob: b97b4661a4059eea18ba7d1d976df8b3303a846f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
const std = @import("std");
const Allocator = std.mem.Allocator;
const testing = std.testing;
const lib = @import("../lib.zig");
const CAllocator = lib.alloc.Allocator;
const key = @import("../../input/key.zig");
const mouse = @import("../../input/mouse.zig");
const mouse_encode = @import("../../input/mouse_encode.zig");
const Result = @import("result.zig").Result;

const log = std.log.scoped(.mouse_event);

/// Wrapper around mouse event that tracks the allocator for C API usage.
const MouseEventWrapper = struct {
    event: mouse_encode.Event = .{},
    alloc: Allocator,
};

/// C: GhosttyMouseEvent
pub const Event = ?*MouseEventWrapper;

/// C: GhosttyMouseAction
pub const Action = mouse.Action;

/// C: GhosttyMouseButton
pub const Button = mouse.Button;

/// C: GhosttyMousePosition
pub const Position = mouse_encode.Event.Pos;

/// C: GhosttyMods
pub const Mods = key.Mods;

pub fn new(
    alloc_: ?*const CAllocator,
    result: *Event,
) callconv(lib.calling_conv) Result {
    const alloc = lib.alloc.default(alloc_);
    const ptr = alloc.create(MouseEventWrapper) catch
        return .out_of_memory;
    ptr.* = .{ .alloc = alloc };
    result.* = ptr;
    return .success;
}

pub fn free(event_: Event) callconv(lib.calling_conv) void {
    const wrapper = event_ orelse return;
    const alloc = wrapper.alloc;
    alloc.destroy(wrapper);
}

pub fn set_action(event_: Event, action: Action) callconv(lib.calling_conv) void {
    if (comptime std.debug.runtime_safety) {
        _ = std.enums.fromInt(Action, @intFromEnum(action)) orelse {
            log.warn("set_action invalid action value={d}", .{@intFromEnum(action)});
            return;
        };
    }

    event_.?.event.action = action;
}

pub fn get_action(event_: Event) callconv(lib.calling_conv) Action {
    return event_.?.event.action;
}

pub fn set_button(event_: Event, button: Button) callconv(lib.calling_conv) void {
    if (comptime std.debug.runtime_safety) {
        _ = std.enums.fromInt(Button, @intFromEnum(button)) orelse {
            log.warn("set_button invalid button value={d}", .{@intFromEnum(button)});
            return;
        };
    }

    event_.?.event.button = button;
}

pub fn clear_button(event_: Event) callconv(lib.calling_conv) void {
    event_.?.event.button = null;
}

pub fn get_button(event_: Event, out: ?*Button) callconv(lib.calling_conv) bool {
    if (event_.?.event.button) |button| {
        if (out) |ptr| ptr.* = button;
        return true;
    }

    return false;
}

pub fn set_mods(event_: Event, mods: Mods) callconv(lib.calling_conv) void {
    event_.?.event.mods = mods;
}

pub fn get_mods(event_: Event) callconv(lib.calling_conv) Mods {
    return event_.?.event.mods;
}

pub fn set_position(event_: Event, pos: Position) callconv(lib.calling_conv) void {
    event_.?.event.pos = pos;
}

pub fn get_position(event_: Event) callconv(lib.calling_conv) Position {
    return event_.?.event.pos;
}

test "alloc" {
    var e: Event = undefined;
    try testing.expectEqual(Result.success, new(
        &lib.alloc.test_allocator,
        &e,
    ));
    free(e);
}

test "free null" {
    free(null);
}

test "set/get" {
    var e: Event = undefined;
    try testing.expectEqual(Result.success, new(
        &lib.alloc.test_allocator,
        &e,
    ));
    defer free(e);

    // Action
    set_action(e, .motion);
    try testing.expectEqual(Action.motion, get_action(e));

    // Button
    set_button(e, .left);
    var button: Button = .unknown;
    try testing.expect(get_button(e, &button));
    try testing.expectEqual(Button.left, button);
    try testing.expect(get_button(e, null));

    clear_button(e);
    try testing.expect(!get_button(e, &button));

    // Mods
    const mods: Mods = .{ .shift = true, .ctrl = true };
    set_mods(e, mods);
    const got_mods = get_mods(e);
    try testing.expect(got_mods.shift);
    try testing.expect(got_mods.ctrl);
    try testing.expect(!got_mods.alt);

    // Position
    set_position(e, .{ .x = 12.5, .y = -4.0 });
    const pos = get_position(e);
    try testing.expectEqual(@as(f32, 12.5), pos.x);
    try testing.expectEqual(@as(f32, -4.0), pos.y);
}