Skip to content

aredancing/mac-layout-switcher

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

⌨️ Caps Layout Switcher

Fast, deterministic keyboard-layout switching on macOS — powered by Hammerspoon.

macOS only lets you cycle through input sources, and its "switch to the last one" shortcut guesses which layout you mean (badly, if you use more than two). This gives every layout its own permanent hotkey, plus keeps the familiar one-key toggle:

  • 👆 Tap CapsLock → toggle between your two most recent layouts
  • ⌨️ Hold CapsLock + a letter → jump straight to a specific layout
  • 🆔 Hold CapsLock + 0 → show & copy the current layout's source ID

Switching is instant and predictable — no more "why is it Korean again?".

Why CapsLock? It's under your finger and almost nobody uses it for ALL-CAPS (hold Shift instead). We repurpose it into a clean modifier key.


Demo (default layout map)

Shortcut Layout
CapsLock tap toggle two most recent
CapsLock + E English
CapsLock + R Russian
CapsLock + K Korean
CapsLock + C Chinese
CapsLock + A Armenian
CapsLock + D German (Austrian)
CapsLock + 0 show/copy current layout ID

These are just examples — you pick your own layouts and letters (see Configure your layouts).


Requirements

  • macOS (tested on Apple Silicon, recent macOS)
  • Hammerspoon (the installer sets it up for you)

Install

Quick install

git clone https://github.com/aredancing/mac-layout-switcher.git
cd mac-layout-switcher
./install.sh

The installer will:

  1. Install Hammerspoon (via Homebrew, if it isn't already installed).
  2. Copy init.lua to ~/.hammerspoon/ (backing up any existing one).
  3. Remap CapsLock → F18 now and persistently (a small LaunchAgent).
  4. Launch Hammerspoon.

Then finish two manual steps macOS requires:

  1. Grant Accessibility — Hammerspoon will prompt you, or go to System Settings → Privacy & Security → Accessibility and enable Hammerspoon. (Required for global hotkeys.)
  2. Click the Hammerspoon menu-bar icon (🔨) → Reload Config.
  3. (Optional) In Hammerspoon Preferences, tick Launch Hammerspoon at login so the hotkeys survive a reboot.

Manual install

If you'd rather not run the script
# 1. Hammerspoon
brew install --cask hammerspoon

# 2. Config
mkdir -p ~/.hammerspoon
cp init.lua ~/.hammerspoon/init.lua

# 3. Remap CapsLock -> F18 (this session)
hidutil property --set \
  '{"UserKeyMapping":[{"HIDKeyboardModifierMappingSrc":0x700000039,"HIDKeyboardModifierMappingDst":0x70000006D}]}'

# 4. Make the remap persistent
cp com.user.capslock-f18.plist ~/Library/LaunchAgents/
launchctl load ~/Library/LaunchAgents/com.user.capslock-f18.plist

Then grant Accessibility to Hammerspoon and Reload Config (see above).


Configure your layouts

The layouts table at the top of init.lua maps a letter → a layout. Every entry is ["<letter>"] = { "Display name", "<sourceID>" }.

You need the source IDs of the layouts you have enabled. Two ways to find them:

A. List them all (recommended). Build and run the tiny helper:

clang -framework Carbon -framework Foundation -o /tmp/list-input-sources tools/list-input-sources.m
/tmp/list-input-sources

It prints your enabled input sources, e.g.:

ABC                                    com.apple.keylayout.ABC
Russian – PC                           com.apple.keylayout.RussianWin
2-Set Korean                           com.apple.inputmethod.Korean.2SetKorean

B. One at a time. Switch to a layout manually (menu bar), then hold CapsLock + 0 — it shows the current layout's ID and copies it to your clipboard.

Then edit ~/.hammerspoon/init.lua, e.g.:

local layouts = {
  ["e"] = { "English (ABC)", "com.apple.keylayout.ABC" },
  ["u"] = { "Ukrainian",     "com.apple.keylayout.Ukrainian-PC" },
  ["j"] = { "Japanese",      "com.apple.inputmethod.Kotoeri.RomajiTyping.Japanese" },
}

Save, then Hammerspoon menu-bar icon → Reload Config. Done.

Tuning the tap: TAP_MAX (default 0.4s) is how long a press can be and still count as a "tap". If quick taps sometimes get missed, raise it to 0.5.


How it works

  • CapsLock as a modifier. CapsLock is a locking toggle, not a normal modifier, so "CapsLock + key" isn't possible directly. We remap it to the otherwise-unused F18 key with hidutil, giving it clean key-down/key-up behavior. Hammerspoon then treats "F18 held" as a modal modifier.
  • Reliable switching. hs.keycodes.currentSourceID() sometimes updates the menu-bar icon but not the actual typing on the first try, so we set it twice.
  • Leaving an IME. Going from an input method (Korean, Chinese, …) to a plain layout, macOS won't release the IME until a different source is selected. The config automatically "bounces" through an intermediate layout so the switch takes on the first press.

Caveats

  • CapsLock's normal ALL-CAPS toggle is disabled — it's now your layout modifier. Use Shift for capitals. (Fully reversible, see below.)
  • Rare stuck modal. If macOS misses a CapsLock key-up, the letters bound in the modal may briefly stop typing. Fix: tap CapsLock once to reset.
  • Some apps bind their own shortcuts; if a chosen letter conflicts inside a specific app, pick another letter in the layouts table.

Uninstall / revert

./uninstall.sh

This removes the LaunchAgent and restores CapsLock to normal. It leaves Hammerspoon and your ~/.hammerspoon/init.lua untouched (delete those manually if you want a full removal).


License

MIT — see LICENSE. Do whatever you like; no warranty.

Built with Hammerspoon. PRs and layout tweaks welcome.

About

Fast, deterministic macOS keyboard-layout switching via Hammerspoon: per-layout hotkeys + a CapsLock tap to toggle the two most recent layouts.

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors