270 lines
10 KiB
Nix
270 lines
10 KiB
Nix
{ config, pkgs, lib, ... }:
|
|
|
|
{
|
|
# === macOS-specific configuration ===
|
|
|
|
home.packages = with pkgs; [
|
|
# macOS window manager
|
|
aerospace
|
|
|
|
# Keyboard remapping (GUI app — download separately or install via brew)
|
|
# brew install --cask karabiner-elements
|
|
];
|
|
|
|
# =============================================================================
|
|
# KEYBOARD GOAL: Consistent finger positions across keyboards
|
|
#
|
|
# ThinkPad T490 (Linux): Ctrl | Super(Win) | Alt | Space
|
|
# Keychron V10M (macOS): Ctrl | Alt(⌥) | Cmd | Space ← remapped
|
|
# After remap (macOS): Ctrl | Super(Cmd) | Alt | Space
|
|
#
|
|
# Muscle memory:
|
|
# Middle key → Super/Cmd = WM actions (workspaces, focus, move)
|
|
# Next to space → Alt/Option = app shortcuts
|
|
#
|
|
# Remap: Physical Alt(⌥) → Cmd(⌘), Physical Cmd(⌘) → Alt(⌥)
|
|
# Applied via Karabiner-Elements, targeted to Keychron only.
|
|
#
|
|
# To find your Keychron's vendor/product IDs:
|
|
# 1. Open Karabiner-Elements → EventViewer tab
|
|
# 2. Press a key on the Keychron
|
|
# 3. Note the "VendorID" and "ProductID" values
|
|
# 4. Update them in the JSON below
|
|
#
|
|
# =============================================================================
|
|
|
|
home.file.".config/karabiner/karabiner.json" = {
|
|
force = true;
|
|
text = builtins.toJSON {
|
|
global = {
|
|
check_for_updates_on_startup = false;
|
|
show_in_menu_bar = false;
|
|
show_profile_name_in_menu_bar = false;
|
|
};
|
|
profiles = [
|
|
{
|
|
name = "Default";
|
|
selected = true;
|
|
simple_modifications = [];
|
|
fn_function_keys = [];
|
|
virtual_hid_keyboard = {
|
|
keyboard_type = "ansi";
|
|
caps_lock_delay_microseconds = 0;
|
|
};
|
|
devices = [];
|
|
complex_modifications = {
|
|
parameters = {
|
|
"basic.simultaneous_threshold_milliseconds" = 50;
|
|
"basic.to_if_held_down_threshold_milliseconds" = 500;
|
|
"basic.to_delayed_action_delay_milliseconds" = 500;
|
|
"basic.to_if_alone_timeout_milliseconds" = 1000;
|
|
};
|
|
rules = [
|
|
{
|
|
description = "Keychron V10M: swap Option ↔ Command (match ThinkPad bottom row)";
|
|
manipulators = [
|
|
{
|
|
# Physical Alt(⌥) → sends Cmd(⌘) = Super/WM key
|
|
type = "basic";
|
|
from = {
|
|
key_code = "left_alt";
|
|
modifiers = { optional = [ "any" ]; };
|
|
};
|
|
to = [ { key_code = "left_gui"; } ];
|
|
conditions = [
|
|
{
|
|
type = "device_if";
|
|
identifiers = [
|
|
{
|
|
# ⚠ UPDATE THESE with your Keychron's IDs
|
|
vendor_id = 0;
|
|
product_id = 0;
|
|
description = "Keychron V10M (Alice 75)";
|
|
}
|
|
];
|
|
}
|
|
];
|
|
}
|
|
{
|
|
# Physical Cmd(⌘) → sends Alt(⌥) = Alt key
|
|
type = "basic";
|
|
from = {
|
|
key_code = "left_gui";
|
|
modifiers = { optional = [ "any" ]; };
|
|
};
|
|
to = [ { key_code = "left_alt"; } ];
|
|
conditions = [
|
|
{
|
|
type = "device_if";
|
|
identifiers = [
|
|
{
|
|
vendor_id = 0;
|
|
product_id = 0;
|
|
}
|
|
];
|
|
}
|
|
];
|
|
}
|
|
];
|
|
}
|
|
];
|
|
};
|
|
}
|
|
];
|
|
};
|
|
};
|
|
|
|
# =============================================================================
|
|
# AEROSPACE — macOS Tiling Window Manager
|
|
#
|
|
# Keybindings use `cmd` (Super after remap) to match Hyprland's SUPER:
|
|
# Middle key + number → switch workspace
|
|
# Middle key + h/j/k/l → focus direction
|
|
# Middle key + tab → focus next window (cycle through all workspaces)
|
|
# Middle key + shift → move window
|
|
#
|
|
# macOS-native Cmd+Tab (now Alt+Tab after remap) still cycles apps.
|
|
# =============================================================================
|
|
|
|
home.file.".config/aerospace/aerospace.toml" = {
|
|
force = true;
|
|
text = ''
|
|
# =============================================================================
|
|
# Aerospace — macOS Tiling Window Manager
|
|
#
|
|
# Keybinding conventions (after Keychron remap matches ThinkPad):
|
|
# cmd (middle key) = SUPER — WM actions
|
|
# alt (next to space) = ALT — app shortcuts
|
|
# =============================================================================
|
|
|
|
# --- General ---
|
|
[general]
|
|
border = true
|
|
gaps = {
|
|
inner = { px = 6, vertical = 8, horizontal = 8 },
|
|
outer = { px = 4, px-monitor-workspace = 4, bottom = 6 },
|
|
}
|
|
|
|
# =============================================================================
|
|
# WORKSPACE SWITCHING — cmd = middle key
|
|
# =============================================================================
|
|
[mode.main.binding]
|
|
# Switch to workspace
|
|
cmd-1 = "workspace 1"
|
|
cmd-2 = "workspace 2"
|
|
cmd-3 = "workspace 3"
|
|
cmd-4 = "workspace 4"
|
|
cmd-5 = "workspace 5"
|
|
cmd-6 = "workspace 6"
|
|
cmd-7 = "workspace 7"
|
|
cmd-8 = "workspace 8"
|
|
cmd-9 = "workspace 9"
|
|
|
|
# Move window to workspace
|
|
cmd-shift-1 = "move-node-to-workspace 1"
|
|
cmd-shift-2 = "move-node-to-workspace 2"
|
|
cmd-shift-3 = "move-node-to-workspace 3"
|
|
cmd-shift-4 = "move-node-to-workspace 4"
|
|
cmd-shift-5 = "move-node-to-workspace 5"
|
|
cmd-shift-6 = "move-node-to-workspace 6"
|
|
cmd-shift-7 = "move-node-to-workspace 7"
|
|
cmd-shift-8 = "move-node-to-workspace 8"
|
|
cmd-shift-9 = "move-node-to-workspace 9"
|
|
|
|
# =============================================================================
|
|
# FOCUS NAVIGATION — Vim-style with cmd (middle key)
|
|
# =============================================================================
|
|
cmd-h = "focus left"
|
|
cmd-j = "focus down"
|
|
cmd-k = "focus up"
|
|
cmd-l = "focus right"
|
|
|
|
# Tab through windows across all workspaces
|
|
cmd-tab = "focus next"
|
|
|
|
# =============================================================================
|
|
# WINDOW MANAGEMENT
|
|
# =============================================================================
|
|
cmd-f = "fullscreen"
|
|
cmd-w = "close"
|
|
cmd-t = "floating toggle"
|
|
cmd-d = "layout tiles horizontal vertical"
|
|
cmd-shift-d = "layout tiles vertical horizontal"
|
|
|
|
# =============================================================================
|
|
# LAYOUT MANAGEMENT
|
|
# =============================================================================
|
|
cmd-r = "mode resize"
|
|
|
|
cmd-shift-h = "move left"
|
|
cmd-shift-j = "move down"
|
|
cmd-shift-k = "move up"
|
|
cmd-shift-l = "move right"
|
|
|
|
# =============================================================================
|
|
# RESIZE MODE
|
|
# =============================================================================
|
|
[mode.resize.binding]
|
|
cmd-h = "resize -50 0"
|
|
cmd-j = "resize 0 50"
|
|
cmd-k = "resize 0 -50"
|
|
cmd-l = "resize 50 0"
|
|
escape = "mode main"
|
|
enter = "mode main"
|
|
|
|
# =============================================================================
|
|
# MISC
|
|
# =============================================================================
|
|
cmd-shift-period = "reload-config"
|
|
cmd-backslash = "layout v_accordion"
|
|
cmd-shift-slash = "layout h_accordion"
|
|
|
|
# =============================================================================
|
|
# APP CYCLING
|
|
#
|
|
# macOS natively handles app cycling via Cmd+Tab.
|
|
# After Karabiner remap, the physical key next to spacebar now sends Alt,
|
|
# so what was Cmd+Tab is now available as a distinct chord.
|
|
# We use cmd+tab (middle key + tab) for Aerospace's "focus next" above,
|
|
# and the macOS native cycle is still accessible via alt+tab (next-to-space + tab).
|
|
# =============================================================================
|
|
'';
|
|
};
|
|
|
|
# =============================================================================
|
|
# HELPER: Find Keychron keyboard IDs for Karabiner
|
|
# =============================================================================
|
|
home.file.".local/bin/find-keychron-id" = {
|
|
force = true;
|
|
executable = true;
|
|
text = ''
|
|
#!/usr/bin/env bash
|
|
# Find your Keychron's vendor/product IDs for Karabiner-Elements config.
|
|
#
|
|
# Usage: ./find-keychron-id
|
|
#
|
|
# If Karabiner EventViewer is running, check its log for recent key events.
|
|
LOG="$HOME/.local/share/karabiner/eventviewer.log"
|
|
if [ -f "$LOG" ]; then
|
|
echo "Checking Karabiner EventViewer log..."
|
|
grep -i "keychron\|vendor_id\|product_id" "$LOG" 2>/dev/null | tail -10
|
|
fi
|
|
|
|
# Alternative: use ioreg to list HID devices
|
|
echo ""
|
|
echo "All HID keyboard devices (look for Keychron):"
|
|
ioreg -p IOUSB -l -w 0 | grep -A 10 -i "keyboard\|keychron" 2>/dev/null || \\
|
|
ioreg -r -c IOUSBDevice -l -w 0 | grep -A 15 -i "keychron\|keyboard" | grep -E "vendor|product|idProduct|idVendor|USB Product Name" | head -20
|
|
|
|
echo ""
|
|
echo "Or press a key on your Keychron and run:"
|
|
echo " hidutil list 2>/dev/null | grep -i keychron"
|
|
echo ""
|
|
echo "Then update vendor_id and product_id (as DECIMAL numbers) in:"
|
|
echo " ~/.config/karabiner/karabiner.json"
|
|
echo ""
|
|
echo " e.g. if vendor_id=0x3434, product_id=0x0408"
|
|
echo " then in JSON: vendor_id=13364, product_id=1032"
|
|
'';
|
|
};
|
|
}
|