A Blazingly fast IME switching tool for macOS,
built with Swift and powered by launchd,
delivering near-native IME switching speed.
I've used macism and im-select before.
But on my older Macs, these tools always required a short wait to switch IME modes. It was an unacceptable delay for daily use. (approximately 400ms)
This tool reduces the delay by about 95% when running as a daemon or launchd — down to 5–20 ms (around 20× faster than other tools), delivering near-native IME switching.
(I was already very satisfied with the switching speed since v3.x, but v4.x broke through that limit.)
If you’re a Mac user frustrated by slow IME switching, give it a try.
- Sets and gets the IME in a single operation
- Works as a daemon or launchd(brew service)
- The daemon handles IME switching internally
- Written in native Swift
- Optimized code
- Standalone (
macime):- Get, Set, Save current, Load previous, List all IMEs
- Switch IME while saving the previous one (in single step)
- Output detailed get|list results as JSON
- Daemon/launchd (
macimed):- Blazingly fast switching via daemon or
brew services
- Blazingly fast switching via daemon or
- Compatibility:
- Fallback to
im-selectstyle command usage
- Fallback to
- Others:
- Stable switching for CJK input methods (Experimental)
- v4.0.0:
- Switching speed is extremelly accelarated via internal
IME.swiftcalling.
- Switching speed is extremelly accelarated via internal
- v3.6.0:
- Deprecate
--status--sock-path--macime-pathoptions frommacimed(They don't reflect environmental variable) - Deprecate
--launchdoption frommacime(Doesn't work in some cases) - Allow
macimedsocket command to handle bothimeanddaemonmethods (e.g.ime set com.apple...,daemon get sock-path) - Upgrade macOS version (10.13 -> 10.15)
- Deprecate
- v3.5.0: Add CJK refreshing (Experimental)
- v3.4.0: Revive
$MACIME_TEMP_DIRenv and Add$MACIME_SOCK_PATH - v3.3.3: Deprecate
--jsonoption (Use--detailoption instead) - v3.0.0: Deprecate
$MACIME_TEMP_DIRenvironmental value
- macOS (>=10.15)
com.apple.keylayout.ABCis installed and enabled (Used inloadsub-command)
brew tap riodelphino/tap
brew install macimebrew uninstall macimebrew update
brew upgrade macimeIf launchd service is enabled, ensure to restart it:
brew services restart macimemacimed can be managed by launchd via Homebrew.
# Start `macimed` service
brew services start macime
# Stop `macimed` service
brew services stop macimeNote
Although the service name is macime, it runs macimed internally.
Or, you can also start macimed manually to monitor logs and observe its behavior:
macimedUseful for debuging. (Almost same performance with brew services in macime >= v4.x)
Show macime version:
macime --version
macime -vShow macime help:
macime --help
macime -hSub commands:
macime get [options]
macime set <IME_ID> [options]
macime list [options]
macime save [options]
macime load [options]get
Show the current IME.
set
Switch to the specified IME.
Optionally saves the previous IME.
list
List available IMEs.
save
Save current IME.
load
Restore the previous IME.
macime supports im-select–style shortcuts.
# Falls back to `macime get`
macime
# Falls back to `macime set`
macime com.apple.keylayout.ABC# Get current IME ID
macime get
# com.apple.keylayout.ABC
# Get current IME detailed info as JSON
macime get --detail
# {
# "isSelectCapable" : true,
# "isSelected" : true,
# "localizedName" : "ABC",
# "id" : "com.apple.keylayout.ABC",
# "sourceLanguages" : [
# "en",
# ...
# "zu"
# ]
# }# Set IME
macime set com.apple.keylayout.ABC
# Set IME while saving current IME as `GLOBAL`
macime set com.apple.keylayout.ABC --save
# The IME ID is saved at `/tmp/riodelphino.macime/prev/GLOBAL`
# Set IME while saving current IME as <session_id>
macime set com.apple.keylayout.ABC --save --session-id nvim-1001
# The IME ID is saved at `/tmp/riodelphino.macime/prev/nvim-1001`--cjk-refresh option is also available.
Note
Using set with --save reduces execution time by 50%, compared to running get and set separately.
Other tools require two excutions. (e.g. im-select -> im-select set com.apple.keylayout.ABC)
# Save current IME to `GLOBAL`
macime save
# Current IME ID is set to `/tmp/riodelphino.macime/prev/GLOBAL`
# Save current IME to `<session_id>`
macime save --session-id nvim-1001
# Current IME ID is set to `/tmp/riodelphino.macime/prev/nvim-1001`# Load IME from `GLOBAL`
macime load
# Reads previous IME ID from `/tmp/riodelphino.macime/prev/GLOBAL`, then set it.
# Load IME from `<session_id>`
macime load --session-id nvim-1001
# Reads previous IME ID from `/tmp/riodelphino.macime/prev/nvim-1001`, then set it.--cjk-refresh option is also available.
# Show IME ID list
macime list
# Show IME detailed list as JSON
macime list --detail
# Show only selectable IME
macime list --select-capableNote
--detail and --select-capable can be mixtured
| Option | Available for | Description |
|---|---|---|
| --detail | get, list | Show detailed IME info as JSON |
| --select-capable | get, list | Show only selectable IME |
| --save | set | Save current IME (with macime set only) |
| --session-id | save, load | Specify the save / load session id (= filename in temp dir) |
| --cjk-refresh | set, load | Refresh IME for CJK input methods (Experimental) |
| --cjk-delay | set, load | Set CJK refreshing delay time as a number between 0 and 1 (Default: 0.05) (Experimental) |
| --debug | (all) | Show debug information |
Warning
Experimental. Please test in your environment, then report any issues or submit a PR.
Reduces the failure rate of CJK IME switching, by creating a hidden window and forcibly refreshing the IME.
It still fails sometimes (Not perfect).
e.g.
Google日本語入力: Google Japanese Input百度拼音: Baidu Pinyin搜狗拼音: Sogou Pinyin
via --cjk-refresh and --cjk-delay option:
# Set
macime set com.baidu.inputmethod.BaiduPinyin --cjk-refresh --cjk-delay 0.05
macime set com.sogou.inputmethod.sogou --cjk-refresh --cjk-delay 0.05
# load
macime load --cjk-refresh --cjk-delay 0.05
macimed is a daemon bundled with macime. It enables blazing faster IME switching.
It runs in the background and controls macime by receiving commands over a Unix domain socket.
Run macimed manually (for debugging):
# Show err/log
macimed
# Show more detailed err/log
macimed --debug
Show the macimed version:
macimed --version
macimed -vShow the macimed help:
macimed --help
macimed -hSet log level:
macimed --log-level info # Use: debug|info|warn|error (Default: info)
macimed -l infomacimed listens to:
- /tmp/riodelphino.macime.sock
macimed recieves commands via socket as plain text.
Commands compliant to macime:
ime set com.apple.keylayout.ABC
ime set com.apple.keylayout.ABC --save
ime set com.apple.keylayout.ABC --save --session-id <session-id>
ime load
ime load --session-id <session-id>
# `--cjk-refresh` is also available for `set` and `load`When the socket recieves a command like above, macimed executes macime command with these args immediately.
Commands for macimed:
# Get all informations of `macimed`
daemon info
# Get
daemon get sock-path # Get sock path
daemon get macime-path # Get macime path
# Set
daemon set log-level info # Set log level. Use one of debug|info|warn|error (Default: info)
Note
Currently daemon set is disabled since it requires restarting server and much more modifications.
To test these commands via macime.nvim (Ensure macimed is running):
(e.g.)
require("macime").send("ime set com.apple.keylayout.ABC")
require("macime").send("ime get", function(ok, data) if ok then print(data) end end)
require("macime").send("daemon info", function(ok, data) if ok then print(data) end end)
require("macime").send("daemon get sock-path", function(ok, data) if ok then print(data) end end)
require("macime").send("daemon set log-level debug", function(ok, data) if ok then print(data) end end)Previous IME IDs are stored in the following paths.
When running macimed manually (socket):
- /tmp/riodelphino.macime/GLOBAL
- /tmp/riodelphino.macime/<session_id>
When running via Homebrew service:
- /private/tmp/riodelphino.macime/GLOBAL
- /private/tmp/riodelphino.macime/<session_id>
These files are deleted when you shutdown macOS.
macimed leaves stdout and stderr logs when it is running via Homebrew service.
With Apple Intel:
- /usr/local/var/log/riodelphino/macimed.out.log
- /usr/local/var/log/riodelphino/macimed.err.log
With Apple Silicon:
- /opt/homebrew/var/log/riodelphino/macimed.out.log
- /opt/homebrew/var/log/riodelphino.macimed.err.log
To check the log paths, run :checkhealth macime.
plist path:
- ~/Library/LaunchAgents/homebrew.mxcl.macime.plist
To check the plist paths, run :checkhealth macime.
macimed requires the full-path of macime, and it is automatically determined from one of the following paths:
MACIME_PATH(Environment variable)- /usr/local/bin/macime (Homebrew on Intel Mac)
- /opt/homebrew/bin/macime (Homebrew on Apple Silicon)
The MACIME_PATH is set at brew install time via riodelphino/homebrew-tap/Fomula/macime.rb:
service do
...
environment_variables(
MACIME_PATH: opt_bin/"macime"
)
...
endmacimed determine the sock path from one of the following paths:
MACIME_SOCK_PATH(Environment variable)/tmp/riodelphino.macimed.sock
macimed determine the temp dir from one of the following paths:
MACIME_TEMP_DIR(Environment variable)/tmp/riodelphino.macime
(Recommended) Install wrapper plugin: riodelphino/macime.nvim
It enables macime, macimed and Homebrew service without extra codings.
Via macime.nvim, the IME switching is unstable in following cases:
- When have not run IME switching for a while.
Solution for now:
- Switch IME several times, and might warm up
macimedor CJK IME. It probably reduces the CJK switching error rate.
See further information: Unstable CJK Switching #2
azookey | azookey-Desktop prevents macime set command to work.
I guess it's because they are still alpha version.
Solutions for now:
- Uninstal
azookey
Note
This error was caused by a merge conflict in the tap repository. Sorry for my git mistake.
If you encounter a syntax error during install/reinstall/upgrade macime:
Error: riodelphino/tap/macime: /usr/local/Homebrew/Library/Taps/riodelphino/homebrew-tap/Formula/macime.rb:2: syntax errors found
...
<<<<<<< HEAD
...
~~~~~~
...
=======Resolve it with the follwing steps:
# Remove macime and the tap
brew uninstall macime
brew untap riodelphino/tap
# Reinstall the tap and macime
brew tap riodelphino/tap
brew install macimeThis cleans up the corrupted tap cache and performs a fresh installation.
- Stable IME switching
- Make the server restartable (for
daemon set sock-path xxx)
Contributions are welcome:
# Clone
git clone https://github.com/riodelphino/macime
cd macime
# Build for debug
swift build
# Build for release
swift build -c releaseFor debugging, temporary run the built macimed with the locally built macime:
# In the macime repository root:
MACIME_PATH=.build/release/macime .build/release/macimed- The IME switching concept is inspired by im-select and macism
- The CJK IME workaround comes from ims-mac
- The idea that Swift can manipulate IME states was inspired by Neovim IMEの状態をカーソルの色に反映させる (Japanese)
See CHANGELOG
MIT License. See LICENSE
