+ =========. -========. :========- .========- ========= =========. -========. :========- .========- ========= =========. -========. :========- .==================== +:@@@@=@@@@+ @@@@%*@@@% @@@@++@@@@ #@@@+=%@@@ =@@@@%*@@@::@@@*==%@@+ @@@@==@@@% @@@++++@@@ #@@@+=%@@@ =@@@+=%@@@::@@@#=#@@@+ @@@*-+@@@% @@@@%+@@@@ #@@@@@@@@@@@@@@@@@@@@: +:@@@: .@@@+ @@@- @@@% @@@::. @@@ #@@+-..@@@ =@@@* @@@::@@@ .:%@@+ @@@ ::+@@% @@@=- -@@@ #@@- : @@@ =@@- = %@@::@@% + *@@+ @@@ = %@@% @@@@*#@@@@ #@@@@@++@+@++*#%@@@@@: +:@@@:@-%@@+ @@@%- @@@% @@@@= +@@@ #@@@#..@@@ =@@= . %@@::@@@.- =@@+ @@@ . :@@% @@@@::@@@@ #@@= ..@@@ =@@* . *@@::@@+ @ =@@+ @@@ + +@@% @@@@@@@@@@ #@@@@@..-.-:=..#@@@@@: +:@@@@@@@@@+ @@@@- @@@% @@@. .:@@@ #@@= . @@@ =@@*=. #@@::@@% . *@@+ @@@.. -@@% @@@@ %@@@@ #@@- . @@@ =@@# . @@@::@@@ . %@@+ @@@ +. @@% @@@@@@@@@@ #@@@@@%%%@%@@%@%@@@@@: +:@@@@@@@@@+ @@@@@@@@@% @@@@@@@@@@ #@@@@@@@@@ =@@@@@@@@@::@@@@@@@@@+ @@@@@@@@@% @@@@@@@@@@ #@@@@@@@@@ =@@@@@@@@@::@@@@%@@@@+ @@@@@%@@@% @@@@@@@@@@ #@@@@@@@@@@@@@@@@@@@@: + ......... ......... ......... ......... ......... ......... ......... ......... ......... ......... ......... ......... ......... .................... + %@@@@@@@@@@@@@# :@@@@@@@@%. %@@@@@@@@: #@@@@@@@@= *@@@@@@@@# =@@@@@@@@# :@@@@@@@@%. %@@@@@@@@: #@@@@@@@@= *@@@@@@@@# =@@@@@@@@# :@@@%@%@@%. %@@@@@@@@: #@@@@@@@@@@@@@@: +:@@@@@@@@@@@@@@@ =@@=...+@@::@:##.+@.@+ @@#...:@@% @@#...:@@@ #@@....+@@ =@@=...=@@::@@-=@+:@@+ @@@@:*@@@% @@@-..-@@@ #@@:..:@@@ =@@#:*:%@@::@@@@=@@@@+ @@@@@@@@@@@@@@@: +:@@@@==#-*-=@@@@ =@# %@* @@::@.:. = @+ @@+ ==*@@% @@+ ++ *@@ #@@@= @@@@ =@@@%. %@@::@@.:@- @@+ @@@@ -@@@% @@: @@..@@ #@@ -# -@@ =@@ =@..@@::@@*: :+@@+ @@-=-+=:+-*:-@@: +:@@@@*+:--:-@@@@ =@# *=- @@::@+ % =@+ @@+ ==*@@% @@+ - :@@@ #@@@= @@@@ =@@* :@@@@::@@..@- @@+ @@@@ -@@@% @@. @@..@@ #@@ :-@@@ =@@ =@..@@::@@%# *%@@+ @@:---+-#.+::@@: +:@@@@@@@@@@@@@@@ =@@*... %@::@@.:@- @@+ @@* ...@@% @@* @% +@@ #@@@+.@@@@ =@@. ..=@@::@@*...+@@+ @@@@.+@@@% @@@....%@@ #@@.+@@@@@ =@@. - =@@::@@@@@@@@@+ @@@@@@@@@@@@@@@: +.@@@@@@@@@@@@@@@ -@@@@@@@@@:.@@@@@@@@@= @@@@@@@@@# @@@@@@@@@@ *@@@@@@@@@ -@@@@@@@@@:.@@@@@@@@@= @@@@@@@@@# @@@@@@@@@@ *@@@@@@@@@ -@@@#*%@@@:.@@@@@@@@@= @@@@@@@@@@@@@@@: + ............... ...... ...... ...... ...... ...... ...... ...... ...... ...... ...... ...... ...... -@@@@@@@@@@@@: +.@@@@@@@@@@@@@@@@@@ *@@@@@@@@@ =@@@@@@@@@:.@@@@@@@@@+ @@@@@@@@@# @@@@@@@@@@ *@@@@@@@@@ =@@@@@@@@@:.@@@@@@@@@+ @@@@@@@@@# @@@%++%@@@ *@@@+*#@@@ =@@@@@@@@@::@@@@@@@@@@@@: +:@@@@@@@@@@@@@@@@@@ #@@@. %@@@ =@@- . *@@::@@. . =@@+ @@@ ..:@@% @@%... #@@ #@@ #@.-@@ =@@@@* @@@::@@::# :@@+ @@@ #@@@@% @@@=. -@@@ #@@@:.#@@@ =@@@-- %@@::@@@@@@@@@@@@: +:@@@@-=#.=..-.%@@@@ #@@= : @@@ =@@- .:#@@::@@.:@+ @@+ @@@ ..+@@% @@:.@=:+@@ #@@ .. -@@ =@@@@* @@@::@@. :@@@+ @@@ #@@@@% @@- #% :@@ #@@% -@@@ =@@= . +@@::@@@@@@@@@@@@: +:@@@@*=++=+@+=%@@@@ #@% .. =@@ =@@:-# :@@::@@..#: @@+ @@@ #@@@@% @@= *= .@@ #@@ #@ -@@ =@@-:= @@@::@@. # -@@+ @@@ +##@@% @@..@@. @@ #@@ . #@@ =@@- +@@::@@@@@@@@@@@@: +:@@@@@@@@@@@@@@@@@@ #@*=@@*-@@ =@@%::-@@@::@@+::=@@@+ @@@:%@@@@% @@@*::-%@@ #@@:%@=*@@ =@@%-:#@@@::@@++@#:%@+ @@@-::-@@% @@%....#@@ #@+ ##:.@@ =@@*+=%@@@::@@@@@@@@@@@@: + #################+ -########* .######### #########: *########= +########+ -########* .######### #########: *########= +########+ -########* .######### .############: + :::::::::::: ::::::::: .:::::::: .::::::::. ::::::::. ::::::::: ::::::::: .:::::::: .::::::::. ::::::::. ::::::::: ::::::::: .:::::::::::::::::::::::::::: +:@@@@@@@@@@@@::@@@@@@@@@+ @@#%@@#@@% @@@#@@#@@@ #@@@%*@@@@ =@@#@@@#@@::@@%##%@@@+ @@%%@@#@@% @@%#@@#%@@ #@@@@@@@@@ =@@@@@@@@@::@@@@@@@@@+ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@: +:@%*%@##***#@::@@@#-.+@@+ @@* *. @@% @@@ .. @@@ #@@ .: +@@ =@@ :@..@@::@@. : .@@+ @@: =# @@% @@. =+ @@ #@@@%#@@@@ =@@@@@@@@@::@@@%**@@@+ @@@@@@@@@@*##%##*#*%@@@@@@@@@: +:@-::=::.#:%@::@@* .+@@@+ @@@* .@@@% @@@@ @@@@ #@* @@@@@@ =@@* * %@@::@@. . :@@+ @@: : @@% @@.. . @@ #@@@*.@@@@ =@@@%.@@@@::@@@%-=@@@+ @@@@@@@@@@::.:..=@:@@@@@@@@@@: +:@#+#@###@#@@::@@@@%-+@@+ @@@@ =@@@% @@% :: %@@ #@@ .- =@@ =@@@. :@@@::@@. -. @@+ @@:.% @@% @@.- - @@ #@@@%@@@@@ =@@@@@@@@@::@@@@@@@@@+ @@@@@@@@@@*##%##@@#@@@@@@@@@@: +:@@@@@@@@@@@@::@@@@@@@@@+ @@@@#%@@@% @@%#@@#%@@ #@@@#*%@@@ =@@@@*@@@@::@@#**#@@@+ @@%#@@*@@% @@#%%#%#@@ #@@@@@@@@@ =@@@@@@@@@::@@@@@@@@@+ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@: + :----------: :-------- :--------. .--------: --------: --------: :-------- :--------. .--------: --------: --------: :-------- :---------------------------: + ************ ************ ************ ******************************************************************** ************ ************ ************ ************ +:@@@@@@@@@@@@::@@@@@@@@@@@@::@@@@@@@@@@@@::@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@::@@@@@@@@@@@@::@@@@@@@@@@@@::@@@@@@@@@@@@::@@@@@@@@@@@@: +:@@=+=+==+%@@::@@@=++=*-%@@::@@*+*==+=*@@::@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@::@@*+*==+=*@@::@@@=++=*-%@@::@@=+=+==+%@@::@@@@=*=*@@@@: +:@*-++*..:=%@::@@*-::=%:@@@::@@-==..:=-@@::@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@::@@-==..:=-@@::@@*-::=%:@@@::@*-++*..:=%@::@@@@.#. @@@@: +:@@@@@@@@@@@@::@@@@@@@@@@@@::@@@@@@@@@@@@::@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@::@@@@@@@@@@@@::@@@@@@@@@@@@::@@@@@@@@@@@@::@@@@@@@@@@@@: +.@@@@@@@@@@@@:.@@@@@@@@@@@@:.@@@@@@@@@@@@:.@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@:.@@@@@@@@@@@@:.@@@@@@@@@@@@:.@@@@@@@@@@@@:.@@@@@@@@@@@@: + :::::::::::: :::::::::::: :::::::::::: :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::: :::::::::::: :::::::::::: :::::::::::: ++ +
macOS switches input sources per app and per window — never per keyboard. InputPilot watches which keyboard produced the last key press and switches the input source to match. Map each keyboard once, then forget it exists.
+ + +macOS 13+ · signed & notarized · Apache-2.0 · v1.0.1 · brew install --cask lucagerlich/tap/inputpilot
Nothing. You type on the other keyboard and the language is already right. The debug log is the only place it shows its work — useful when reporting a bug, and safe to share.
+ +Three steps, once.
+Type on each keyboard so InputPilot learns it. Devices are recognised again after unplugging, reconnecting, or moving to another port.
+Assign an input source per keyboard in Settings. Add per-device or global fallbacks for anything unmapped.
+A 400 ms debounce and a 1.5 s cooldown keep it from flapping. Modifier-only presses are ignored, so ⌘-Tab never changes your layout.
+InputPilot asks for Input Monitoring — the permission that lets an app see keyboard events. That is a lot to ask for, so here is exactly what it does with it.
+It reads which keyboard sent a key press. It does not read the key.
+Sandboxed apps cannot read HID devices directly, and that is the only way to tell keyboards apart. So InputPilot ships outside the App Store, signed with a Developer ID certificate and notarized by Apple — it opens without warnings.
Some Macs do not populate that list automatically. Add it by hand: System Settings → Privacy & Security → Input Monitoring → + → pick InputPilot in Applications, then switch it on.
macOS applies Input Monitoring on the next launch. Quit InputPilot and open it again.
Yes. Keyboards are identified by vendor, product, transport and name, so a Bluetooth keyboard is recognised again after reconnecting.
Nothing. Free and open source under the Apache 2.0 licence.
macOS 13 or newer. About a minute to set up.
+ +