Skip to content

Add System Launch event with boot-time detection#9

Draft
Copilot wants to merge 5 commits intomainfrom
copilot/add-system-launch-event
Draft

Add System Launch event with boot-time detection#9
Copilot wants to merge 5 commits intomainfrom
copilot/add-system-launch-event

Conversation

Copy link
Contributor

Copilot AI commented Feb 9, 2026

Adds a new event type that fires once per system boot rather than per app launch. Uses sysctl(KERN_BOOTTIME) to detect actual boot time and persists last-notified boot timestamp in UserDefaults.

Changes

  • Event.swift: Added systemLaunch case with tag 140
  • SystemBootManager.swift: New singleton manager for boot detection
    • Returns nil on sysctl failure to prevent false positives
    • 1-second tolerance for boot time comparison
    • Marks boot as notified before event handling to guarantee once-per-boot behavior
  • AppDelegate.swift: Checks for new boot in applicationDidFinishLaunching, triggers event if enabled
  • Localization: Added SYSTEM_LAUNCH and EVENT_SYSTEM_LAUNCH keys to all locale files

Implementation

// Boot detection using sysctl
func getSystemBootTime() -> Date? {
    var mib = [CTL_KERN, KERN_BOOTTIME]
    var bootTime = timeval()
    var size = MemoryLayout<timeval>.stride
    
    if sysctl(&mib, UInt32(mib.count), &bootTime, &size, nil, 0) != -1 {
        return Date(timeIntervalSince1970: TimeInterval(bootTime.tv_sec))
    }
    return nil
}

// In AppDelegate
if SystemBootManager.shared.isNewSystemBoot() {
    SystemBootManager.shared.markBootNotified()  // Mark first to ensure once-per-boot
    if appState.appConfig.activeEvents.contains(Event.systemLaunch.tag) {
        // Handle notification/recording/script
    }
}

Menu automatically includes the new event via Event.allCases iteration.

Original prompt

Problem Statement

Add a new "System Launch Event" that sends a notification only once after system startup (boot), not on subsequent app launches. This is different from an "App Launch Event" which would fire every time the app is opened.

Requirements

1. Add New Event Type to Event Enum

In HemuLock/Enums/Event.swift:

  • Add a new case systemLaunch = "SYSTEM_LAUNCH" to the enum
  • Assign it tag 140 (following the pattern: 110-111 for screen, 120-121 for system sleep, 130-131 for lock)
  • Since this is not a standard macOS notification, it will be handled differently (triggered manually on app launch)

2. Implement System Boot Detection Logic

Create a new manager file HemuLock/Managers/SystemBootManager.swift:

  • Track the system boot time using sysctl to get system uptime
  • Store the last boot time when a notification was sent in UserDefaults
  • Provide a method to check if this is a new system boot (not just app relaunch)
  • Method signature: func isNewSystemBoot() -> Bool
  • Method to mark boot as notified: func markBootNotified()

3. Trigger System Launch Event in AppDelegate

In HemuLock/AppDelegate.swift, in the applicationDidFinishLaunching method:

  • After initializing the EventObserver (line 373)
  • Check if this is a new system boot using SystemBootManager
  • If it's a new boot, manually trigger the system launch event by calling observer?.handleEvent() with a mock notification for Event.systemLaunch
  • Mark the boot as notified

4. Update EventObserver

In HemuLock/EventObserver.swift:

  • The existing handleEvent method should work with the new event type
  • No changes needed since it dynamically handles all Event enum cases

5. Add Localization Strings

Add to all localization files:

HemuLock/en.lproj/Localizable.strings:

"SYSTEM_LAUNCH" = "System Started";
"EVENT_SYSTEM_LAUNCH" = "System Launch";

HemuLock/zh-Hans.lproj/Localizable.strings:

"SYSTEM_LAUNCH" = "系统已启动";
"EVENT_SYSTEM_LAUNCH" = "系统启动";

HemuLock/Base.lproj/Localizable.strings:

"SYSTEM_LAUNCH" = "System Started";
"EVENT_SYSTEM_LAUNCH" = "System Launch";

6. Update Menu Structure

In HemuLock/Controllers/MenuController.swift:

  • The menu is built dynamically from Event.allCases (line 48)
  • No changes needed - the new event will automatically appear in the menu

7. Update AppConfig Default Events

In HemuLock/Models/AppConfig.swift:

  • The default active events are currently [Event.systemLock.tag, Event.systemUnLock.tag]
  • Consider whether to include the new System Launch event in the default active events (optional, can leave as-is)

Technical Implementation Details

System Boot Detection Logic

Use sysctl to get system uptime:

func getSystemBootTime() -> Date {
    var mib = [CTL_KERN, KERN_BOOTTIME]
    var bootTime = timeval()
    var size = MemoryLayout<timeval>.stride
    
    if sysctl(&mib, UInt32(mib.count), &bootTime, &size, nil, 0) != -1 {
        return Date(timeIntervalSince1970: TimeInterval(bootTime.tv_sec))
    }
    return Date()
}

Store in UserDefaults:

  • Key: "last_notified_boot_time"
  • Compare current boot time with stored boot time
  • If different, it's a new boot

Integration Point

In AppDelegate.applicationDidFinishLaunching:

observer = EventObserver()

// Check for system launch event
if SystemBootManager.shared.isNewSystemBoot() {
    // Create a notification for system launch
    let notification = Notification(name: Notification.Name("SystemLaunchNotification"))
    // Manually trigger the event - need to handle this specially since there's no macOS notification for it
    if appState.appConfig.activeEvents.contains(Event.systemLaunch.tag) {
        // Handle recording
        if appState.appConfig.isRecordEvent {
            observer?.recordEvent(event: .systemLaunch)
        }
        
        // Send notification
        if appState.appConfig.notifyType != Notify.none.tag {
            observer?.sendNotify(event: .systemLaunch)
        }
        
        // Execute script
        if appState.appConfig.isExecScript {
            observer?.runScript(Event.systemLaunch.name)
        }
    }
    
    SystemBootManager.shared.markBootNotified()
}

Files to Modify

  1. HemuLock/Enums/Event.swift - Add new event case
  2. HemuLock/Managers/SystemBootManager.swift - Create new file
  3. HemuLock/AppDelegate.swift - Add system boot check logic
  4. HemuLock/en.lproj/Localizable.strings - Add localization
  5. HemuLock/zh-Hans.lproj/Localizable.strings - Add localization
  6. HemuLock/Base.lproj/Localizable.strings - Add localization

Testing

After implementation, test:

  1. Enable the System Launch event in the menu
  2. Configure a notification service
  3. Restart the system
  4. Verify notification is sent once when app launches after boot
  5. Quit and relaunch the app without rebooting
  6. Verify notification is NOT sent on subsequent app launches
  7. Reboot again...

This pull request was created from Copilot chat.


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 4 commits February 9, 2026 06:49
Co-authored-by: liopoos <12404909+liopoos@users.noreply.github.com>
Co-authored-by: liopoos <12404909+liopoos@users.noreply.github.com>
…ng comments

Co-authored-by: liopoos <12404909+liopoos@users.noreply.github.com>
Co-authored-by: liopoos <12404909+liopoos@users.noreply.github.com>
Copilot AI changed the title [WIP] Add new system launch event for notifications Add System Launch event with boot-time detection Feb 9, 2026
Copilot AI requested a review from liopoos February 9, 2026 06:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants