Skip to content
Open
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
4 changes: 4 additions & 0 deletions Squirrel.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
D26434552706A15100857391 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D26434542706A15100857391 /* QuartzCore.framework */; };
E93074B70A5C264700470842 /* InputMethodKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E93074B60A5C264700470842 /* InputMethodKit.framework */; };
F45E005F2B8CA81C00179B75 /* UserNotifications.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F45E005E2B8CA81C00179B75 /* UserNotifications.framework */; };
4D2A6EB7-BA19-4424-8EE7-631DBEC1AA87 /* StatusBarManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBA6C012-5161-4121-AC4F-E125D9F00676 /* StatusBarManager.swift */; };
/* End PBXBuildFile section */

/* Begin PBXCopyFilesBuildPhase section */
Expand Down Expand Up @@ -297,6 +298,7 @@
D26434542706A15100857391 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
E93074B60A5C264700470842 /* InputMethodKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = InputMethodKit.framework; path = /System/Library/Frameworks/InputMethodKit.framework; sourceTree = "<absolute>"; };
F45E005E2B8CA81C00179B75 /* UserNotifications.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UserNotifications.framework; path = System/Library/Frameworks/UserNotifications.framework; sourceTree = SDKROOT; };
FBA6C012-5161-4121-AC4F-E125D9F00676 /* StatusBarManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = StatusBarManager.swift; path = sources/StatusBarManager.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -327,6 +329,7 @@
B39771282BEDAF4A0093A49B /* SquirrelView.swift */,
B39771242BED899F0093A49B /* SquirrelConfig.swift */,
B35D2FE72BF00839009D156B /* BridgingFunctions.swift */,
FBA6C012-5161-4121-AC4F-E125D9F00676 /* StatusBarManager.swift */,
B38E9B8F2BE9AE1E0036ABEF /* Squirrel-Bridging-Header.h */,
);
name = Sources;
Expand Down Expand Up @@ -589,6 +592,7 @@
B38E9B912BE9AE1E0036ABEF /* SquirrelApplicationDelegate.swift in Sources */,
B39771272BED9B250093A49B /* SquirrelTheme.swift in Sources */,
B35D2FE82BF00839009D156B /* BridgingFunctions.swift in Sources */,
4D2A6EB7-BA19-4424-8EE7-631DBEC1AA87 /* StatusBarManager.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
5 changes: 5 additions & 0 deletions data/squirrel.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ chord_duration: 0.1 # seconds
# options: always | never | appropriate
show_notifications_when: appropriate

# Whether to show the current ascii_mode state in the system menu bar
# true: show "中"/"A" in menu bar
# false: do not show (default)
menubar_ascii_mode: false

style:
color_scheme: native
# Optional: define both light and dark color schemes to match system appearance
Expand Down
5 changes: 5 additions & 0 deletions sources/SquirrelApplicationDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ final class SquirrelApplicationDelegate: NSObject, NSApplicationDelegate, SPUSta
var panel: SquirrelPanel?
var enableNotifications = false
let updateController = SPUStandardUpdaterController(startingUpdater: true, updaterDelegate: nil, userDriverDelegate: nil)
let statusBarManager = StatusBarManager()
var supportsGentleScheduledUpdateReminders: Bool {
true
}
Expand Down Expand Up @@ -61,6 +62,7 @@ final class SquirrelApplicationDelegate: NSObject, NSApplicationDelegate, SPUSta
// swiftlint:disable:next notification_center_detachment
NotificationCenter.default.removeObserver(self)
DistributedNotificationCenter.default().removeObserver(self)
statusBarManager.teardown()
panel?.hide()
}

Expand Down Expand Up @@ -162,6 +164,8 @@ final class SquirrelApplicationDelegate: NSObject, NSApplicationDelegate, SPUSta
}

enableNotifications = config!.getString("show_notifications_when") != "never"
let showStatusInMenuBar = config!.getBool("menubar_ascii_mode") ?? false
statusBarManager.setup(enabled: showStatusInMenuBar)
if let panel = panel, let config = self.config {
panel.load(config: config, forDarkMode: false)
panel.load(config: config, forDarkMode: true)
Expand Down Expand Up @@ -284,6 +288,7 @@ private extension SquirrelApplicationDelegate {
func showStatusMessage(msgTextLong: String?, msgTextShort: String?) {
if !(msgTextLong ?? "").isEmpty || !(msgTextShort ?? "").isEmpty {
panel?.updateStatus(long: msgTextLong ?? "", short: msgTextShort ?? "")
statusBarManager.updateStatus(text: msgTextShort ?? "")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

除了 ascii_mode 也會顯示其他更新的狀態嗎

}
}

Expand Down
15 changes: 15 additions & 0 deletions sources/SquirrelInputController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,9 @@ final class SquirrelInputController: IMKInputController {
if keyboardLayout != "" {
client?.overrideKeyboard(withKeyboardNamed: keyboardLayout)
}
if session != 0 {
updateMenuBarStatus()
}
preedit = ""
}

Expand Down Expand Up @@ -295,6 +298,18 @@ final class SquirrelInputController: IMKInputController {

private extension SquirrelInputController {

func updateMenuBarStatus() {
guard session != 0 else { return }
let isAsciiMode = rimeAPI.get_option(session, "ascii_mode")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

最好先檢查狀態圖標是否啓用,未啓用則不需要獲取當前狀態、簡寫等信息。

"ascii_mode".withCString { name in
let label = rimeAPI.get_state_label_abbreviated(session, name, isAsciiMode, true)
if let str = label.str {
let text = String(cString: str)
NSApp.squirrelAppDelegate.statusBarManager.updateStatus(text: text)
}
}
}

func onChordTimer(_: Timer) {
// chord release triggered by timer
var processedKeys = false
Expand Down
45 changes: 45 additions & 0 deletions sources/StatusBarManager.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//
// StatusBarManager.swift
// Squirrel
//

import AppKit

final class StatusBarManager {
private var statusItem: NSStatusItem?

deinit {
teardown()
}

/// 根据配置初始化或销毁菜单栏图标
/// - Parameters:
/// - enabled: true 创建状态项,false 移除
/// - initialText: 初始显示的文本,默认为空字符串
func setup(enabled: Bool, initialText: String = "") {
if enabled {
if statusItem == nil {
statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
}
if !initialText.isEmpty {
statusItem?.button?.title = initialText
}
} else {
teardown()
}
}

/// 更新菜单栏显示的文本
/// - Parameter text: 要显示的文本,如 "中" 或 "A"
func updateStatus(text: String) {
statusItem?.button?.title = text
}

/// 清理资源,从菜单栏移除状态项
func teardown() {
if let item = statusItem {
NSStatusBar.system.removeStatusItem(item)
statusItem = nil
}
}
}