2009-12-29 115 views
15

是否有Api,可以將屏幕鎖定爲可從鑰匙串首選項添加的菜單項?在mac os中通過api鎖定屏幕X

+0

我知道有一些東西可用,因爲SizzlingKeys可以做到這一點。不知道什麼類/方法雖然。你應該澄清你是否在尋找一個Cocoa或AppleScript API。 – 2009-12-29 19:46:19

+0

問題標籤爲可可。 – 2009-12-30 08:13:51

+0

是否有類似的代碼來解鎖屏幕(假設代碼「知道」密碼)? – mbaros 2017-07-03 11:33:40

回答

1

我沒有看到任何記錄本身,而是菜單使用屏幕保護程序框架,它定義了這一點:

@interface ScreenSaverDefaults : NSUserDefaults 
{ 
@private 
    NSMutableDictionary  *_defaults; 
    NSMutableDictionary  *_registeredDefaults; 
    NSString    *_userName; 
    NSString    *_domainName; 
    BOOL     _dirty; 
    BOOL     _screenLockPrefChanged; 
} 

+ (id) defaultsForModuleWithName:(NSString *)inModuleName; 

@end 
8

要鎖定屏幕,請致電:

/系統/庫/ CoreServices /菜單\ 其他/ User.menu /內容/資源/ CGSession -suspend

+0

這只是踢我到登錄屏幕。 (不是OP) – seaturtle 2017-11-07 21:04:05

+0

這確實會鎖定屏幕,但也要求您重新輸入您的登錄名(不僅僅是密碼)...(可能是「Preston」的原始答案) – rogerdpack 2017-12-28 19:23:22

3

普雷斯頓是正確的,我用下面的方法,它就像一個魅力:

- (void)lockScreen { 
    NSTask *task; 
    NSArray *arguments = [NSArray arrayWithObject:@"-suspend"]; 

    task = [[NSTask alloc] init]; 
    [task setArguments: arguments]; 
    [task setLaunchPath: @"/System/Library/CoreServices/Menu Extras/User.menu/Contents/Resources/CGSession"]; 
    [task launch]; 
    [task release]; 
    NSLog(@"screen is Locked"); 
} 
+1

您怎麼才能鎖定Mac而不是轉發選擇用戶屏幕(似乎這種方法確實太多了)?謝謝! – Idan 2013-11-26 14:33:17

+0

@Idan在我的答案中的解決方案做你想做的:http://stackoverflow.com/a/26489672/1698467 – skywinder 2014-10-21 14:52:10

8

如果你真的想要做什麼鑰匙串並(即只鎖定屏幕,不用去登錄窗口),這是相當容易:

io_registry_entry_t r = IORegistryEntryFromPath(kIOMasterPortDefault, "IOService:/IOResources/IODisplayWrangler"); 
if (r) { 
    IORegistryEntrySetCFProperty(r, CFSTR("IORequestIdle"), sleep ? kCFBooleanTrue);   
    IOObjectRelease(r); 
} 

但是,這隻適用於用戶在睡眠或屏幕保護程序開始時要求密碼設置爲'立即'的情況。但是,您可以立即爲它們設置它,然後將其設置回完成時的狀態。事實證明,要生效可能會非常棘手(更多信息,請參閱this answer),但可以完成。把它放在一起,你有這樣的:

- (void)lockScreen; 
{ 
    int screenSaverDelayUserSetting = 0; 

    screenSaverDelayUserSetting = [self readScreensaveDelay]; 

    if (screenSaverDelayUserSetting != 0) { 
     // if the delay isn't already 0, temporarily set it to 0 so the screen locks immediately. 
     [self setScreensaverDelay:0]; 
     [self touchSecurityPreferences]; 
    } 

    io_registry_entry_t r = IORegistryEntryFromPath(kIOMasterPortDefault, "IOService:/IOResources/IODisplayWrangler"); 
    if (r) { 
     IORegistryEntrySetCFProperty(r, CFSTR("IORequestIdle"), sleep ? kCFBooleanTrue : kCFBooleanFalse);   
     IOObjectRelease(r); 
    } 

    if (screenSaverDelayUserSetting != 0) { 
     [self setScreensaverDelay:screenSaverDelayUserSetting]; 
     [self launchAndQuitSecurityPreferences]; 
    } 
} 

- (void)touchSecurityPreferences; 
{ 
    // necessary for screen saver setting changes to take effect on file-vault-enabled systems 
    // NOTE: this *only* works when going from non-zero settings of askForPasswordDelay to zero. 

    NSAppleScript *kickSecurityPreferencesScript = [[[NSAppleScript alloc] initWithSource: @"tell application \"System Events\" to tell security preferences to set require password to wake to true"] autorelease]; 
    [kickSecurityPreferencesScript executeAndReturnError:nil]; 
} 

- (void)launchAndQuitSecurityPreferences; 
{ 
    // necessary for screen saver setting changes to take effect on file-vault-enabled systems when going from a askForPasswordDelay setting of zero to a non-zero setting 
    NSAppleScript *kickSecurityPreferencesScript = [[[NSAppleScript alloc] initWithSource: 
                @"tell application \"System Preferences\"\n" 
                @"  tell anchor \"General\" of pane \"com.apple.preference.security\" to reveal\n" 
                @"  activate\n" 
                @"end tell\n" 
                @"delay 0\n" 
                @"tell application \"System Preferences\" to quit"] autorelease]; 
    [kickSecurityPreferencesScript executeAndReturnError:nil]; 
} 

- (int)readScreensaveDelay; 
{ 
    NSArray *arguments = @[@"read",@"com.apple.screensaver",@"askForPasswordDelay"]; 

    NSTask *readDelayTask = [[[NSTask alloc] init] autorelease]; 
    [readDelayTask setArguments:arguments]; 
    [readDelayTask setLaunchPath: @"/usr/bin/defaults"]; 

    NSPipe *pipe = [NSPipe pipe]; 
    [readDelayTask setStandardOutput:pipe]; 
    NSFileHandle *file = [pipe fileHandleForReading]; 
    [readDelayTask launch]; 
    NSData *resultData = [file readDataToEndOfFile]; 
    NSString *resultString = [[NSString alloc] initWithData:resultData encoding:NSUTF8StringEncoding]; 
    return resultString.intValue; 
} 

- (void)setScreensaverDelay:(int)delay; 
{ 
    NSArray *arguments = @[@"write",@"com.apple.screensaver",@"askForPasswordDelay", [NSString stringWithFormat:@"%i", delay]]; 
    NSTask *resetDelayTask = [[[NSTask alloc] init] autorelease]; 
    [resetDelayTask setArguments:arguments]; 
    [resetDelayTask setLaunchPath: @"/usr/bin/defaults"]; 
    [resetDelayTask launch]; 
} 
+0

產生另一個進程只是運行/ usr/bin/defaults似乎非常過分和嚴厲。您是否有理由避免使用CFPreferences API? – Draxillion 2014-03-05 19:40:30

+0

不幸的是閱讀屏幕保護程序延遲將不會在10.13上工作。 – 2018-01-02 11:15:05

0

要鎖定計算機,並顯示最近的用戶密碼PROMT您可以使用此代碼:

- (void)lockScreen 
{ 
    MDSendAppleEventToSystemProcess(kAESleep); 
} 

OSStatus MDSendAppleEventToSystemProcess(AEEventID eventToSendID) 
{ 
    AEAddressDesc     targetDesc; 
    static const ProcessSerialNumber kPSNOfSystemProcess = {0, kSystemProcess}; 
    AppleEvent      eventReply   = {typeNull, NULL}; 
    AppleEvent      eventToSend   = {typeNull, NULL}; 

    OSStatus status = AECreateDesc(typeProcessSerialNumber, 
      &kPSNOfSystemProcess, sizeof(kPSNOfSystemProcess), &targetDesc); 

    if (status != noErr) return status; 

    status = AECreateAppleEvent(kCoreEventClass, eventToSendID, 
      &targetDesc, kAutoGenerateReturnID, kAnyTransactionID, &eventToSend); 

    AEDisposeDesc(&targetDesc); 

    if (status != noErr) return status; 

    status = AESendMessage(&eventToSend, &eventReply, 
      kAENormalPriority, kAEDefaultTimeout); 

    AEDisposeDesc(&eventToSend); 
    if (status != noErr) return status; 
    AEDisposeDesc(&eventReply); 
    return status; 
} 
+0

這使系統進入睡眠狀態,kAESleep。鎖屏只是一個副作用。 – 2015-02-13 22:36:33

16

這不是正式文件,並使用私有API,但在Mac OS 10.10(也許還更早的系統)以下工作:

// lockscreen.c 
extern void SACLockScreenImmediate (); 

int main() 
{ 
    SACLockScreenImmediate(); 
    return 0; 
} 

建設有:

clang -F /System/Library/PrivateFrameworks -framework login -o lockscreen lockscreen.c 

現在調用./lockscreen將立即鎖定屏幕,無論用戶在其安全首選項中配置了什麼(是否鎖定屏幕保護程序/系統休眠)並且無需登錄用戶。這是系統內部用於記錄屏幕的功能。我很強烈地不鼓勵使用它,它可能會破壞你的應用程序,我甚至不確定我是否正確地調用它(也許它需要參數,也許它有一個返回值),所以它甚至可能會破壞你的整個系統(暫時 - 重啓將修復一切),誰知道。我只是想在某個地方發佈文檔。也許有更好的黑客技能的人可以再分析一下這個電話。

+0

int _SACLockScreenImmediate(){ rax = * _kLFDBFlag_SA_ScreenSaver; ((*(_(gDBLoggingMasks +(rax >> 0x3c)* 0x8)&rax)!= 0x0)rbx = CFStringCreateWithFormat(* _kCFAllocatorDefault,0x0,@「%s:enter」); DBLoggingLogWithFormat(* _ kLFDBFlag_SA_ScreenSaver,@「%s:%d:%@」,「SACLockScreenImmediate」,0x1fe,rbx); CFRelease(rbx); } rbx = _CreateArgumentsForFunction(@「SACLockScreenImmediate」,0x0); \t .... return rax; } – slboat 2015-12-19 03:38:28

+0

它工作的很好,它沒有參數,但有一個返回值 – slboat 2015-12-19 03:38:47

+0

在High Sierra FWIW中工作得很好。 – rogerdpack 2017-12-28 19:24:28

5

只是沒有使用SWIFT Mecki的回答是:

let libHandle = dlopen("/System/Library/PrivateFrameworks/login.framework/Versions/Current/login", RTLD_LAZY) 
    let sym = dlsym(libHandle, "SACLockScreenImmediate") 
    typealias myFunction = @convention(c) Void -> Void 
    let SACLockScreenImmediate = unsafeBitCast(sym, myFunction.self) 
    SACLockScreenImmediate() 

在這裏: https://github.com/ftiff/MenuLock/blob/master/MenuLock/AppDelegate.swift#L126

1

下面的代碼不準確鑰匙扣菜單項做什麼,因爲它只是調用。我曾經使用過這個(在10.11和10.12),但是現在在10.13(公共測試版)上失敗了,因爲根本沒有Keychain.menu也沒有菜單項。Mecki的答案是一個可用的替代品,但不會淡出屏幕,因此它的確是低級別的。

void lock() { 
    NSBundle *bundle = [NSBundle bundleWithPath:@"/Applications/Utilities/Keychain Access.app/Contents/Resources/Keychain.menu"]; 
    Class principalClass = [bundle principalClass]; 
    id instance = [[principalClass alloc] init]; 
    [instance performSelector:@selector(_lockScreenMenuHit:) withObject:nil]; 
} 
+0

是的,不在這裏工作(高塞拉利昂) – rogerdpack 2017-12-28 19:28:45