Issues with using system library libevdev

Hey, everyone!

I want to create a small overlay library that sends mouse move and click events.
I’ve seen that on linux you can use libevdev.
I’ve been having some trouble initializing libevdev.

That’s my code:

const std = @import("std");
pub const c = @cImport({
    @cInclude("libevdev/libevdev.h");
    @cInclude("libevdev/libevdev-uinput.h");
});

pub fn main() !void {
    const allocator = std.heap.c_allocator;

    // setup mouse stuff
    const evdev: *c.libevdev = try allocator.create(c.libevdev);
    defer allocator.free(evdev);

    // Open device
    const fd = try std.posix.openZ(
        "/dev/input/event0",
        .{ .ACCMODE = .RDONLY },
        0,
    );
    defer _ = std.posix.close(fd);

    // Initialize libevdev
    try c.libevdev_new_from_fd(fd, &evdev);
}

When I run zig build I get the following stacktrace:

[mo@archlinux rayover]$ zig build
install
└─ install rayover
   └─ zig build-exe rayover Debug native 3 errors
src/main.zig:133:36: error: expected type '[*c]?*cimport.struct_libevdev', found '*const *cimport.struct_libevdev'
    try c.libevdev_new_from_fd(fd, &evdev);
                                   ^~~~~~
src/main.zig:133:36: note: cast discards const qualifier
/home/mo/git/projects/rayover/.zig-cache/o/7fc4b7bfa82ed0d6db3ba59e412c08d6/cimport.zig:508:53: note: parameter type declared here
pub extern fn libevdev_new_from_fd(fd: c_int, dev: [*c]?*struct_libevdev) c_int;
                                                   ~^~~~~~~~~~~~~~~~~~~~
referenced by:
    callMain: /usr/lib/zig/std/start.zig:524:32
    callMainWithArgs: /usr/lib/zig/std/start.zig:482:12
    remaining reference traces hidden; use '-freference-trace' to see all reference traces
/usr/lib/zig/std/mem/Allocator.zig:104:17: error: no size available for type 'cimport.struct_libevdev'
    if (@sizeOf(T) == 0) return @as(*T, @ptrFromInt(math.maxInt(usize)));
                ^
/home/mo/git/projects/rayover/.zig-cache/o/7fc4b7bfa82ed0d6db3ba59e412c08d6/cimport.zig:501:29: note: opaque declared here
pub const struct_libevdev = opaque {};
                            ^~~~~~~~~
/usr/lib/zig/std/meta.zig:116:5: error: Expected pointer, slice, array or vector type, found '*cimport.struct_libevdev'
    @compileError("Expected pointer, slice, array or vector type, found '" ++ @typeName(T) ++ "'");
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/lib/zig/std/mem.zig:4113:30: note: called from here
    if (@sizeOf(std.meta.Elem(Slice)) == 0) return &[0]u8{};

Try using var.

I fixed it! I kinda didn’t know how to handle opaque pointers in this case.
My working solution looks like this:

const std = @import("std");
pub const c = @cImport({
    @cInclude("libevdev/libevdev.h");
    @cInclude("libevdev/libevdev-uinput.h");
});

pub fn main() !void {
    // setup mouse stuff
    var dev: ?*c.libevdev = undefined;

    // Open device

    const fd = try std.posix.openZ(
        "/dev/input/event0",
        .{ .ACCMODE = .RDONLY },
        0,
    );
    defer _ = std.posix.close(fd);

    // Initialize libevdev
    _ = c.libevdev_new_from_fd(fd, &dev);
}
1 Like