diff --git a/fcitx5 b/fcitx5 index 4dd1326..1be1da1 160000 --- a/fcitx5 +++ b/fcitx5 @@ -1 +1 @@ -Subproject commit 4dd13267e928fec22b9d512a27548208bd83dbc2 +Subproject commit 1be1da12e09b1a61dba982f85703738551551c9c diff --git a/macosfrontend/macosfrontend-public.h b/macosfrontend/macosfrontend-public.h index c9787f2..f2f2511 100644 --- a/macosfrontend/macosfrontend-public.h +++ b/macosfrontend/macosfrontend-public.h @@ -18,4 +18,4 @@ uint16_t fcitx_string_to_osx_keycode(const char *) noexcept; ICUUID create_input_context(const char *appId, id client) noexcept; void destroy_input_context(ICUUID uuid) noexcept; void focus_in(ICUUID uuid) noexcept; -void focus_out(ICUUID uuid) noexcept; +std::string focus_out(ICUUID uuid) noexcept; diff --git a/macosfrontend/macosfrontend.cpp b/macosfrontend/macosfrontend.cpp index c156259..5ffcd95 100644 --- a/macosfrontend/macosfrontend.cpp +++ b/macosfrontend/macosfrontend.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -174,12 +175,28 @@ void MacosFrontend::focusIn(ICUUID uuid) { useAppDefaultIM(program); } -void MacosFrontend::focusOut(ICUUID uuid) { +std::string MacosFrontend::focusOut(ICUUID uuid) { auto *ic = findIC(uuid); if (!ic) - return; + return "{}"; + + // Fake a switch input method event to call engine's deactivate method and + // maybe commit and clear preedit synchronously. + ic->isSyncEvent = true; + InputContextEvent event(ic, EventType::InputContextSwitchInputMethod); + auto engine = instance_->inputMethodEngine(ic); + auto entry = instance_->inputMethodEntry(ic); + engine->deactivate(*entry, event); + // At this stage panel is still shown. If removed, a following backspace + // will commit a BS character in VSCode. + ic->setDummyPreedit(false); + auto state = ic->getState(false); + ic->isSyncEvent = false; + FCITX_INFO() << "Focus out " << ic->program(); ic->focusOut(); + + return state; } MacosInputContext::MacosInputContext(MacosFrontend *frontend, @@ -306,6 +323,7 @@ void focus_in(ICUUID uuid) noexcept { with_fcitx([=](Fcitx &fcitx) { return fcitx.frontend()->focusIn(uuid); }); } -void focus_out(ICUUID uuid) noexcept { - with_fcitx([=](Fcitx &fcitx) { return fcitx.frontend()->focusOut(uuid); }); +std::string focus_out(ICUUID uuid) noexcept { + return with_fcitx( + [=](Fcitx &fcitx) { return fcitx.frontend()->focusOut(uuid); }); } diff --git a/macosfrontend/macosfrontend.h b/macosfrontend/macosfrontend.h index f415ec6..1e25781 100644 --- a/macosfrontend/macosfrontend.h +++ b/macosfrontend/macosfrontend.h @@ -75,7 +75,7 @@ class MacosFrontend : public AddonInstance { void destroyInputContext(ICUUID); std::string keyEvent(ICUUID, const Key &key, bool isRelease); void focusIn(ICUUID); - void focusOut(ICUUID); + std::string focusOut(ICUUID); private: Instance *instance_; diff --git a/src/controller.swift b/src/controller.swift index af9a410..11ef43c 100644 --- a/src/controller.swift +++ b/src/controller.swift @@ -44,11 +44,7 @@ class FcitxInputController: IMKInputController { uuid = create_input_context(appId, client) } - func processKey(_ unicode: UInt32, _ modsVal: UInt32, _ code: UInt16, _ isRelease: Bool) -> Bool { - guard let client = client as? IMKTextInput else { - return false - } - let res = String(process_key(uuid, unicode, modsVal, code, isRelease)) + func processRes(_ client: IMKTextInput, _ res: String) -> Bool { do { if let data = res.data(using: .utf8) { let json = try JSON(data: data) @@ -66,6 +62,14 @@ class FcitxInputController: IMKInputController { return false } + func processKey(_ unicode: UInt32, _ modsVal: UInt32, _ code: UInt16, _ isRelease: Bool) -> Bool { + guard let client = client as? IMKTextInput else { + return false + } + let res = String(process_key(uuid, unicode, modsVal, code, isRelease)) + return processRes(client, res) + } + // Default behavior is to recognize keyDown only override func recognizedEvents(_ sender: Any!) -> Int { let events: NSEvent.EventTypeMask = [.keyDown, .flagsChanged] @@ -130,7 +134,12 @@ class FcitxInputController: IMKInputController { } override func deactivateServer(_ client: Any!) { - focus_out(uuid) + guard let client = client as? IMKTextInput else { + return + } + let res = String(focus_out(uuid)) + // Maybe commit and clear preedit synchronously if user switches to ABC by Ctrl+Space. + let _ = processRes(client, res) } override func menu() -> NSMenu! {