From 1c8d9fac0754199fa82c3f6210d7c3dfb350ad12 Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Mon, 17 Aug 2026 01:27:47 +0900 Subject: [PATCH] engine: Ctrl+Shift chords belong to the application Ctrl+Shift+V switched to Vietnamese and ate the key, in every terminal where it pastes; Ctrl+Shift+T and N opened no tab. Only a plain Ctrl+letter is a strans command now; a chord with Shift, Alt, or Super commits what is pending and passes, as Alt and Super chords already did. Caps Lock still works: the keysym's case never mattered. --- README.md | 4 +++- strans.c | 19 ++++++++++++++----- tests/engine_test.c | 10 +++++++--- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index f2bdae0..1540563 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,9 @@ Vietnamese Telex is also available as a compatibility mode. | `Ctrl+H` | One-shot Hanja search | A Korean keyboard's 한/영 key toggles Korean and English, and its 한자 key -is `Ctrl+H`. +is `Ctrl+H`. Only a plain `Ctrl` chord is a strans key: with `Shift`, `Alt`, +or `Super` held it commits what is pending and goes to the application, so +`Ctrl+Shift+V` still pastes. A complete Japanese reading shows its Kanji candidates with none chosen. `Space` chooses the first and then steps on, wrapping (`Shift+Space` steps diff --git a/strans.c b/strans.c index 9d71532..7135314 100644 --- a/strans.c +++ b/strans.c @@ -615,6 +615,16 @@ searchlang(Rune c) return c == LangEMOJI || c == LangHANJA ? c : 0; } +/* + * A chord with Alt or Super, or Ctrl with Shift, is the application's + * (Ctrl+Shift+V pastes); only a plain Ctrl+letter is a strans command. + */ +static int +chord(u32int mod) +{ + return (mod & ~Mshift) != 0 && mod != Mctrl; +} + static void endsearch(void) { @@ -722,12 +732,11 @@ searchkey(u32int ks, u32int mod, Str *com) endsearch(); return 1; } - if(ks >= Kspec || (ks < ' ' && !(mod & Mctrl)) || - (mod & (Malt|Msuper))){ + if(ks >= Kspec || (ks < ' ' && !(mod & Mctrl)) || chord(mod)){ flush(com); return 0; } - if(mod & Mctrl){ + if(mod == Mctrl){ c = ctrlkey(ks); n = searchlang(c); if(n != 0 && n != search.lang){ @@ -821,11 +830,11 @@ transition(u32int ks, u32int mod, Str *com) reset(); return 1; } - if(ks >= Kspec || (mod & (Malt|Msuper))){ + if(ks >= Kspec || chord(mod)){ flush(com); return 0; } - if(mod & Mctrl){ + if(mod == Mctrl){ c = ctrlkey(ks); n = searchlang(c); if(n != 0){ diff --git a/tests/engine_test.c b/tests/engine_test.c index bb5675b..a0f5967 100644 --- a/tests/engine_test.c +++ b/tests/engine_test.c @@ -1636,16 +1636,20 @@ engine_emoji_preedit_languages(struct ct *t) CT_CHECK(t, !keystroke(Kmodfirst+2, 0, &com)); impre(&im, &shown); checkstr(t, "modifier preserves Japanese", "か", &shown); - CT_CHECK(t, keystroke('E', Mctrl|Mshift, &com)); + CT_CHECK(t, keystroke('E', Mctrl, &com)); checkstr(t, "committed Japanese preedit", "か", &com); CT_CHECK(t, search.lang); CT_EQ_INT(t, LangJP, im.l->lang); CT_CHECK(t, !keystroke('E', Mctrl|Malt, &com)); CT_EQ_INT(t, 0, search.lang); - CT_CHECK(t, keystroke('E', Mctrl|Mshift, &com)); + CT_CHECK(t, keystroke('E', Mctrl, &com)); CT_CHECK(t, !keystroke('E', Mctrl|Msuper, &com)); CT_EQ_INT(t, 0, search.lang); - CT_CHECK(t, keystroke('E', Mctrl|Mshift, &com)); + CT_CHECK(t, keystroke('E', Mctrl, &com)); + CT_CHECK(t, !keystroke('V', Mctrl|Mshift, &com)); + CT_EQ_INT(t, 0, search.lang); + CT_EQ_INT(t, LangJP, im.l->lang); + CT_CHECK(t, keystroke('E', Mctrl, &com)); CT_EQ_INT(t, LangJP, im.l->lang); CT_CHECK(t, keystroke('a', 0, &com)); CT_CHECK(t, !keystroke(Kmodfirst+2, 0, &com));