From 9d8463255c7a55c8b8bff3606e326a5fc25bdca9 Mon Sep 17 00:00:00 2001 From: Harrison DiAmbrosio Date: Mon, 5 Jan 2026 15:49:29 -0500 Subject: [PATCH] basic add and del mousemaps work, drag is yet to be implemented --- runtime/share/mezzaluna/master.lua | 73 ++++---------------------- src/Cursor.zig | 83 ++++++++++++++++++------------ src/Server.zig | 2 + src/lua/Input.zig | 24 +++++---- src/types/Mousemap.zig | 11 ++-- 5 files changed, 81 insertions(+), 112 deletions(-) diff --git a/runtime/share/mezzaluna/master.lua b/runtime/share/mezzaluna/master.lua index ae71be8..f0fd66a 100644 --- a/runtime/share/mezzaluna/master.lua +++ b/runtime/share/mezzaluna/master.lua @@ -6,43 +6,6 @@ mez.input.add_keymap("alt", "g", { end }) -mez.input.add_keymap("alt", "i", { - press = function () - local coroutine = require("coroutine") - print(coroutine) - local co = coroutine.create(function () - print("starting coroutine") - local view_id = mez.view.get_focused_id() - - local size = mez.view.get_size(view_id) - local pos = mez.view.get_position(view_id) - local res = mez.output.get_resolution(0) - - local x_pos = pos.x - local y_pos = pos.y - local x_vel = 10 - local y_vel = 10 - - while true do - x_pos = x_pos + x_vel - y_pos = y_pos + y_vel - - if x_pos + size.width > res.width or x_pos < 0 then - x_vel = x_vel * -1 - end - - if y_pos + size.height > res.height or y_pos < 0 then - y_vel = y_vel * -1 - end - - print("(" .. x_pos .. ", " .. y_pos .. ")") - mez.view.set_position(view_id, x_pos, y_pos) - end - end) - coroutine.resume(co) - end -}) - local master = function() local config = { tag_count = 5, @@ -310,32 +273,16 @@ local master = function() press = function() mez.api.change_vt(i) end }) end + + mez.input.add_mousemap("alt", "BTN_LEFT", { + press = function() + print("pressed mouse") + mez.input.del_mousemap("alt", "BTN_LEFT"); + end, + release = function() print("released mouse") end, + drag = function() print("dragging mouse") end + }) + end master() - -function print_table(tbl, indent, seen) - indent = indent or 0 - seen = seen or {} - - -- Prevent infinite loops from circular references - if seen[tbl] then - print(string.rep(" ", indent) .. "...(circular reference)") - return - end - seen[tbl] = true - - for key, value in pairs(tbl) do - local formatting = string.rep(" ", indent) .. tostring(key) .. ": " - - if type(value) == "table" then - print(formatting .. "{") - print_table(value, indent + 1, seen) - print(string.rep(" ", indent) .. "}") - elseif type(value) == "string" then - print(formatting .. '"' .. value .. '"') - else - print(formatting .. tostring(value)) - end - end -end diff --git a/src/Cursor.zig b/src/Cursor.zig index c1ff698..28da562 100644 --- a/src/Cursor.zig +++ b/src/Cursor.zig @@ -10,6 +10,7 @@ const xkb = @import("xkbcommon"); const View = @import("View.zig"); const Utils = @import("Utils.zig"); +const Mousemap = @import("types/Mousemap.zig"); const c = @import("C.zig").c; const server = &@import("main.zig").server; @@ -149,45 +150,33 @@ event: *wlr.Pointer.event.MotionAbsolute, } fn handleButton( -listener: *wl.Listener(*wlr.Pointer.event.Button), -event: *wlr.Pointer.event.Button + listener: *wl.Listener(*wlr.Pointer.event.Button), + event: *wlr.Pointer.event.Button ) void { const cursor: *Cursor = @fieldParentPtr("button", listener); - _ = server.seat.wlr_seat.pointerNotifyButton(event.time_msec, event.button, event.state); - - // @hook PointerButtonPress // TODO Probably change this name - // @param button string // TODO Translate a button to a string or smth - // @param state string - "pressed" or "released" - // @param time_msecs number - const state = if (event.state == .pressed) "pressed" else "released"; - server.events.exec("PointerButtonPress", .{event.button, state, event.time_msec}); - switch (event.state) { .pressed => { - if(server.seat.keyboard_group.keyboard.getModifiers().alt) { - // Can be BTN_RIGHT, BTN_LEFT, or BTN_MIDDLE - cursor.drag.start_x = @as(c_int, @intFromFloat(cursor.wlr_cursor.x)); - cursor.drag.start_y = @as(c_int, @intFromFloat(cursor.wlr_cursor.y)); - if(server.seat.focused_surface) |fs| { - // Keep track of where the drag started + cursor.drag.start_x = @as(c_int, @intFromFloat(cursor.wlr_cursor.x)); + cursor.drag.start_y = @as(c_int, @intFromFloat(cursor.wlr_cursor.y)); + if(server.seat.focused_surface) |fs| { + // Keep track of where the drag started - if(fs == .view) { - cursor.drag.view = fs.view; - cursor.drag.view_offset_x = cursor.drag.start_x - fs.view.scene_tree.node.x; - cursor.drag.view_offset_y = cursor.drag.start_y - fs.view.scene_tree.node.y; - } - - // Maybe comptime this for later reference - if(event.button == c.libevdev_event_code_from_name(c.EV_KEY, "BTN_LEFT")) { - cursor.mode = .move; - } else if(event.button == c.libevdev_event_code_from_name(c.EV_KEY, "BTN_RIGHT")) { - if(fs == .view) { - cursor.mode = .resize; - _ = fs.view.xdg_toplevel.setResizing(true); - } - } + if(fs == .view) { + cursor.drag.view = fs.view; + cursor.drag.view_offset_x = cursor.drag.start_x - fs.view.scene_tree.node.x; + cursor.drag.view_offset_y = cursor.drag.start_y - fs.view.scene_tree.node.y; } + + // Maybe comptime this for later reference + // if(event.button == c.libevdev_event_code_from_name(c.EV_KEY, "BTN_LEFT")) { + // cursor.mode = .move; + // } else if(event.button == c.libevdev_event_code_from_name(c.EV_KEY, "BTN_RIGHT")) { + // if(fs == .view) { + // cursor.mode = .resize; + // _ = fs.view.xdg_toplevel.setResizing(true); + // } + // } } }, .released => { @@ -205,6 +194,36 @@ event: *wlr.Pointer.event.Button std.log.err("Invalid/Unimplemented pointer button event type", .{}); } } + + + var handled = false; + const modifiers = server.seat.keyboard_group.keyboard.getModifiers(); + + // Proceed if mousemap for current mouse and modifier state's exist + if (server.mousemaps.get(Mousemap.hash(modifiers, @bitCast(event.button)))) |map| { + switch (event.state) { + .pressed => { + // Only make callback if a callback function exists + if(map.options.lua_press_ref_idx > 0) { + map.callback(.press); + handled = true; + } + }, + .released => { + if(map.options.lua_press_ref_idx > 0) { + map.callback(.release); + handled = true; + } + }, + else => { unreachable; } + } + } + + // If no keymap exists for button event, forward it to a surface + // TODO: Allow for transparent mousemaps that pass mouse button events anyways + if(!handled) { + _ = server.seat.wlr_seat.pointerNotifyButton(event.time_msec, event.button, event.state); + } } fn handleHoldBegin( diff --git a/src/Server.zig b/src/Server.zig index bb44cda..2009561 100644 --- a/src/Server.zig +++ b/src/Server.zig @@ -12,6 +12,7 @@ const LayerSurface = @import("LayerSurface.zig"); const Output = @import("Output.zig"); const View = @import("View.zig"); const Keymap = @import("types/Keymap.zig"); +const Mousemap = @import("types/Mousemap.zig"); const Hook = @import("types/Hook.zig"); const Events = @import("types/Events.zig"); const Popup = @import("Popup.zig"); @@ -103,6 +104,7 @@ pub fn init(self: *Server) void { .cursor = undefined, .remote_lua_manager = RemoteLuaManager.init() catch Utils.oomPanic(), .keymaps = .init(gpa), + .mousemaps = .init(gpa), .hooks = .init(gpa), .events = try .init(gpa), .remote_lua_clients = .{}, diff --git a/src/lua/Input.zig b/src/lua/Input.zig index d5a0f44..e296cfe 100644 --- a/src/lua/Input.zig +++ b/src/lua/Input.zig @@ -6,9 +6,11 @@ const xkb = @import("xkbcommon"); const wlr = @import("wlroots"); const Keymap = @import("../types/Keymap.zig"); +const Mousemap = @import("../types/Mousemap.zig"); const Utils = @import("../Utils.zig"); const LuaUtils = @import("LuaUtils.zig"); +const c = @import("../C.zig").c; const server = &@import("../main.zig").server; fn parse_modkeys(modStr: []const u8) wlr.Keyboard.ModifierMask { @@ -64,35 +66,36 @@ pub fn add_keymap(L: *zlua.Lua) i32 { /// ---Create a new mousemap /// ---@param string modifiers -/// ---@param string button name (ex. "left", "right") +/// ---@param string libevdev button name (ex. "BTN_LEFT", "BTN_RIGHT") /// ---@param table options pub fn add_mousemap(L: *zlua.Lua) i32 { var mousemap: Mousemap = undefined; - // mousemap.options.repeat = true; const mod = L.checkString(1); mousemap.modifier = parse_modkeys(mod); const button = L.checkString(2); - mousemap.keycode = xkb.Keysym.fromName(button, .no_flags); + mousemap.event_code = c.libevdev_event_code_from_name(c.EV_KEY, button); _ = L.pushString("press"); _ = L.getTable(3); if (L.isFunction(-1)) { - keymap.options.lua_press_ref_idx = L.ref(zlua.registry_index) catch Utils.oomPanic(); + mousemap.options.lua_press_ref_idx = L.ref(zlua.registry_index) catch Utils.oomPanic(); } _ = L.pushString("release"); _ = L.getTable(3); if (L.isFunction(-1)) { - keymap.options.lua_release_ref_idx = L.ref(zlua.registry_index) catch Utils.oomPanic(); + mousemap.options.lua_release_ref_idx = L.ref(zlua.registry_index) catch Utils.oomPanic(); } - _ = L.pushString("repeat"); + _ = L.pushString("drag"); _ = L.getTable(3); - keymap.options.repeat = L.isNil(-1) or L.toBoolean(-1); + if (L.isFunction(-1)) { + mousemap.options.lua_drag_ref_idx = L.ref(zlua.registry_index) catch Utils.oomPanic(); + } - const hash = Keymap.hash(mousemap.modifier, mousemap.keycode); + const hash = Mousemap.hash(mousemap.modifier, mousemap.event_code); server.mousemaps.put(hash, mousemap) catch Utils.oomPanic(); L.pushNil(); @@ -129,13 +132,12 @@ pub fn del_mousemap(L: *zlua.Lua) i32 { var mousemap: Mousemap = undefined; const mod = L.checkString(1); - mousemap.modifier = parse_modkeys(mod); const button = L.checkString(2); + mousemap.event_code = c.libevdev_event_code_from_name(c.EV_KEY, button); - mousemap.keycode = xkb.Keysym.fromName(button, .no_flags); - _ = server.mousemaps.remove(Keymap.hash(mousemap.modifier, mousemap.keycode)); + _ = server.mousemaps.remove(Mousemap.hash(mousemap.modifier, mousemap.event_code)); L.pushNil(); return 1; diff --git a/src/types/Mousemap.zig b/src/types/Mousemap.zig index 735d9e9..aef1ebd 100644 --- a/src/types/Mousemap.zig +++ b/src/types/Mousemap.zig @@ -12,20 +12,19 @@ const RemoteLua = @import("../RemoteLua.zig"); const Lua = &@import("../main.zig").lua; modifier: wlr.Keyboard.ModifierMask, -keycode: xkb.Keysym, +event_code: i32, options: struct { /// This is the location of the on press lua function in the lua registry lua_press_ref_idx: i32, /// This is the location of the on release lua function in the lua registry lua_release_ref_idx: i32, - /// THis is the location of the on drag lua function in the lua registry + /// This is the location of the on drag lua function in the lua registry lua_drag_ref_idx: i32, }, pub const MousemapState = enum { press, drag, release }; pub fn callback(self: *const Mousemap, state: MousemapState) void { - const lua_ref_idx = if (release) self.options.lua_release_ref_idx else self.options.lua_press_ref_idx; const lua_ref_idx = switch(state) { .press => self.options.lua_press_ref_idx, .release => self.options.lua_release_ref_idx, @@ -45,8 +44,8 @@ pub fn callback(self: *const Mousemap, state: MousemapState) void { Lua.state.pop(-1); } -pub fn hash(modifier: wlr.Keyboard.ModifierMask, keycode: xkb.Keysym) u64 { +pub fn hash(modifier: wlr.Keyboard.ModifierMask, event_code: i32) u64 { const mod_val: u32 = @bitCast(modifier); - const key_val: u32 = @intFromEnum(keycode); - return (@as(u64, mod_val) << 32) | @as(u64, key_val); + const button_val: u32 = @bitCast(event_code); + return (@as(u64, mod_val) << 32) | @as(u64, button_val); }