在macOS中通过API锁定屏幕

asf*_*fsa 16 macos cocoa

是否有API,可以锁定屏幕作为您可以从Keychain首选项添加的菜单栏条目?

Keychain功能正在锁定屏幕但不会使系统进入睡眠状态.

Mec*_*cki 21

它没有正式记录并使用私有API,但以下适用于MacOS 10.10(也可能在早期系统上):

// lockscreen.c
extern int SACLockScreenImmediate ( void );

int main ( ) {
    return SACLockScreenImmediate();
}
Run Code Online (Sandbox Code Playgroud)

建立:

clang -F /System/Library/PrivateFrameworks -framework login -o lockscreen lockscreen.c 
Run Code Online (Sandbox Code Playgroud)

现在调用./lockscreen将立即锁定屏幕,无论用户在其安全首选项中配置了什么(是否锁定屏幕保护程序/系统睡眠)并且不将用户注销.这是系统内部用于锁定屏幕的功能.

我强烈反对使用它,它可能会破坏你的应用程序,我甚至不确定我是否正确调用它(可能它需要参数,也许它有一个返回值),所以它甚至可能会打破你的整个系统(暂时 - 重启将会修理一切),谁知道.我只是想在某处发布文档.

如果有比我更好的黑客技能的人可以再分析一下这个电话,这将是很好的和有用的.


小智 9

要锁定屏幕,请致电:

/ System/Library/CoreServices/Menu\Extras/User.menu/Contents/Resources/CGSession -suspend


Wil*_*son 9

如果你真的想做钥匙串做的事情(即只是锁定屏幕,不要去登录窗口),这很容易:

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

但是,这仅在用户将"睡眠后需要密码或屏幕保护程序开始"设置为"立即"时才有效.但是,您可以立即将它设置为它们,然后将其设置为完成后的状态.事实证明,生效可能相当棘手(请参阅此答案以获取更多信息),但可以完成.把它们放在一起,你有类似的东西:

- (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];
}
Run Code Online (Sandbox Code Playgroud)


Fra*_* T. 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()
Run Code Online (Sandbox Code Playgroud)

在这里:https: //github.com/ftiff/MenuLock/blob/master/MenuLock/AppDelegate.swift#L126


Aze*_*utt 1

我没有看到任何这样的记录,但菜单使用 ScreenSaver 框架,它定义了这一点:

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

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

@end
Run Code Online (Sandbox Code Playgroud)