Compare commits

..

21 Commits

Author SHA1 Message Date
b0707744e2 fix nixpkgs to 25.11, update to new zig api 2025-12-01 10:00:33 +01:00
ce2d957a88 flake: update 2025-09-23 22:05:08 +02:00
4962f12867 flake: update 2025-01-25 11:54:55 +01:00
79a35cf42e flake: format and update zig 2025-01-25 11:54:19 +01:00
8a7923bd4e update build syntax 2024-07-16 10:58:36 +02:00
a36c82b2ac version: update 2024-07-16 10:56:43 +02:00
687f9fe715 update build syntax 2024-07-16 10:50:15 +02:00
488affbe3a flake: update 2024-07-16 10:34:44 +02:00
5d14340f98 std.os -> std.posix 2024-05-07 15:31:25 +02:00
5ddce57fc0 flake: update 2024-05-07 12:25:28 +02:00
6c802d0ae4 systemd: add service 2024-03-18 19:37:46 +01:00
9043844893 add basic dbg command 2023-10-04 21:45:28 +02:00
015eeab44a refactor: finish first phase 2023-10-04 21:45:13 +02:00
9f78401625 flake: add lldb to devshell 2023-10-04 21:44:49 +02:00
8a73de5731 flake: update 2023-10-04 20:32:12 +02:00
1d7313ad68 refactor: start refactoring 2023-10-04 20:14:44 +02:00
f0ee83ebbb main: add inputDeviceOpenAndGrab fun 2023-09-04 19:34:00 +02:00
9e68abf2a0 syntax: in zig use ptr.elem instead of ptr.*.elem 2023-09-03 22:35:16 +02:00
ffadcffdc1 syntax: in zig use ptr.elem instead of ptr.*.elem 2023-09-03 22:32:25 +02:00
33db0ea301 uinput: implement uinput functionality 2023-09-03 21:06:16 +02:00
468c4bd474 flake: add a hack to fix build not finding libevdev/libevdev.h 2023-09-03 20:11:47 +02:00
8 changed files with 121 additions and 68 deletions

View File

@@ -17,11 +17,13 @@ pub fn build(b: *std.Build) void {
var exe = b.addExecutable(.{
.name = "zremap",
// In this case the main source file is merely a path, however, in more
// In this case the main source file is merely a path, however, in more),
// complicated build scripts, this could be a generated file.
.root_source_file = .{ .path = "src/main.zig" },
.target = target,
.optimize = optimize,
.root_module = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
}),
});
exe.linkLibC();
exe.linkSystemLibrary("evdev");
@@ -57,9 +59,11 @@ pub fn build(b: *std.Build) void {
// Creates a step for unit testing. This only builds the test executable
// but does not run it.
const unit_tests = b.addTest(.{
.root_source_file = .{ .path = "src/main.zig" },
.target = target,
.optimize = optimize,
.root_module = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
}),
});
const run_unit_tests = b.addRunArtifact(unit_tests);

2
debug.sh Executable file
View File

@@ -0,0 +1,2 @@
#!/usr/bin/env bash
lldb -- ./zig-out/bin/zremap /dev/input/by-path/platform-i8042-serio-0-event-kbd

6
flake.lock generated
View File

@@ -2,11 +2,11 @@
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1693060755,
"narHash": "sha256-KNsbfqewEziFJEpPR0qvVz4rx0x6QXxw1CcunRhlFdk=",
"lastModified": 1758446476,
"narHash": "sha256-5rdAi7CTvM/kSs6fHe1bREIva5W3TbImsto+dxG4mBo=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "c66ccfa00c643751da2fd9290e096ceaa30493fc",
"rev": "a1f79a1770d05af18111fbbe2a3ab2c42c0f6cd0",
"type": "github"
},
"original": {

View File

@@ -1,29 +1,44 @@
{
description = "zremap nix flake";
outputs = {
self,
nixpkgs,
}: {
defaultPackage.x86_64-linux = with import nixpkgs {system = "x86_64-linux";};
stdenv.mkDerivation {
pname = "zremap";
version = "0.1";
src = self;
nativeBuildInputs = [zig.hook];
buildInputs = [libevdev];
};
outputs =
{
self,
nixpkgs,
}:
{
defaultPackage.x86_64-linux =
with import nixpkgs { system = "x86_64-linux"; };
stdenv.mkDerivation {
pname = "zremap";
version = "0.2";
src = self;
nativeBuildInputs = [ zig.hook ];
buildInputs = [
libevdev
pkg-config
];
buildPhase = ''
NIX_CFLAGS_COMPILE=" -isystem $(pkg-config --variable=includedir libevdev)/libevdev-1.0 $NIX_CFLAGS_COMPILE"
'';
};
devShells.x86_64-linux.default = with import nixpkgs {system = "x86_64-linux";};
mkShell {
buildInputs = [
libevdev
zig
];
devShells.x86_64-linux.default =
with import nixpkgs { system = "x86_64-linux"; };
mkShell {
nativeBuildInputs = [
zig
lldb
];
buildInputs = [
libevdev
pkg-config
];
shellHook = ''
echo "happy hacking!"
'';
};
};
shellHook = ''
NIX_CFLAGS_COMPILE="-isystem $(pkg-config --variable=includedir libevdev)/libevdev-1.0 $NIX_CFLAGS_COMPILE"
echo "happy hacking!"
'';
};
};
}

6
makefile Normal file
View File

@@ -0,0 +1,6 @@
install:
cp ./zremap.service /etc/systemd/system
cp ./zremap-start /usr/local/bin
systemctl daemon-reload
systemctl enable zremap.service

View File

@@ -1,41 +1,58 @@
const std = @import("std");
const c = @cImport({
@cInclude("linux/input.h");
@cInclude("libevdev-1.0/libevdev/libevdev.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 EscDown = c.input_event{ .type = c.EV_KEY, .code = c.KEY_ESC, .value = 1, .time = undefined };
const EscUp = c.input_event{ .type = c.EV_KEY, .code = c.KEY_ESC, .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 };
const Syn = c.input_event{ .type = c.EV_SYN, .code = c.SYN_REPORT, .value = 0, .time = 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);
return (e1.type == e2.type) and (e1.code == e2.code) and (e1.value == e2.value);
}
//fn event_read(event: *c.input_event) !void {
// event.* = try std.io.getStdIn().reader().readStruct(@TypeOf(event.*));
//}
fn event_write(event: *const c.input_event) !void {
try std.io.getStdOut().writer().writeStruct(event.*);
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;
}
return dev;
}
fn write_esc() !void {
std.time.sleep(20000);
try event_write(&EscDown);
try event_write(&Syn);
std.time.sleep(20000);
try event_write(&EscUp);
fn uinputCreate(dev: *c.libevdev) !?*c.libevdev_uinput {
var uinput: *align(8) c.libevdev_uinput = undefined;
if (c.libevdev_uinput_create_from_device(@ptrCast(dev), c.LIBEVDEV_UINPUT_OPEN_MANAGED, @ptrCast(&uinput)) < 0) {
return error.libevdevUinputCreateFail;
}
return uinput;
}
fn device_open() !void {}
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.Thread.sleep(20 * std.time.ns_per_ms);
try uinputWrite(uinput_dev, &pressKey);
try uinputWrite(uinput_dev, &sync);
std.Thread.sleep(20 * std.time.ns_per_ms);
try uinputWrite(uinput_dev, &releaseKey);
}
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
@@ -46,20 +63,11 @@ pub fn main() !void {
if (args.len != 2) {
std.debug.print("error: expected one argument", .{});
std.os.exit(1);
std.posix.exit(1);
}
const dev_name = args[1];
var dev_fd = try std.fs.openFileAbsolute(dev_name, .{});
const dev = c.libevdev_new();
if (c.libevdev_set_fd(dev, dev_fd.handle) < 0) {
std.debug.print("evdev: failed creating device from descriptor", .{});
std.os.exit(1);
}
if (c.libevdev_grab(dev, c.LIBEVDEV_GRAB) < 0) {
std.debug.print("evdev: failed grabbing device", .{});
std.os.exit(1);
}
const dev = try inputDeviceOpenAndGrab(dev_name);
const uinput_dev = try uinputCreate(dev.?);
var write_esc_lshift: bool = undefined;
var write_esc_rshift: bool = undefined;
@@ -82,12 +90,12 @@ pub fn main() !void {
break :outer;
}
if (event.type == c.EV_MSC and event.type == c.MSC_SCAN) {
if (event.type == c.EV_MSC and event.code == c.MSC_SCAN) {
continue :outer;
}
if (event.type != c.EV_KEY) {
try event_write(&event);
try uinputWrite(uinput_dev.?, &event);
continue :outer;
}
@@ -100,16 +108,16 @@ pub fn main() !void {
event.code = c.KEY_LEFTMETA;
}
try event_write(&event);
try uinputWrite(uinput_dev.?, &event);
if (write_esc_lshift) {
write_esc_lshift = false;
try write_esc();
try uinputWriteKey(uinput_dev.?, c.KEY_ESC);
}
if (write_esc_rshift) {
write_esc_rshift = false;
try write_esc();
try uinputWriteKey(uinput_dev.?, c.KEY_ESC);
}
}
}

5
zremap-start Executable file
View File

@@ -0,0 +1,5 @@
#!/bin/sh
sleep 1
zremap /dev/input/by-path/platform-i8042-serio-0-event-kbd

13
zremap.service Normal file
View File

@@ -0,0 +1,13 @@
[Unit]
Description=zremap keyboard remapping service
After=system.slice sysinit.target basic.target systemd-journald.socket
Before=shutdown.target multi-user.target
StartLimitIntervalSec=0
[Service]
Type=simple
Restart=no
ExecStart=/usr/local/bin/zremap-start
[Install]
WantedBy=multi-user.target