diff --git a/BLEUnlock/AppDelegate.swift b/BLEUnlock/AppDelegate.swift
index 4ee9c91..407bddd 100644
--- a/BLEUnlock/AppDelegate.swift
+++ b/BLEUnlock/AppDelegate.swift
@@ -16,6 +16,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate, NSMenuItemVa
let unlockRSSIMenu = NSMenu()
let timeoutMenu = NSMenu()
let lockDelayMenu = NSMenu()
+ let externalDisplayMenu = NSMenu()
var deviceDict: [UUID: NSMenuItem] = [:]
var monitorMenuItem : NSMenuItem?
let prefs = UserDefaults.standard
@@ -30,6 +31,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate, NSMenuItemVa
var unlockedAt = 0.0
var inScreensaver = false
var lastRSSI: Int? = nil
+ var externalDisplayModelOnly = false
func menuWillOpen(_ menu: NSMenu) {
if menu == deviceMenu {
@@ -66,6 +68,8 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate, NSMenuItemVa
item.state = .off
}
}
+ } else if menu == externalDisplayMenu {
+ updateExternalMonitor()
}
}
@@ -277,6 +281,60 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate, NSMenuItemVa
return false
}
+ func getDisplayUUIDs() -> [(localizedName: String, uuidString: String)] {
+ var displayInfoArray: [(localizedName: String, uuidString: String)] = []
+
+ let screens = NSScreen.screens
+ for screen in screens {
+ let deviceDescription = screen.deviceDescription
+ if let screenNumber = deviceDescription[NSDeviceDescriptionKey("NSScreenNumber")] as? CGDirectDisplayID {
+ let uuidRef = CGDisplayCreateUUIDFromDisplayID(screenNumber)?.takeRetainedValue()
+ if let uuidRef = uuidRef {
+ let uuidString = CFUUIDCreateString(kCFAllocatorDefault, uuidRef) as String
+ if #available(macOS 10.15, *) {
+ displayInfoArray.append((localizedName: screen.localizedName, uuidString: uuidString))
+ } else {
+ displayInfoArray.append((localizedName: uuidString, uuidString: uuidString))
+ }
+ }
+ }
+ }
+ return displayInfoArray
+ }
+
+ func updateExternalMonitor() {
+ externalDisplayMenu.removeAllItems()
+ let selectedDisplayUUIDs = prefs.array(forKey: "externalDisplays") as? [String] ?? []
+ let displays = getDisplayUUIDs()
+
+ for display in displays {
+ let menuItem = NSMenuItem(title: display.localizedName, action: nil, keyEquivalent: "")
+ menuItem.representedObject = display.uuidString
+
+ if display.localizedName.contains("Built-in") {
+ menuItem.isEnabled = false
+ } else {
+ menuItem.action = #selector(setExternalDisplays(_:))
+ menuItem.target = self
+ menuItem.state = selectedDisplayUUIDs.contains(display.uuidString) ? .on : .off
+ }
+
+ externalDisplayMenu.addItem(menuItem)
+ }
+ }
+
+ func isExternalDisplayConnected() -> Bool {
+ let selectedDisplayUUIDs = prefs.array(forKey: "externalDisplays") as? [String] ?? []
+
+ if selectedDisplayUUIDs.isEmpty {
+ return false
+ }
+
+ let connectedDisplayUUIDs = getDisplayUUIDs().map { $0.uuidString }
+
+ return selectedDisplayUUIDs.allSatisfy { connectedDisplayUUIDs.contains($0) }
+ }
+
func tryUnlockScreen() {
guard !manualLock else { return }
guard ble.presence else { return }
@@ -291,6 +349,11 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate, NSMenuItemVa
CGEvent(keyboardEventSource: src, virtualKey: 0x35, keyDown: true)?.post(tap: .cghidEventTap)
CGEvent(keyboardEventSource: src, virtualKey: 0x35, keyDown: false)?.post(tap: .cghidEventTap)
}
+
+ if self.prefs.bool(forKey: "externalDisplayModelOnly") && !isExternalDisplayConnected() {
+ print("External Display is not connected")
+ return
+ }
guard !self.prefs.bool(forKey: "wakeWithoutUnlocking") else { return }
@@ -489,6 +552,12 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate, NSMenuItemVa
menuItem.state = value ? .on : .off
prefs.set(value, forKey: "wakeOnProximity")
}
+
+ @objc func toggleExternalDisplayModeOnly(_ menuItem: NSMenuItem) {
+ let value = !prefs.bool(forKey: "externalDisplayModelOnly")
+ menuItem.state = value ? .on : .off
+ prefs.set(value, forKey: "externalDisplayModelOnly")
+ }
@objc func setLockRSSI(_ menuItem: NSMenuItem) {
let value = menuItem.tag
@@ -551,6 +620,20 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate, NSMenuItemVa
prefs.set(wakeWithoutUnlocking, forKey: "wakeWithoutUnlocking")
menuItem.state = wakeWithoutUnlocking ? .on : .off
}
+
+ @objc func setExternalDisplays(_ menuItem: NSMenuItem) {
+ guard let uuidString = menuItem.representedObject as? String else { return }
+
+ menuItem.state = (menuItem.state == .on) ? .off : .on
+
+ var selectedDisplayUUIDs = prefs.array(forKey: "externalDisplays") as? [String] ?? []
+ if menuItem.state == .on {
+ selectedDisplayUUIDs.append(uuidString)
+ } else {
+ selectedDisplayUUIDs.removeAll { $0 == uuidString }
+ }
+ prefs.set(selectedDisplayUUIDs, forKey: "externalDisplays")
+ }
@objc func lockNow() {
guard !isScreenLocked() else { return }
@@ -622,6 +705,17 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate, NSMenuItemVa
if prefs.bool(forKey: "wakeOnProximity") {
item.state = .on
}
+
+ mainMenu.addItem(NSMenuItem.separator())
+ item = mainMenu.addItem(withTitle: t("external_display_mode_only"), action: #selector(toggleExternalDisplayModeOnly), keyEquivalent: "")
+ if prefs.bool(forKey: "externalDisplayModelOnly") {
+ item.state = .on
+ }
+
+ item = mainMenu.addItem(withTitle: t("external_displays"), action: nil, keyEquivalent: "")
+ item.submenu = externalDisplayMenu
+ externalDisplayMenu.delegate = self
+ mainMenu.addItem(NSMenuItem.separator())
item = mainMenu.addItem(withTitle: t("wake_without_unlocking"), action: #selector(toggleWakeWithoutUnlocking), keyEquivalent: "")
if prefs.bool(forKey: "wakeWithoutUnlocking") {
diff --git a/BLEUnlock/Base.lproj/Localizable.strings b/BLEUnlock/Base.lproj/Localizable.strings
index 4e75488..ff9be37 100644
--- a/BLEUnlock/Base.lproj/Localizable.strings
+++ b/BLEUnlock/Base.lproj/Localizable.strings
@@ -36,3 +36,5 @@
"use_screensaver_to_lock" = "Use Screensaver to Lock";
"wake_on_proximity" = "Wake on Proximity";
"wake_without_unlocking" = "Wake without Unlocking";
+"external_display_mode_only" = "External Display Detection";
+"external_displays" = "External Displays";
diff --git a/BLEUnlock/Info.plist b/BLEUnlock/Info.plist
index a871345..678853a 100644
--- a/BLEUnlock/Info.plist
+++ b/BLEUnlock/Info.plist
@@ -19,7 +19,7 @@
CFBundleShortVersionString
1.12.2
CFBundleVersion
- 796
+ 847
LSApplicationCategoryType
public.app-category.utilities
LSMinimumSystemVersion
diff --git a/BLEUnlock/de.lproj/Localizable.strings b/BLEUnlock/de.lproj/Localizable.strings
index c9d978e..3ed36bb 100644
--- a/BLEUnlock/de.lproj/Localizable.strings
+++ b/BLEUnlock/de.lproj/Localizable.strings
@@ -36,3 +36,5 @@
"use_screensaver_to_lock" = "Den Bildschirmschoner verwenden zum Sperren";
"wake_on_proximity" = "Aufwachen bei Annäherung";
"wake_without_unlocking" = "Aufwachen ohne Entsperren";
+"external_display_mode_only" = "Externer Bildschirm Erkennung";
+"external_displays" = "Externe Bildschirme";