rullo24/Zeys
A Windows-ready, Zig keyboard library for seamlessly interacting with low-level keyboard functionality through higher-level Zig functions.
Zeys provides a set of functions for simulating keyboard events, handling hotkeys, and interacting with the Windows API to manage keyboard inputs. It supports binding, unbinding, and triggering hotkeys, simulating key presses and releases, checking key states, and more. This module is intended for use in Windows-based applications.
Platform | Support |
---|---|
Windows | ✔ |
Linux | ❌ |
Mac | ❌ |
NOTE: Currently, the module only supports Windows. Linux support will be considered in future updates (if people would like this).
NOTE: At the time of Zeys v1.1.0's release, this code works on Zig v0.13.0 (the latest release).
Thanks to SuSonicTH, I have had some help in updating this repo (v1.1.0) to allow for it to be downloaded via Zig's built-in package manager (zon).
To use Zeys in your project, simply follow the process below:
zig fetch --save "https://github.com/rullo24/Zeys/archive/refs/tags/v1.1.0.tar.gz"
const std = @import("std");
pub fn build(b: *std.Build) void {
const optimise = b.standardOptimizeOption(.{});
const target = b.standardTargetOptions(.{});
const zeys = b.dependency("Zeys", .{
.target = target,
.optimize = optimise,
});
const exe = b.addExecutable(.{
.name = "tester",
.root_source_file = b.path("test_zeys.zig"),
.optimize = optimise,
.target = target,
});
exe.root_module.addImport("zeys", zeys.module("zeys"));
b.installArtifact(exe);
}
const std = @import("std");
const zeys = @import("zeys");
pub fn main() void {
while (true) {
if (zeys.isPressed(zeys.VK.VK_A) == true) {
std.debug.print("ON\n", .{});
}
}
return;
}
/// Binds a hotkey to a Windows WM_HOTKEY message.
///
/// - `keys`: The virtual keys to bind.
/// - `p_func`: The callback function to invoke when the hotkey is triggered.
/// - `p_args_struct`: The arguments to pass to the callback.
/// - `repeat`: Whether the hotkey should repeat more than once when held down.
bindHotkey(keys: []const VK, p_func: *const fn (*anyopaque) void, p_args_struct: *?anyopaque, repeat: bool) !void
/// Unbinds a hotkey, preventing the associated WM_HOTKEY messages from being sent.
///
/// - `keys`: The virtual keys of the hotkey to unbind.
unbindHotkey(keys: []const VK) !void
/// Simulates an infinite wait loop while calling callback functions when hotkeys are triggered.
zeysInfWait() void
/// Waits for the specified keys to be pressed (simulates a while (not_pressed)) and triggers the corresponding hotkey callback functions.
///
/// - `virt_keys`: The virtual keys to wait for before passing over this function
waitUntilKeysPressed(virt_keys: []const VK) !void
/// Returns the virtual keys (VK) that are currently pressed (globally).
///
/// - `vk_buf`: A mutable buffer slice of type `VK` to store the keys detected as pressed. The buffer must be at least 255 elements long.
///
/// Returns a slice of Zeys virtual keys.
getCurrPressedKeys(vk_buf: []VK) ![]VK
/// Checks if the specified key is currently pressed.
///
/// - `virt_key`: The virtual key to check.
///
/// Returns true if the key is pressed, false otherwise.
isPressed(virt_key: VK) bool
/// Checks if the specified toggle key is active (e.g., Caps Lock, Num Lock).
///
/// - `virt_key`: The toggle key to check.
///
/// Returns true if the toggle key is active, false otherwise.
isToggled(virt_key: VK) !bool
/// Simulates pressing and releasing a key once, with a 1ms delay to avoid undefined behavior.
///
/// - `virt_key`: The virtual key to press and release.
pressAndReleaseKey(virt_key: VK) !void
/// Simulates pressing a sequence of keys corresponding to the characters in the provided string.
///
/// - `str`: The string of characters to simulate as key presses.
pressKeyString(str: []const u8) !void
/// Checks if the specified key is a modifier key (e.g., Ctrl, Shift, Alt).
///
/// - `virt_key`: The key to check.
///
/// Returns true if the key is a modifier, false otherwise.
keyIsModifier(virt_key: VK) bool
/// Retrieves the current keyboard's locale ID (hexadecimal string).
///
/// - `alloc`: The memory allocator to use for the locale ID string.
///
/// Returns the keyboard locale ID.
getKeyboardLocaleIdAlloc(alloc: std.mem.Allocator) ![]u8
/// Converts a Windows locale ID (hex string) to a human-readable string.
///
/// - `u8_id`: The locale ID in hexadecimal string format.
///
/// Returns the keyboard layout string corresponding to the locale ID.
getKeyboardLocaleStringFromWinLocale(u8_id: []const u8) ![]const u8
/// Blocks all user input (keyboard and mouse) system-wide. Requires admin privileges.
blockAllUserInput() !void
/// Unblocks all user input (keyboard and mouse) system-wide. Requires admin privileges.
unblockAllUserInput() !void
/// Converts a virtual key enum (`VK`) to its corresponding `u8` representation.
///
/// - `virt_key_enum`: The virtual key enum value to convert.
getCharFromVkEnum(virt_key_enum: VK) !u8
/// Converts a `c_short` integer value to its corresponding virtual key enum (`VK`).
///
/// - `vk_short`: The `c_short` integer representing a virtual key code.
getVkEnumFromCShort(vk_short: c_short) !VK
/// Retrieves the virtual key code corresponding to the given ASCII character.
///
/// - `ex_char`: An ASCII character (`u8`).
getVkFromChar(ex_char: u8) !VK
Virtual keys are constants used by the Windows API to represent keyboard keys. These constants are part of the enum(c_short) declaration in Zeys and correspond to both standard and special keys i.e. function keys (F1-F12), numeric keypad keys, and modifier keys (e.g., Shift, Ctrl, Alt).
This enum allows for more manageable code when working with keyboard inputs, as you can use meaningful names like VK_A, VK_RETURN (enter), and VK_SHIFT instead of raw numeric values. Virtual keys are essential for simulating key presses and managing hotkeys in the Zeys module.
List of Common Virtual Keys
Here’s how you can use the virtual keys in Zeys to simulate key presses or bind hotkeys:
// Simulating a key press of the "A" key
pressAndReleaseKey(zeys.VK.VK_A); // Simulates pressing and releasing the 'A' key
// Binding a hotkey to Ctrl+Shift+Z
try zeys.bindHotkey( &[_]zeys.VK{ zeys.VK.VK_Z, zeys.VK.VK_CONTROL, zeys.VK.VK_SHIFT, }, &tester_func_1, @constCast(&.{}), false);
These virtual keys are used throughout the Zeys module for functions like bindHotkey(), pressAndReleaseKey(), isPressed(), and more. They help to ensure that the module can interact with the system in a way that aligns with Windows' key-coding conventions.
To bind a hotkey, use the bindHotkey() function. This will associate a specific combination of keys with a function to be called when the hotkey is pressed.
fn tester_func_1(args: *anyopaque) void {
_ = args;
std.debug.print("You're working in tester_func_1() :)\n", .{});
}
pub fn main() {
std.debug.print("Press Z + CTRL + SHIFT to run tester_func_1\n", .{});
std.debug.print("Press 0 to move to the next example\n", .{});
// var tester_1: test_struct_1 = .{};
try zeys.bindHotkey( &[_]zeys.VK{ zeys.VK.VK_Z, zeys.VK.VK_CONTROL, zeys.VK.VK_SHIFT, },
&tester_func_1,
@constCast(&.{}), // need to parse an empty struct for no arguments --> casting struct to pointer
false);
try zeys.waitUntilKeysPressed( &[_]zeys.VK{ zeys.VK.VK_0, });
try zeys.unbindHotkey( &[_]zeys.VK{ zeys.VK.VK_Z, zeys.VK.VK_CONTROL, zeys.VK.VK_SHIFT, });
}
To unbind a hotkey, use the unbindHotkey() function and provide the same key combination used during binding.
unbindHotkey( &[_]zeys.VK{ zeys.VK.VK_B, } );
To simulate a key press, you can use the pressAndReleaseKey() function.
pressAndReleaseKey(zeys.VK.VK_A); // Simulate pressing and releasing the 'A' key
To block all user input (keyboard and mouse), use the blockAllUserInput() function.
blockAllUserInput();
For more example usage of the library, please check the ./example directory included in this repo. This folder explains in higher detail the intricacies of the project.
This module relies on several Windows API functions to interact with the system's keyboard and input functionality. Some of the key functions used include:
Zeys uses Zig's built-in error handling for common failure scenarios, such as:
This module is provided as-is. I am not responsible for any misuse or unintended consequences that may result from using this module. Please use it responsibly and ensure you have proper safeguards in place before using any functions that block input or simulate key presses.
This project is licensed under the MIT License - see the LICENSE file for details.