@@ -141,6 +141,39 @@ std::string MacosFrontend::keyEvent(ICUUID uuid, const Key &key, bool isRelease,
141141 auto timeEventPtr = timeEvent.release ();
142142 }
143143
144+ bool keepVimPreedit = false ;
145+ if (ic->vimMode () && !keyEvent.accepted () &&
146+ imGetCurrentIMName () != " keyboard-us" ) {
147+ if (key.check (FcitxKey_Escape) ||
148+ key.check (FcitxKey_bracketleft, KeyState::Ctrl) ||
149+ key.check (FcitxKey_c, KeyState::Ctrl)) {
150+ // If the dummy preedit hack on Ctrl was needed, it has to be
151+ // preserved here, otherwise vim won't enter normal mode. Make this
152+ // explicit, as some engines (rime, mozc) will call
153+ // updateUserInterface(UserInterfaceComponent::InputPanel) even if
154+ // input panel was and keeps empty, which makes webpanel clear the
155+ // dummy preedit.
156+ keepVimPreedit = true ;
157+ imSetCurrentIM (" keyboard-us" );
158+ } else if (!ic->inputPanel ().transient () && ic->inputPanel ().empty ()) {
159+ // HACK: For Terminal and iTerm, when pressing an handled ctrl, we
160+ // force a dummy preedit so that the following c or [ could be
161+ // processed by fcitx. It's known that Esc won't work in Terminal,
162+ // but we don't want to force dummy preedit unconditionally as it
163+ // breaks other keys.
164+ if (!isRelease &&
165+ (ic->program () == " com.apple.Terminal" ||
166+ ic->program () == " com.googlecode.iterm2" ) &&
167+ (key.check (FcitxKey_Control_L, KeyState::Ctrl) ||
168+ key.check (FcitxKey_Control_R, KeyState::Ctrl))) {
169+ keepVimPreedit = true ;
170+ ic->setVimPreedit (true );
171+ }
172+ }
173+ }
174+ if (!keepVimPreedit) {
175+ ic->setVimPreedit (false );
176+ }
144177 return ic->popState (keyEvent.accepted ());
145178}
146179
@@ -198,6 +231,12 @@ void MacosFrontend::useAppDefaultIM(const std::string &appId) {
198231 }
199232}
200233
234+ void MacosFrontend::useVimMode (const std::string &appId,
235+ MacosInputContext *ic) {
236+ const auto &vimMode = *config_.vimMode ;
237+ ic->setVimMode (std::ranges::find (vimMode, appId) != vimMode.end ());
238+ }
239+
201240void MacosFrontend::focusIn (ICUUID uuid, bool isPassword) {
202241 auto *ic = findIC (uuid);
203242 if (!ic)
@@ -207,7 +246,10 @@ void MacosFrontend::focusIn(ICUUID uuid, bool isPassword) {
207246 ic->focusIn ();
208247 auto program = ic->program ();
209248 FCITX_INFO () << " Focus in " << program;
210- useAppDefaultIM (program);
249+ if (!program.empty ()) {
250+ useAppDefaultIM (program);
251+ useVimMode (program, ic);
252+ }
211253}
212254
213255std::string MacosFrontend::commitComposition (ICUUID uuid) {
@@ -282,7 +324,7 @@ std::string MacosInputContext::popState(bool accepted) {
282324 j[" commit" ] = state_.commit ;
283325 j[" preedit" ] = state_.preedit ;
284326 j[" caretPos" ] = state_.caretPos ;
285- j[" dummyPreedit" ] = state_.dummyPreedit ;
327+ j[" dummyPreedit" ] = state_.dummyPreedit || state_. vimPreedit ;
286328 j[" accepted" ] = accepted;
287329 resetState ();
288330 return j.dump ();
0 commit comments