diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/main.zig | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/src/main.zig b/src/main.zig new file mode 100644 index 0000000..9969741 --- /dev/null +++ b/src/main.zig @@ -0,0 +1,97 @@ +const std = @import("std"); +const c = @cImport({ + @cInclude("linux/joystick.h"); +}); + +pub fn main() !void { + const allocator = std.heap.c_allocator; + var keybinds = std.ArrayList(Keybind).init(allocator); + defer keybinds.deinit(); + + var args = std.process.args(); + defer args.deinit(); + + if(!args.skip()) + usage(); + + var input_filepath: []const u8 = ""; + if(args.next()) |arg| { + input_filepath = arg[0..arg.len]; + } else { + std.debug.print("error: missing required argument input_device\n", .{}); + usage(); + } + + while(args.next()) |arg| { + const keybind = Keybind.parse_string(arg) catch { + std.debug.print("error: invalid keybind: {s}\n", .{arg}); + usage(); + unreachable; + }; + try keybinds.append(keybind); + } + + const event_fd = std.os.open(input_filepath, std.os.O.RDONLY, 0) catch |err| { + std.debug.print("error: failed to open: {s}\n", .{input_filepath}); + return err; + }; + defer std.os.close(event_fd); + + var event: c.js_event = undefined; + while(true) { + const read_size = try std.os.read(event_fd, std.mem.asBytes(&event)); + if(read_size != @sizeOf(@TypeOf(event))) + continue; + + if(event.type & c.JS_EVENT_BUTTON == 0) + continue; + + if(event.value != 1) + continue; + + for(keybinds.items) |*keybind| { + if(event.number != keybind.key) + continue; + + std.debug.print("key pressed: {d}, running command: {s}\n", .{keybind.key, keybind.command}); + keybind.execute_command(allocator); + } + } +} + +fn usage() void { + std.debug.print( + \\usage: zbind <input_device> [binds...] + \\ binds buttons on a joystick device (such as a controller) to commands + \\ + \\OPTIONS: + \\ binds There may be multiple keybindings in the format key,command + \\ + \\EXAMPLES: + \\ zbind /dev/input/by-id/usb-Joystick "0,echo 'hello world' > log.log" "4,script.sh" + , .{}); + std.os.exit(1); +} + +const Keybind = struct { + key: u8, + command: []const u8, + + pub fn parse_string(str: []const u8) !Keybind { + var it = std.mem.splitScalar(u8, str, ','); + const key_str = it.next() orelse return error.InvalidSyntax; + const command = it.next() orelse return error.InvalidSyntax; + const key = try std.fmt.parseInt(u8, key_str, 10); + return .{ + .key = key, + .command = command, + }; + } + + pub fn execute_command(self: *Keybind, allocator: std.mem.Allocator) void { + var child = std.ChildProcess.init(&.{ "/bin/sh", "-c", self.command }, allocator); + child.stdin_behavior = .Ignore; + child.spawn() catch return; + _ = child.wait() catch return; + } +};
\ No newline at end of file |