Compare commits
21 Commits
df0c3657b4
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
b0707744e2
|
|||
|
ce2d957a88
|
|||
|
4962f12867
|
|||
|
79a35cf42e
|
|||
|
8a7923bd4e
|
|||
|
a36c82b2ac
|
|||
|
687f9fe715
|
|||
|
488affbe3a
|
|||
|
5d14340f98
|
|||
|
5ddce57fc0
|
|||
|
6c802d0ae4
|
|||
| 9043844893 | |||
| 015eeab44a | |||
| 9f78401625 | |||
| 8a73de5731 | |||
| 1d7313ad68 | |||
| f0ee83ebbb | |||
| 9e68abf2a0 | |||
| ffadcffdc1 | |||
| 33db0ea301 | |||
| 468c4bd474 |
18
build.zig
18
build.zig
@@ -17,11 +17,13 @@ pub fn build(b: *std.Build) void {
|
|||||||
|
|
||||||
var exe = b.addExecutable(.{
|
var exe = b.addExecutable(.{
|
||||||
.name = "zremap",
|
.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.
|
// complicated build scripts, this could be a generated file.
|
||||||
.root_source_file = .{ .path = "src/main.zig" },
|
.root_module = b.createModule(.{
|
||||||
.target = target,
|
.root_source_file = b.path("src/main.zig"),
|
||||||
.optimize = optimize,
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
exe.linkLibC();
|
exe.linkLibC();
|
||||||
exe.linkSystemLibrary("evdev");
|
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
|
// Creates a step for unit testing. This only builds the test executable
|
||||||
// but does not run it.
|
// but does not run it.
|
||||||
const unit_tests = b.addTest(.{
|
const unit_tests = b.addTest(.{
|
||||||
.root_source_file = .{ .path = "src/main.zig" },
|
.root_module = b.createModule(.{
|
||||||
.target = target,
|
.root_source_file = b.path("src/main.zig"),
|
||||||
.optimize = optimize,
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const run_unit_tests = b.addRunArtifact(unit_tests);
|
const run_unit_tests = b.addRunArtifact(unit_tests);
|
||||||
|
|||||||
2
debug.sh
Executable file
2
debug.sh
Executable 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
6
flake.lock
generated
@@ -2,11 +2,11 @@
|
|||||||
"nodes": {
|
"nodes": {
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1693060755,
|
"lastModified": 1758446476,
|
||||||
"narHash": "sha256-KNsbfqewEziFJEpPR0qvVz4rx0x6QXxw1CcunRhlFdk=",
|
"narHash": "sha256-5rdAi7CTvM/kSs6fHe1bREIva5W3TbImsto+dxG4mBo=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "c66ccfa00c643751da2fd9290e096ceaa30493fc",
|
"rev": "a1f79a1770d05af18111fbbe2a3ab2c42c0f6cd0",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|||||||
61
flake.nix
61
flake.nix
@@ -1,29 +1,44 @@
|
|||||||
{
|
{
|
||||||
description = "zremap nix flake";
|
description = "zremap nix flake";
|
||||||
|
|
||||||
outputs = {
|
outputs =
|
||||||
self,
|
{
|
||||||
nixpkgs,
|
self,
|
||||||
}: {
|
nixpkgs,
|
||||||
defaultPackage.x86_64-linux = with import nixpkgs {system = "x86_64-linux";};
|
}:
|
||||||
stdenv.mkDerivation {
|
{
|
||||||
pname = "zremap";
|
defaultPackage.x86_64-linux =
|
||||||
version = "0.1";
|
with import nixpkgs { system = "x86_64-linux"; };
|
||||||
src = self;
|
stdenv.mkDerivation {
|
||||||
nativeBuildInputs = [zig.hook];
|
pname = "zremap";
|
||||||
buildInputs = [libevdev];
|
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";};
|
devShells.x86_64-linux.default =
|
||||||
mkShell {
|
with import nixpkgs { system = "x86_64-linux"; };
|
||||||
buildInputs = [
|
mkShell {
|
||||||
libevdev
|
nativeBuildInputs = [
|
||||||
zig
|
zig
|
||||||
];
|
lldb
|
||||||
|
];
|
||||||
|
buildInputs = [
|
||||||
|
libevdev
|
||||||
|
pkg-config
|
||||||
|
];
|
||||||
|
|
||||||
shellHook = ''
|
shellHook = ''
|
||||||
echo "happy hacking!"
|
NIX_CFLAGS_COMPILE="-isystem $(pkg-config --variable=includedir libevdev)/libevdev-1.0 $NIX_CFLAGS_COMPILE"
|
||||||
'';
|
echo "happy hacking!"
|
||||||
};
|
'';
|
||||||
};
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
6
makefile
Normal file
6
makefile
Normal 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
|
||||||
78
src/main.zig
78
src/main.zig
@@ -1,41 +1,58 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const c = @cImport({
|
const c = @cImport({
|
||||||
@cInclude("linux/input.h");
|
@cInclude("linux/input.h");
|
||||||
@cInclude("libevdev-1.0/libevdev/libevdev.h");
|
@cInclude("libevdev/libevdev.h");
|
||||||
|
@cInclude("libevdev/libevdev-uinput.h");
|
||||||
@cInclude("errno.h");
|
@cInclude("errno.h");
|
||||||
});
|
});
|
||||||
|
|
||||||
const CapsLockDown = c.input_event{ .type = c.EV_KEY, .code = c.KEY_CAPSLOCK, .value = 1, .time = undefined };
|
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 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 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 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 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 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 {
|
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 {
|
fn inputDeviceOpenAndGrab(dev_name: []const u8) !?*c.libevdev {
|
||||||
// event.* = try std.io.getStdIn().reader().readStruct(@TypeOf(event.*));
|
const dev_fd = try std.fs.openFileAbsolute(dev_name, .{});
|
||||||
//}
|
const dev = c.libevdev_new();
|
||||||
|
if (c.libevdev_set_fd(dev, dev_fd.handle) < 0) {
|
||||||
fn event_write(event: *const c.input_event) !void {
|
return error.libevdevCreateFail;
|
||||||
try std.io.getStdOut().writer().writeStruct(event.*);
|
}
|
||||||
|
if (c.libevdev_grab(dev, c.LIBEVDEV_GRAB) < 0) {
|
||||||
|
return error.libevdevGrabFail;
|
||||||
|
}
|
||||||
|
return dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_esc() !void {
|
fn uinputCreate(dev: *c.libevdev) !?*c.libevdev_uinput {
|
||||||
std.time.sleep(20000);
|
var uinput: *align(8) c.libevdev_uinput = undefined;
|
||||||
try event_write(&EscDown);
|
if (c.libevdev_uinput_create_from_device(@ptrCast(dev), c.LIBEVDEV_UINPUT_OPEN_MANAGED, @ptrCast(&uinput)) < 0) {
|
||||||
try event_write(&Syn);
|
return error.libevdevUinputCreateFail;
|
||||||
std.time.sleep(20000);
|
}
|
||||||
try event_write(&EscUp);
|
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 {
|
pub fn main() !void {
|
||||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
@@ -46,20 +63,11 @@ pub fn main() !void {
|
|||||||
|
|
||||||
if (args.len != 2) {
|
if (args.len != 2) {
|
||||||
std.debug.print("error: expected one argument", .{});
|
std.debug.print("error: expected one argument", .{});
|
||||||
std.os.exit(1);
|
std.posix.exit(1);
|
||||||
}
|
}
|
||||||
const dev_name = args[1];
|
const dev_name = args[1];
|
||||||
var dev_fd = try std.fs.openFileAbsolute(dev_name, .{});
|
const dev = try inputDeviceOpenAndGrab(dev_name);
|
||||||
|
const uinput_dev = try uinputCreate(dev.?);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
var write_esc_lshift: bool = undefined;
|
var write_esc_lshift: bool = undefined;
|
||||||
var write_esc_rshift: bool = undefined;
|
var write_esc_rshift: bool = undefined;
|
||||||
@@ -82,12 +90,12 @@ pub fn main() !void {
|
|||||||
break :outer;
|
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;
|
continue :outer;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.type != c.EV_KEY) {
|
if (event.type != c.EV_KEY) {
|
||||||
try event_write(&event);
|
try uinputWrite(uinput_dev.?, &event);
|
||||||
continue :outer;
|
continue :outer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,16 +108,16 @@ pub fn main() !void {
|
|||||||
event.code = c.KEY_LEFTMETA;
|
event.code = c.KEY_LEFTMETA;
|
||||||
}
|
}
|
||||||
|
|
||||||
try event_write(&event);
|
try uinputWrite(uinput_dev.?, &event);
|
||||||
|
|
||||||
if (write_esc_lshift) {
|
if (write_esc_lshift) {
|
||||||
write_esc_lshift = false;
|
write_esc_lshift = false;
|
||||||
try write_esc();
|
try uinputWriteKey(uinput_dev.?, c.KEY_ESC);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (write_esc_rshift) {
|
if (write_esc_rshift) {
|
||||||
write_esc_rshift = false;
|
write_esc_rshift = false;
|
||||||
try write_esc();
|
try uinputWriteKey(uinput_dev.?, c.KEY_ESC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
5
zremap-start
Executable file
5
zremap-start
Executable 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
13
zremap.service
Normal 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
|
||||||
Reference in New Issue
Block a user