zremap/src/main.zig

128 lines
4.7 KiB
Zig

const std = @import("std");
const c = @cImport({
@cInclude("linux/input.h");
@cInclude("libevdev/libevdev.h");
@cInclude("libevdev/libevdev-uinput.h");
@cInclude("errno.h");
});
const CapsLockDown = c.input_event{ .type = c.EV_KEY, .code = c.KEY_CAPSLOCK, .value = 1, .time = undefined };
const CapsLockUp = c.input_event{ .type = c.EV_KEY, .code = c.KEY_CAPSLOCK, .value = 0, .time = undefined };
const LShiftDown = c.input_event{ .type = c.EV_KEY, .code = c.KEY_LEFTSHIFT, .value = 1, .time = undefined };
const LShiftUp = c.input_event{ .type = c.EV_KEY, .code = c.KEY_LEFTSHIFT, .value = 0, .time = undefined };
const RShiftDown = c.input_event{ .type = c.EV_KEY, .code = c.KEY_RIGHTSHIFT, .value = 1, .time = undefined };
const RShiftUp = c.input_event{ .type = c.EV_KEY, .code = c.KEY_RIGHTSHIFT, .value = 0, .time = undefined };
var uinput: *align(8) c.libevdev_uinput = undefined;
fn event_equal(e1: *const c.input_event, e2: *const c.input_event) bool {
return (e1.type == e2.type) and (e1.code == e2.code) and (e1.value == e2.value);
}
fn inputDeviceOpenAndGrab(dev_name: []const u8) !?*c.libevdev {
const dev_fd = try std.fs.openFileAbsolute(dev_name, .{});
const dev = c.libevdev_new();
if (c.libevdev_set_fd(dev, dev_fd.handle) < 0) {
return error.libevdevCreateFail;
}
if (c.libevdev_grab(dev, c.LIBEVDEV_GRAB) < 0) {
return error.libevdevGrabFail;
}
if (c.libevdev_uinput_create_from_device(@ptrCast(dev), c.LIBEVDEV_UINPUT_OPEN_MANAGED, @ptrCast(uinput)) < 0) {
return error.libevdevUinputCreateFail;
}
return dev;
}
fn uinputCreate(dev: *c.libevdev) !?*c.libevdev_uinput {
if (c.libevdev_uinput_create_from_device(@ptrCast(dev), c.LIBEVDEV_UINPUT_OPEN_MANAGED, @ptrCast(uinput)) < 0) {
return error.libevdevUinputCreateFail;
}
return uinput;
}
fn uinputWrite(uinput_dev: *c.libevdev_uinput, event: *const c.input_event) !void {
if (c.libevdev_uinput_write_event(@ptrCast(uinput_dev), event.type, event.code, event.value) < 0) {
return error.writeFailed;
}
}
fn uinputWriteKey(uinput_dev: *c.libevdev_uinput, key: u16) !void {
const pressKey = c.input_event{ .type = c.EV_KEY, .code = key, .value = 1, .time = undefined };
const releaseKey = c.input_event{ .type = c.EV_KEY, .code = key, .value = 0, .time = undefined };
const sync = c.input_event{ .type = c.EV_SYN, .code = c.SYN_REPORT, .value = 0, .time = undefined };
std.time.sleep(20000);
try uinputWrite(uinput_dev, &pressKey);
try uinputWrite(uinput_dev, &sync);
std.time.sleep(20000);
try uinputWrite(uinput_dev, &releaseKey);
}
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
const allocator = gpa.allocator();
defer _ = gpa.deinit();
const args = try std.process.argsAlloc(allocator);
if (args.len != 2) {
std.debug.print("error: expected one argument", .{});
std.os.exit(1);
}
const dev_name = args[1];
const dev = try inputDeviceOpenAndGrab(dev_name);
//const uinput_dev = try uinputCreate(dev.?);
const uinput_dev = uinput;
var write_esc_lshift: bool = undefined;
var write_esc_rshift: bool = undefined;
var is_lshift_down: bool = false;
var is_rshift_down: bool = false;
outer: while (true) {
var event: c.input_event = undefined;
var rc = c.libevdev_next_event(dev, c.LIBEVDEV_READ_FLAG_NORMAL | c.LIBEVDEV_READ_FLAG_BLOCKING, @ptrCast(&event));
while (rc == c.LIBEVDEV_READ_STATUS_SYNC) {
rc = c.libevdev_next_event(dev, c.LIBEVDEV_READ_FLAG_SYNC, @ptrCast(&event));
}
if (rc == -c.EAGAIN) {
continue :outer;
}
if (rc != c.LIBEVDEV_READ_STATUS_SUCCESS) {
break :outer;
}
if (event.type == c.EV_MSC and event.code == c.MSC_SCAN) {
continue :outer;
}
if (event.type != c.EV_KEY) {
try uinputWrite(uinput_dev, &event);
continue :outer;
}
write_esc_lshift = event_equal(&event, &LShiftUp) and is_lshift_down;
write_esc_rshift = event_equal(&event, &RShiftUp) and is_rshift_down;
is_lshift_down = event_equal(&event, &LShiftDown);
is_rshift_down = event_equal(&event, &RShiftDown);
if (event_equal(&event, &CapsLockUp) or event_equal(&event, &CapsLockDown)) {
event.code = c.KEY_LEFTMETA;
}
try uinputWrite(uinput_dev, &event);
if (write_esc_lshift) {
write_esc_lshift = false;
try uinputWriteKey(uinput_dev, c.KEY_ESC);
}
if (write_esc_rshift) {
write_esc_rshift = false;
try uinputWriteKey(uinput_dev, c.KEY_ESC);
}
}
}