Keep Ctrl+Space out of Fcitx's toggles instead of probing for it

The terminal prefix bind read the Fcitx config and profile on every press
to avoid fighting a Ctrl+Space toggle. configure --defaults now removes
that key from every trigger list, so the bind only checks for a terminal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
David Heinemeier HanssonandClaude Opus 5.5 committed 2026-10-11 08:05:33 +09:00
1 parent cf9e8f3625
commit 0cd685946b
5 files changed
+39 -68

No files matched your search

+7 -20
View File
@@ -107,29 +107,16 @@ assert_fires "the JIS + key zooms the Obsidian Flatpak in with Ctrl + ^" \
$'send CTRL asciicircum down\nsend CTRL asciicircum up' "$zoom" "md.obsidian.Obsidian"
# The prefix bind has to pass Ctrl + Space on, or tmux and Herdr never see it.
# Fcitx never toggles on it (configure --defaults removes it from its keys), so
# a terminal can always return to direct input first.
prefix="CTRL + SPACE"
freed=$'[Hotkey/TriggerKeys]\n0=Zenkaku_Hankaku\n\n[Hotkey/ActivateKeys]\n0=Henkan'
TEST_FCITX5_CONFIG=$freed assert_fires "the terminal prefix switches to direct input once Ctrl + Space no longer toggles" \
$'non_consuming\nexec timeout 0.3 fcitx5-remote --check -c' "$prefix" "com.mitchellh.ghostty" "terminal*"
TEST_FCITX5_CONFIG=$freed assert_fires "the prefix leaves input alone outside terminals" \
"non_consuming" "$prefix" "chromium" "browser"
# While fcitx5 still toggles on Ctrl + Space, switching to direct input would
# undo the toggle it just made.
assert_fires "the prefix leaves input alone without an fcitx5 config" \
"non_consuming" "$prefix" "com.mitchellh.ghostty" "terminal*"
TEST_FCITX5_CONFIG=$'[Behavior]\nShareInputState=No' assert_fires "the prefix leaves input alone with the default trigger keys" \
"non_consuming" "$prefix" "com.mitchellh.ghostty" "terminal*"
TEST_FCITX5_CONFIG=$'[Hotkey/TriggerKeys]\n0=Zenkaku_Hankaku\n1=Control+space' assert_fires "the prefix leaves input alone while Ctrl + Space is a trigger key" \
"non_consuming" "$prefix" "com.mitchellh.ghostty" "terminal*"
direct=$'non_consuming\nexec timeout 0.3 fcitx5-remote --check -c'
assert_fires "the terminal prefix switches to direct input" "$direct" "$prefix" "com.mitchellh.ghostty" "terminal*"
assert_fires "the prefix leaves input alone outside terminals" "non_consuming" "$prefix" "chromium" "browser"
for layout in us kr; do
TEST_LAYOUT="$layout" TEST_FCITX5_CONFIG=$freed assert_fires "the terminal prefix works with $layout keyboards too" \
$'non_consuming\nexec timeout 0.3 fcitx5-remote --check -c' "$prefix" "foot" "terminal"
TEST_LAYOUT="$layout" assert_fires "the terminal prefix works with $layout keyboards too" "$direct" "$prefix" "foot" "terminal"
done
TEST_KEYBOARD_ONLY=true TEST_FCITX5_CONFIG=$freed assert_fires "keyboard-only profiles skip the terminal controller call" \
"non_consuming" "$prefix" "foot" "terminal"
TEST_KEYBOARD_ONLY=true assert_fires "keyboard-only profiles use the same prefix bind" "$direct" "$prefix" "foot" "terminal"
assert_fires "Super + I cycles configured input independently of custom Fcitx keys" \
"exec omarchy-input-method cycle" "SUPER + I" "chromium"
+11 -2
View File
@@ -105,6 +105,14 @@ class InputMethodTest(unittest.TestCase):
self.assertEqual(config["Behavior"], {"ActiveByDefault": "True"})
self.assertEqual(quickphrase.read_text(), "[TriggerKey]\n\n")
def test_ctrl_space_is_removed_from_every_trigger_list(self):
path = self.config / "fcitx5/config"
setup.atomic_write(path, "[Hotkey/TriggerKeys]\n0=Alt+space\n1=Control+space\n2=Hangul\n\n[Behavior]\nActiveByDefault=True\n")
setup.defaults(self.config)
config = setup.sections(path.read_text())
self.assertEqual(config["Hotkey/TriggerKeys"], {"0": "Alt+space", "1": "Hangul"})
self.assertEqual(config["Behavior"], {"ActiveByDefault": "True"})
def test_generated_stock_shortcuts_are_repaired(self):
path = self.config / "fcitx5/config"
setup.atomic_write(path, "[Hotkey/TriggerKeys]\n0=Control+space\n1=Zenkaku_Hankaku\n2=Hangul\n\n[Hotkey/EnumerateGroupForwardKeys]\n0=Super+space\n")
@@ -113,11 +121,12 @@ class InputMethodTest(unittest.TestCase):
self.assertEqual(config["Hotkey/EnumerateGroupForwardKeys"], {})
self.assertNotIn("Control+space", config["Hotkey/TriggerKeys"].values())
def test_existing_engine_inherited_hotkeys_are_preserved(self):
def test_inherited_hotkeys_keep_fcitx_defaults_except_the_ctrl_space_toggle(self):
path = self.config / "fcitx5/config"
setup.atomic_write(path, "[Behavior]\nActiveByDefault=True\n")
setup.defaults(self.config, fresh=False)
self.assertEqual(path.read_text(), "[Behavior]\nActiveByDefault=True\n")
self.assertEqual(path.read_text(), "[Behavior]\nActiveByDefault=True\n\n[Hotkey/TriggerKeys]\n0=Zenkaku_Hankaku\n1=Hangul\n")
self.assertFalse(setup.defaults(self.config, fresh=False))
def test_lao_preference_keeps_a_latin_fcitx_keyboard(self):
self.preference.write_text("INPUT_METHOD=none\nXKB_LAYOUT=la\n")