Remap keys with pure macOS functionality.
Although the efforts of the Karabiner-Elements project are highly appreciated, using it always felt too intrusive and, recently, also like a liability. In fact, although quite unknown, if it comes to simple key remapping tasks, one can use features built directly into macOS.
This project helps in defining remappings easily through a straight-forward configuration file.
Clone this repository and make sure you have Python with pyyaml
installed.
Edit config.yaml
to your needs.
It has the following structure:
keyboard:
fromKey1: toKey1
fromKey2: toKey2
# ...
keypad:
fromKey1: toKey1
# ...
The fromKey
and the toKey
label names correspond to .keyboard
and .keypad
as defined in keytables.yaml
.
For example, to remap
Caps lock to Backspace, and
Backspace to Delete
you have to define config.yaml
as follows:
keyboard:
Capslock: Backspace
Backspace: Delete
Apply your configuration as follows:
hidutil property --set `./remap.py --hidutil-property`
To keep your remapping configuration in effect across restarts, you can load it automatically using launchd. To load your configuration automatically on the next restart, execute the following command:
./remap.py --launchd-plist ~/Library/LaunchAgents/ch.veehait.macos-remap-keys.plist
If you're using Nix with Home Manager on Darwin, you can use something like
the following to manage your mappings. It takes care of applying your remapping
configuration after a home-manager switch
and also links the launchd plist
to get picked up on restarts.
{ config, pkgs, lib, ... }:
let
macos-remap-keys-flake = builtins.getFlake "github:veehaitch/macos-remap-keys";
macos-remap-keys = macos-remap-keys-flake.defaultPackage.x86_64-darwin;
keytables = builtins.toPath "${macos-remap-keys-flake}/keytables.yaml";
config = pkgs.writeText "macos-remap-config.yaml" (builtins.toJSON {
keyboard = {
Capslock = "Backspace";
Backspace = "Delete";
};
});
macos-remap-launchd = pkgs.runCommand "macos-remap-launchd" { } ''
mkdir -p $out
${macos-remap-keys}/bin/remap.py \
--config "${config}" \
--keytables "${keytables}" \
--launchd-plist \
"$out/ch.veehait.macos-remap-keys.plist" >/dev/null
'';
in
{
# Activate the remappings on switch
home.activation."macosRemapKeys" = lib.hm.dag.entryAfter ["writeBoundary"] ''
$DRY_RUN_CMD hidutil property --set \
`${macos-remap-keys}/bin/remap.py \
--config ${config} \
--keytables ${keytables} \
--hidutil-property` >/dev/null
'';
# Activate the remappings on boot
home.file."Library/LaunchAgents/ch.veehait.macos-remap-keys.plist".source = "${macos-remap-launchd}/ch.veehait.macos-remap-keys.plist";
}
Although very similar, the format demanded by hidutil
isn't JSON.
For hidutil property --set
to work, the values of HIDKeyboardModifierMapping{Src,Dst}
have to be numbers in their hexadecimal representation. Using a decimal representation,
as supported by JSON, won't work.
That's a weird decision—just Apple things—which demands some Regex string manipulation.
Wonder what would happen if you'd just use a hex string instead of a number? macOS crashes—completely. Hard to believe? Go ahead and try it yourself but make sure you don't have any unsaved work:
hidutil property --set '{"UserKeyMapping":[{"HIDKeyboardModifierMappingSrc":"0x700000039","HIDKeyboardModifierMappingDst":"0x70000002A"}]}'