Skip to content
Draft
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
26 changes: 26 additions & 0 deletions HemuLock/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,32 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
}

observer = EventObserver()

// Check for system launch event - only fire once per system boot
if SystemBootManager.shared.isNewSystemBoot() {
// Mark this boot as notified first to prevent duplicate notifications.
// This ensures the event fires only once per boot, even if the user
// enables/disables the event or relaunches the app during the same boot session.
SystemBootManager.shared.markBootNotified()

// Only handle if System Launch event is enabled in config
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)
}
}
}
}

/**
Expand Down
2 changes: 2 additions & 0 deletions HemuLock/Base.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,15 @@
"SYSTEM_WAKE" = "System Wake";
"SYSTEM_LOCK" = "System Lock";
"SYSTEM_UNLOCK" = "System Unlock";
"SYSTEM_LAUNCH" = "System Started";

"EVENT_SCREEN_SLEEP" = "Screen Sleep";
"EVENT_SCREEN_WAKE" = "Screen Wake";
"EVENT_SYSTEM_SLEEP" = "System Sleep";
"EVENT_SYSTEM_WAKE" = "System Wake";
"EVENT_SYSTEM_LOCK" = "System Lock";
"EVENT_SYSTEM_UNLOCK" = "System Unlock";
"EVENT_SYSTEM_LAUNCH" = "System Launch";

"EMPTY_PUSHOVER" = "Pushover Configuration Parameters Error";
"EMPTY_BARK" = "Bark Configuration Parameters Error";
Expand Down
5 changes: 5 additions & 0 deletions HemuLock/Enums/Event.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ enum Event: String, CaseIterable {
case systemWake = "SYSTEM_WAKE"
case systemLock = "SYSTEM_LOCK"
case systemUnLock = "SYSTEM_UNLOCK"
case systemLaunch = "SYSTEM_LAUNCH"

var name: String {
return rawValue
Expand All @@ -34,6 +35,8 @@ enum Event: String, CaseIterable {
return 130
case .systemUnLock:
return 131
case .systemLaunch:
return 140
}
}

Expand All @@ -51,6 +54,8 @@ enum Event: String, CaseIterable {
return NSNotification.Name(rawValue: "com.apple.screenIsLocked")
case .systemUnLock:
return NSNotification.Name(rawValue: "com.apple.screenIsUnlocked")
case .systemLaunch:
return NSNotification.Name(rawValue: "com.hemulock.systemLaunch")
}
}
}
81 changes: 81 additions & 0 deletions HemuLock/Managers/SystemBootManager.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
//
// SystemBootManager.swift
// HemuLock
//
// Created by HemuLock on 2024/02/09.
//

import Foundation

/**
SystemBootManager handles detection of system boot events.

This manager tracks system boot time and determines if a notification
for the current boot has already been sent. It uses sysctl to get the
system boot time and UserDefaults to persist the last notified boot time.
*/
class SystemBootManager {
static let shared = SystemBootManager()

private let lastBootTimeKey = "last_notified_boot_time"

// Tolerance in seconds for comparing boot times.
// System boot times may have minor differences due to precision,
// so we use a 1-second tolerance to avoid false positives.
private let bootTimeToleranceSeconds: TimeInterval = 1.0

private init() {}

/**
Get the current system boot time using sysctl.

- Returns: The date when the system was last booted, or nil if unable to determine
*/
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
}

/**
Check if this is a new system boot (not just app relaunch).

Compares the current system boot time with the last boot time that was notified.

- Returns: true if this is a new boot that hasn't been notified yet, false otherwise
*/
func isNewSystemBoot() -> Bool {
guard let currentBootTime = getSystemBootTime() else {
// If we can't determine boot time, don't trigger the event
return false
}

// Get the last notified boot time from UserDefaults
if let lastBootTime = UserDefaults.standard.object(forKey: lastBootTimeKey) as? Date {
// If the boot times are different, it's a new boot
// Allow a small tolerance for timing differences
return abs(currentBootTime.timeIntervalSince(lastBootTime)) > bootTimeToleranceSeconds
}

// If no previous boot time is stored, consider it a new boot
return true
}

/**
Mark the current boot as notified.

Stores the current system boot time in UserDefaults to prevent
duplicate notifications for the same boot.
*/
func markBootNotified() {
guard let currentBootTime = getSystemBootTime() else {
return
}
UserDefaults.standard.set(currentBootTime, forKey: lastBootTimeKey)
}
}
2 changes: 2 additions & 0 deletions HemuLock/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,15 @@
"SYSTEM_WAKE" = "System Wake";
"SYSTEM_LOCK" = "System Lock";
"SYSTEM_UNLOCK" = "System Unlock";
"SYSTEM_LAUNCH" = "System Started";

"EVENT_SCREEN_SLEEP" = "Screen Sleep";
"EVENT_SCREEN_WAKE" = "Screen Wake";
"EVENT_SYSTEM_SLEEP" = "System Sleep";
"EVENT_SYSTEM_WAKE" = "System Wake";
"EVENT_SYSTEM_LOCK" = "System Lock";
"EVENT_SYSTEM_UNLOCK" = "System Unlock";
"EVENT_SYSTEM_LAUNCH" = "System Launch";

"EMPTY_PUSHOVER" = "Pushover Configuration Parameters Error";
"EMPTY_BARK" = "Bark Configuration Parameters Error";
Expand Down
2 changes: 2 additions & 0 deletions HemuLock/zh-Hans.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,15 @@
"SYSTEM_WAKE" = "系统被唤醒";
"SYSTEM_LOCK" = "系统已被锁定";
"SYSTEM_UNLOCK" = "系统已解锁";
"SYSTEM_LAUNCH" = "系统已启动";

"EVENT_SCREEN_SLEEP" = "屏幕睡眠";
"EVENT_SCREEN_WAKE" = "屏幕唤醒";
"EVENT_SYSTEM_SLEEP" = "系统睡眠";
"EVENT_SYSTEM_WAKE" = "系统唤醒";
"EVENT_SYSTEM_LOCK" = "锁定";
"EVENT_SYSTEM_UNLOCK" = "解锁";
"EVENT_SYSTEM_LAUNCH" = "系统启动";

"EMPTY_PUSHOVER" = "Pushover配置参数错误";
"EMPTY_BARK" = "Bark配置参数错误";
Expand Down