Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions sources/SquirrelApplicationDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@
notifCenter.addObserver(forName: .init("SquirrelGetASCIIModeNotification"), object: nil, queue: nil, using: rimeGetASCIIMode)
notifCenter.addObserver(forName: .init(kTISNotifySelectedKeyboardInputSourceChanged as String), object: nil, queue: .main) { [weak self] _ in
self?.updateStatusItemVisibility()
self?.finalizeStrandedComposition()
}
}

Expand All @@ -268,7 +269,7 @@
}
}

private func notificationHandler(contextObject: UnsafeMutableRawPointer?, sessionId: RimeSessionId, messageTypeC: UnsafePointer<CChar>?, messageValueC: UnsafePointer<CChar>?) {

Check warning on line 272 in sources/SquirrelApplicationDelegate.swift

View workflow job for this annotation

GitHub Actions / build

Function should have complexity 10 or less; currently complexity is 13 (cyclomatic_complexity)
let delegate: SquirrelApplicationDelegate = Unmanaged<SquirrelApplicationDelegate>.fromOpaque(contextObject!).takeUnretainedValue()

let messageType = messageTypeC.map { String(cString: $0) }
Expand Down Expand Up @@ -357,8 +358,23 @@

func updateStatusItemVisibility() {
guard let statusItem = statusItem else { return }
let id = SquirrelInstaller.currentInputSourceID() ?? ""
statusItem.isVisible = id.hasPrefix("im.rime.inputmethod.Squirrel")
let currentInputSourceID = SquirrelInstaller.currentInputSourceID() ?? ""
statusItem.isVisible = currentInputSourceID.hasPrefix("im.rime.inputmethod.Squirrel")
}

// macOS 26 does not call deactivateServer when the input source is switched
// away by another process via TISSelectInputSource() (e.g. macism, Input
// Source Pro): the pending composition is stranded and the candidate panel
// is left orphaned on screen (#1140). The input-source-changed notification
// is still delivered, so finalize the composition here as a fallback.
// Switching via the menu bar calls deactivateServer first, making this a
// no-op.
func finalizeStrandedComposition() {
let currentInputSourceID = SquirrelInstaller.currentInputSourceID() ?? ""
guard !currentInputSourceID.hasPrefix("im.rime.inputmethod.Squirrel") else { return }
if let inputController = panel?.inputController {
inputController.deactivateServer(inputController.client())
}
}

func applyStatusIcon(asciiMode: Bool, schemaLabel: String?) {
Expand Down Expand Up @@ -393,7 +409,7 @@
func rimeToggleASCIIMode(_ notification: Notification) {
guard let mode = notification.object as? String else { return }
let enableASCII = mode == "ascii"

if enableASCII {
NotificationCenter.default.post(name: .init("SquirrelSetASCIIModeNotification"), object: true)
} else {
Expand Down
21 changes: 9 additions & 12 deletions sources/SquirrelInputController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ final class SquirrelInputController: IMKInputController {
preedit = ""
// Update menu bar icon
if session != 0 {
let state = rimeAPI.get_option(session, "ascii_mode");
let state = rimeAPI.get_option(session, "ascii_mode")
let label = rimeAPI.get_state_label_abbreviated(session, "ascii_mode", state, true).asString
NSApp.squirrelAppDelegate.updateStatusIcon(asciiMode: state, schemaLabel: label)
}
Expand All @@ -208,7 +208,7 @@ final class SquirrelInputController: IMKInputController {
// print("[DEBUG] initWithServer: \(server ?? .init()) delegate: \(delegate ?? "nil") client:\(client ?? "nil")")
super.init(server: server, delegate: delegate, client: client)
createSession()

// Listen for ASCII mode toggle notifications
NotificationCenter.default.addObserver(
forName: .init("SquirrelSetASCIIModeNotification"),
Expand All @@ -217,7 +217,7 @@ final class SquirrelInputController: IMKInputController {
) { [weak self] notification in
self?.handleASCIIModeToggle(notification)
}

// Listen for ASCII mode status requests
NotificationCenter.default.addObserver(
forName: .init("SquirrelReportASCIIModeNotification"),
Expand All @@ -226,8 +226,6 @@ final class SquirrelInputController: IMKInputController {
) { [weak self] notification in
self?.reportASCIIMode(notification)
}


}

override func deactivateServer(_ sender: Any!) {
Expand Down Expand Up @@ -637,27 +635,26 @@ private extension SquirrelInputController {
private func handleASCIIModeToggle(_ notification: Notification) {
guard let enableASCII = notification.object as? Bool else { return }
guard session != 0 && rimeAPI.find_session(session) else { return }

rimeAPI.set_option(session, "ascii_mode", enableASCII)

// Force update the UI to reflect the mode change
rimeUpdate()
}

private func reportASCIIMode(_: Notification) {
// Only active input controller should respond
guard let client = client else { return }
guard session != 0 && rimeAPI.find_session(session) else { return }

let isASCIIMode = rimeAPI.get_option(session, "ascii_mode")
let status = isASCIIMode ? "ascii" : "nascii"

// Directly respond with the status
DistributedNotificationCenter.default().postNotificationName(
.init("SquirrelASCIIModeResponse"),
.init("SquirrelASCIIModeResponse"),
object: status
)
}


}
Loading