Skip to content

Commit 0e791a3

Browse files
committed
implement commitComposition to distinguish switch app and switch abc; fix double commit on switch abc
1 parent e60b1c2 commit 0e791a3

File tree

5 files changed

+40
-36
lines changed

5 files changed

+40
-36
lines changed

macosfrontend/macosfrontend-public.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,5 @@ ICUUID create_input_context(const char *appId, id client,
1515
const char *accentColor) noexcept;
1616
void destroy_input_context(ICUUID uuid) noexcept;
1717
void focus_in(ICUUID uuid, bool isPassword) noexcept;
18-
std::string focus_out(ICUUID uuid) noexcept;
18+
std::string commit_composition(ICUUID uuid) noexcept;
19+
void focus_out(ICUUID uuid) noexcept;

macosfrontend/macosfrontend.cpp

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,7 @@ std::string MacosFrontend::keyEvent(ICUUID uuid, const Key &key, bool isRelease,
141141
auto timeEventPtr = timeEvent.release();
142142
}
143143

144-
auto state = ic->getState(keyEvent.accepted());
145-
ic->resetState();
146-
return state;
144+
return ic->popState(keyEvent.accepted());
147145
}
148146

149147
MacosInputContext *MacosFrontend::findIC(ICUUID uuid) {
@@ -212,7 +210,7 @@ void MacosFrontend::focusIn(ICUUID uuid, bool isPassword) {
212210
useAppDefaultIM(program);
213211
}
214212

215-
std::string MacosFrontend::focusOut(ICUUID uuid) {
213+
std::string MacosFrontend::commitComposition(ICUUID uuid) {
216214
auto *ic = findIC(uuid);
217215
if (!ic)
218216
return "{}";
@@ -230,13 +228,18 @@ std::string MacosFrontend::focusOut(ICUUID uuid) {
230228
// At this stage panel is still shown. If removed, a following backspace
231229
// will commit a BS character in VSCode.
232230
ic->setDummyPreedit(false);
233-
auto state = ic->getState(false);
231+
auto state = ic->popState(false);
234232
ic->isSyncEvent = false;
235233

234+
return state;
235+
}
236+
237+
void MacosFrontend::focusOut(ICUUID uuid) {
238+
auto *ic = findIC(uuid);
239+
if (!ic)
240+
return;
236241
FCITX_INFO() << "Focus out " << ic->program();
237242
ic->focusOut();
238-
239-
return state;
240243
}
241244

242245
MacosInputContext::MacosInputContext(MacosFrontend *frontend,
@@ -274,13 +277,14 @@ void MacosInputContext::updatePreeditImpl() {
274277
state_.caretPos = preedit.cursor();
275278
}
276279

277-
std::string MacosInputContext::getState(bool accepted) {
280+
std::string MacosInputContext::popState(bool accepted) {
278281
nlohmann::json j;
279282
j["commit"] = state_.commit;
280283
j["preedit"] = state_.preedit;
281284
j["caretPos"] = state_.caretPos;
282285
j["dummyPreedit"] = state_.dummyPreedit;
283286
j["accepted"] = accepted;
287+
resetState();
284288
return j.dump();
285289
}
286290

@@ -345,7 +349,12 @@ void focus_in(ICUUID uuid, bool isPassword) noexcept {
345349
});
346350
}
347351

348-
std::string focus_out(ICUUID uuid) noexcept {
349-
return with_fcitx(
350-
[=](Fcitx &fcitx) { return fcitx.frontend()->focusOut(uuid); });
352+
std::string commit_composition(ICUUID uuid) noexcept {
353+
return with_fcitx([=](Fcitx &fcitx) {
354+
return fcitx.frontend()->commitComposition(uuid);
355+
});
356+
}
357+
358+
void focus_out(ICUUID uuid) noexcept {
359+
with_fcitx([=](Fcitx &fcitx) { return fcitx.frontend()->focusOut(uuid); });
351360
}

macosfrontend/macosfrontend.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,8 @@ class MacosFrontend : public AddonInstance {
8383
std::string keyEvent(ICUUID, const Key &key, bool isRelease,
8484
bool isPassword);
8585
void focusIn(ICUUID, bool isPassword);
86-
std::string focusOut(ICUUID);
86+
std::string commitComposition(ICUUID uuid);
87+
void focusOut(ICUUID);
8788

8889
private:
8990
Instance *instance_;
@@ -138,7 +139,7 @@ class MacosInputContext : public InputContext {
138139
void setDummyPreedit(bool dummyPreedit) {
139140
state_.dummyPreedit = dummyPreedit;
140141
}
141-
std::string getState(bool accepted);
142+
std::string popState(bool accepted);
142143
// Shows whether we are processing a sync event (mainly key down) that needs
143144
// to return a bool to indicate if it's handled. In this case, commit and
144145
// preedit need to be set in batch synchronously before returning. Otherwise

macosfrontend/macosfrontend.swift

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ private var currentPreedit = ""
66

77
private let zeroWidthSpace = "\u{200B}"
88

9-
public var hasCaret = false
10-
119
private var controller: IMKInputController? = nil
1210

1311
public func setController(_ ctrl: Any) {
@@ -60,16 +58,11 @@ private func setPreedit(_ client: IMKTextInput, _ preedit: String, _ caretPosUtf
6058

6159
public func commitAndSetPreeditSync(
6260
_ client: IMKTextInput, _ commit: String, _ preedit: String, _ caretPos: Int,
63-
_ dummyPreedit: Bool, focusOut: Bool = false
61+
_ dummyPreedit: Bool
6462
) {
6563
if !commit.isEmpty {
6664
commitString(client, commit)
6765
}
68-
// Setting preedit on focus out may cause IMK stall for seconds. High possibility
69-
// to reproduce by having no caret on a Safari page and Cmd+T to open a new Tab.
70-
if focusOut && !hasCaret {
71-
return
72-
}
7366
// Without client preedit, Backspace bypasses IM in Terminal, every key
7467
// is both processed by IM and passed to client in iTerm, so we force a
7568
// dummy client preedit here.
@@ -135,7 +128,6 @@ public func getCaretCoordinates(
135128
forCharacterIndex: followCaret ? (isEnd ? u16pos - 1 : u16pos) : 0,
136129
lineHeightRectangle: &rect)
137130
if rect.width == 0 && rect.height == 0 {
138-
hasCaret = false
139131
return false
140132
}
141133
x.pointee = Double(NSMinX(rect))
@@ -144,6 +136,5 @@ public func getCaretCoordinates(
144136
if followCaret && isEnd {
145137
x.pointee += 10
146138
}
147-
hasCaret = true
148139
return true
149140
}

src/controller.swift

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -63,15 +63,24 @@ class FcitxInputController: IMKInputController {
6363
uuid = create_input_context(appId, client, accentColor)
6464
}
6565

66-
func processRes(_ client: IMKTextInput, _ res: String, focusOut: Bool = false) -> Bool {
66+
override func commitComposition(_ sender: Any!) {
67+
guard let client = client as? IMKTextInput else {
68+
return
69+
}
70+
let res = String(commit_composition(uuid))
71+
// Maybe commit and clear preedit synchronously if user switches to ABC by Ctrl+Space.
72+
// For Rime with CapsLock, the result will depend on ascii_composer/switch_key/Caps_Lock instead of fcitx5-rime config.
73+
let _ = processRes(client, res)
74+
}
75+
76+
func processRes(_ client: IMKTextInput, _ res: String) -> Bool {
6777
guard let data = res.data(using: .utf8),
6878
let response = try? JSONDecoder().decode(SyncResponse.self, from: data)
6979
else {
7080
return false
7181
}
7282
commitAndSetPreeditSync(
73-
client, response.commit, response.preedit, response.caretPos, response.dummyPreedit,
74-
focusOut: focusOut)
83+
client, response.commit, response.preedit, response.caretPos, response.dummyPreedit)
7584
return response.accepted
7685
}
7786

@@ -181,26 +190,19 @@ class FcitxInputController: IMKInputController {
181190
}
182191
}
183192

193+
// activateServer is called when app is in foreground but not necessarily a text field is selected.
184194
override func activateServer(_ client: Any!) {
185195
// overrideKeyboard is needed for pressing space to play in Shotcut.
186196
if let client = client as? IMKTextInput {
187197
client.overrideKeyboard(withKeyboardNamed: "com.apple.keylayout.ABC")
188198
}
189-
// activateServer is called when app is in foreground but not necessarily a text field is selected.
190-
hasCaret = false
191199
// Make sure status bar is updated on click password input, before first key event.
192200
let isPassword = getSecureInputInfo(isOnFocus: true)
193201
focus_in(uuid, isPassword)
194202
}
195203

196204
override func deactivateServer(_ client: Any!) {
197-
guard let client = client as? IMKTextInput else {
198-
return
199-
}
200-
let res = String(focus_out(uuid))
201-
// Maybe commit and clear preedit synchronously if user switches to ABC by Ctrl+Space.
202-
let _ = processRes(client, res, focusOut: true)
203-
hasCaret = false
205+
focus_out(uuid)
204206
}
205207

206208
override func menu() -> NSMenu! {

0 commit comments

Comments
 (0)