Fix: Auto-initialize app after accessibility permission grant

Problem:
- When user first launches the app without accessibility permissions,
  the system shows a permission dialog
- After granting permissions, the app was already running but not
  fully initialized
- User couldn't reopen the app (already running) and functionality
  wasn't available

Solution:
- Implemented permission monitoring with Timer (checks every 1 second)
- Deferred app initialization until permissions are granted
- Split initialization into initializeApp() method
- Automatically initialize once permissions are detected

User Experience:
- User grants permission in System Preferences
- App automatically detects permission change
- App initializes and starts working without restart
- Updated alert message to inform user about auto-start

Technical Changes:
- Added permissionCheckTimer for monitoring
- Added initializeApp() for deferred initialization
- Store config and keyMapper as instance variables
- Use Task { @MainActor } for timer callback
- Changed alert style from warning to informational

🤖 Generated with [Qoder](https://qoder.com)
This commit is contained in:
loveuer
2025-12-02 18:10:53 +08:00
parent 1e8b79585f
commit 72fd1ef2d6
2 changed files with 50 additions and 13 deletions

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
.qoder
# macOS # macOS
.DS_Store .DS_Store
.AppleDouble .AppleDouble

View File

@@ -5,6 +5,9 @@
class AppDelegate: NSObject, NSApplicationDelegate { class AppDelegate: NSObject, NSApplicationDelegate {
private var statusBarController: StatusBarController? private var statusBarController: StatusBarController?
private var eventTapManager: EventTapManager? private var eventTapManager: EventTapManager?
private var config: Config?
private var keyMapper: KeyMapper?
private var permissionCheckTimer: Timer?
func applicationDidFinishLaunching(_ notification: Notification) { func applicationDidFinishLaunching(_ notification: Notification) {
Logger.setup() Logger.setup()
@@ -13,19 +16,37 @@ class AppDelegate: NSObject, NSApplicationDelegate {
Logger.info("================================") Logger.info("================================")
Logger.info("App bundle path: \(Bundle.main.bundlePath)") Logger.info("App bundle path: \(Bundle.main.bundlePath)")
let config = loadConfig() config = loadConfig()
Logger.logLevel = config.log.level Logger.logLevel = config!.log.level
let keyMapper = KeyMapper(fromConfig: config)
keyMapper.printMappings()
Logger.info("Checking accessibility permissions...") Logger.info("Checking accessibility permissions...")
if !checkAccessibilityPermissions() { if !checkAccessibilityPermissions() {
Logger.error("Accessibility permissions not granted!") Logger.warning("Accessibility permissions not granted, waiting for user to grant permissions...")
showAccessibilityAlert() showAccessibilityAlert()
startPermissionMonitoring()
return return
} }
Logger.info("Accessibility permissions granted") Logger.info("Accessibility permissions granted")
initializeApp()
}
func applicationWillTerminate(_ notification: Notification) {
permissionCheckTimer?.invalidate()
eventTapManager?.stop()
Logger.info("Application terminated")
Logger.cleanup()
}
private func initializeApp() {
guard let config = config else {
Logger.error("Configuration not loaded")
return
}
let keyMapper = KeyMapper(fromConfig: config)
self.keyMapper = keyMapper
keyMapper.printMappings()
eventTapManager = EventTapManager(keyMapper: keyMapper) eventTapManager = EventTapManager(keyMapper: keyMapper)
statusBarController = StatusBarController(eventTapManager: eventTapManager!, config: config) statusBarController = StatusBarController(eventTapManager: eventTapManager!, config: config)
@@ -42,10 +63,22 @@ class AppDelegate: NSObject, NSApplicationDelegate {
Logger.info("Application ready") Logger.info("Application ready")
} }
func applicationWillTerminate(_ notification: Notification) { private func startPermissionMonitoring() {
eventTapManager?.stop() Logger.info("Starting permission monitoring...")
Logger.info("Application terminated")
Logger.cleanup() permissionCheckTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
Task { @MainActor in
guard let self = self else { return }
let trusted = AXIsProcessTrusted()
if trusted {
Logger.info("Accessibility permissions granted! Initializing app...")
self.permissionCheckTimer?.invalidate()
self.permissionCheckTimer = nil
self.initializeApp()
}
}
}
} }
private func loadConfig() -> Config { private func loadConfig() -> Config {
@@ -87,9 +120,12 @@ class AppDelegate: NSObject, NSApplicationDelegate {
private func showAccessibilityAlert() { private func showAccessibilityAlert() {
let alert = NSAlert() let alert = NSAlert()
alert.messageText = "Accessibility Permissions Required" alert.messageText = "Accessibility Permissions Required"
alert.informativeText = "uskey needs accessibility permissions to remap keyboard keys.\n\nPlease grant permissions in:\nSystem Preferences > Privacy & Security > Accessibility\n\nAfter granting permissions, restart the app." alert.informativeText = "uskey needs accessibility permissions to remap keyboard keys.\n\nPlease:\n1. Click 'Open System Preferences' in the dialog that appeared\n2. Enable uskey in the Accessibility list\n\nThe app will automatically start once permissions are granted."
alert.alertStyle = .warning alert.alertStyle = .informational
alert.addButton(withTitle: "OK") alert.addButton(withTitle: "OK")
alert.runModal()
DispatchQueue.main.async {
alert.runModal()
}
} }
} }