2009-12-29 72 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