Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions cfg_samples/kanata-input-source-helper.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Sample per-user LaunchAgent for kanata-input-source-helper on macOS.

Install this in the logged-in user's LaunchAgents directory, not in
/Library/LaunchDaemons. The input-source helper must run in the user's
Aqua session so macOS Text Input Source Services sees the same enabled
keyboard layouts as the menu bar and real typing behavior.

Customize the helper binary path in ProgramArguments below if needed:
- default: /opt/homebrew/bin/kanata-input-source-helper
- Intel/Homebrew or manual installs might use /usr/local/bin/kanata-input-source-helper

Install:
mkdir -p ~/Library/LaunchAgents
cp cfg_samples/kanata-input-source-helper.plist ~/Library/LaunchAgents/dev.kanata.input-source-helper.plist
chmod 644 ~/Library/LaunchAgents/dev.kanata.input-source-helper.plist
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/dev.kanata.input-source-helper.plist

Reload after editing this plist or replacing the helper binary:
launchctl kickstart -k gui/$(id -u)/dev.kanata.input-source-helper

Uninstall:
launchctl bootout gui/$(id -u)/dev.kanata.input-source-helper
rm ~/Library/LaunchAgents/dev.kanata.input-source-helper.plist
-->
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>dev.kanata.input-source-helper</string>

<key>ProgramArguments</key>
<array>
<string>/opt/homebrew/bin/kanata-input-source-helper</string>
</array>

<key>LimitLoadToSessionType</key>
<string>Aqua</string>

<key>RunAtLoad</key>
<true/>

<key>KeepAlive</key>
<dict>
<key>SuccessfulExit</key>
<false/>
</dict>

<key>StandardOutPath</key>
<string>/tmp/kanata-input-source-helper.log</string>

<key>StandardErrorPath</key>
<string>/tmp/kanata-input-source-helper.log</string>
</dict>
</plist>
19 changes: 19 additions & 0 deletions cfg_samples/macos-input-source.kbd
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
(defcfg
process-unmapped-keys yes
)

(defsrc
ralt
)

(defalias
us (set-input-source "com.apple.keylayout.US")
ru (set-input-source "com.apple.keylayout.RussianWin")
toggle-ru-us (switch
((input-source-is "com.apple.keylayout.US")) @ru break
() @us break)
)

(deflayer base
@toggle-ru-us
)
53 changes: 53 additions & 0 deletions docs/config.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -958,6 +958,35 @@ When activated, the underlying `defsrc` key will be the output action.
_ _ d @src)
----

[[set-input-source]]
=== set-input-source

**Reference**

[cols="1,6"]
|===
| `(set-input-source $input-source-id)`
| macOS-only action that switches to the exact keyboard input source ID.
|===

**Description**

This action uses native macOS Text Input Source Services to select an installed
keyboard input source by its exact ID.

On macOS, input-source actions are executed through the
`kanata-input-source-helper` process. Install it as the per-user LaunchAgent
documented in `docs/setup-macos.md` when using this action.

.Example:
[source]
----
(defalias us (set-input-source "com.apple.keylayout.US"))
----

This is only supported on macOS. Other platforms reject this action during
configuration validation.

[[no-op]]
=== No-op

Expand Down Expand Up @@ -2915,6 +2944,7 @@ if any of the items evaluates to true.
(input-history $input-type $key-name $input-recency)
(layer $layer-name)
(base-layer $layer-name)
(input-source-is $input-source-id)
----

[cols="1,4"]
Expand Down Expand Up @@ -2958,6 +2988,10 @@ The max recency is 8.
| `base-layer`
| Evaluates to true if the most-recently-switched-to layer
from a `layer-switch` action matches `$layer-name`.

| `input-source-is`
| macOS-only. Evaluates to true if the current keyboard input source ID exactly
matches `$input-source-id`, for example `com.apple.keylayout.US`.
|===

**Description**
Expand Down Expand Up @@ -3221,6 +3255,25 @@ if `layer-switch` has never been activated.
)
----

==== input-source-is

The `input-source-is` list item is macOS-only and checks the current keyboard
input source ID using native macOS APIs.

On macOS, this check is executed through the `kanata-input-source-helper`
process so it observes the logged-in user's input-source session. Install the
per-user LaunchAgent documented in `docs/setup-macos.md` when using this
condition.

.Example:
[source]
----
(defalias russian-if-active
(switch
((input-source-is "com.apple.keylayout.RussianWin")) r break
() _ break))
----


[[cmd]]
=== cmd
Expand Down
7 changes: 7 additions & 0 deletions docs/design.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,10 @@

Most of the OS specific code is in `oskbd/` and `keys/`. There's a bit of it in
`kanata/` since the event loops to receive OS events are different.

macOS input-source switching is intentionally split out into
`kanata-input-source-helper`, a per-user LaunchAgent. Kanata can run as root for
keyboard grabbing, but macOS Text Input Source Services state belongs to the
logged-in Aqua user session. The main Kanata process sends small local IPC
requests to the helper for getting or setting the current input source; the
helper performs the native TIS calls in the user's session.
60 changes: 59 additions & 1 deletion docs/setup-macos.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,56 @@ After editing your kanata config (or the plist itself), reload with:
sudo launchctl kickstart -k system/dev.kanata.kanata
```

### 7. Uninstall
### 7. (Optional) Install the input-source helper as a LaunchAgent

If your config uses `(set-input-source "...")` or `(input-source-is "...")`,
install the macOS input-source helper as a per-user LaunchAgent. The helper
must run as the logged-in Aqua console user so macOS Text Input Source Services
sees the same enabled input sources as the menu bar and real typing behavior.

First install the helper binary somewhere stable:

```sh
cargo build --release --bin kanata-input-source-helper
sudo mkdir -p /opt/homebrew/bin
sudo cp target/release/kanata-input-source-helper /opt/homebrew/bin/kanata-input-source-helper
sudo chmod 755 /opt/homebrew/bin/kanata-input-source-helper
```

If you install the helper somewhere else, edit `ProgramArguments` in
[`cfg_samples/kanata-input-source-helper.plist`](../cfg_samples/kanata-input-source-helper.plist)
before loading it.

Install and start the LaunchAgent:

```sh
mkdir -p ~/Library/LaunchAgents
cp cfg_samples/kanata-input-source-helper.plist ~/Library/LaunchAgents/dev.kanata.input-source-helper.plist
chmod 644 ~/Library/LaunchAgents/dev.kanata.input-source-helper.plist
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/dev.kanata.input-source-helper.plist
```

Verify it is running:

```sh
launchctl print gui/$(id -u)/dev.kanata.input-source-helper
```

Logs are written to `/tmp/kanata-input-source-helper.log`.

After editing the helper plist or replacing the helper binary, reload with:

```sh
launchctl kickstart -k gui/$(id -u)/dev.kanata.input-source-helper
```

This is intentionally a LaunchAgent, not a LaunchDaemon. Kanata itself may run
as root for keyboard grabbing, but input-source selection is user-session
state. Running the helper as a root LaunchDaemon can make TIS report layouts as
installed but disabled even though the active user's macOS UI shows them as
enabled.

### 8. Uninstall

Remove the LaunchDaemon (if you installed it):

Expand All @@ -139,10 +188,19 @@ sudo launchctl bootout system/dev.kanata.kanata
sudo rm /Library/LaunchDaemons/dev.kanata.kanata.plist
```

Remove the input-source LaunchAgent (if you installed it):

```sh
launchctl bootout gui/$(id -u)/dev.kanata.input-source-helper
rm ~/Library/LaunchAgents/dev.kanata.input-source-helper.plist
rm -f /tmp/kanata-input-source-helper.log
```

Remove the kanata binary:

```sh
sudo rm /usr/local/bin/kanata
sudo rm /opt/homebrew/bin/kanata-input-source-helper
```

If you are also fully removing the Karabiner driver:
Expand Down
Loading
Loading