Заблокировать экран api в mac os X

Есть ли Api, который может блокировать экран как меню, которое вы можете добавить из настроек привязки ключей?

Ответ 1

Он официально не документирован и использует частный API, но следующее работает на MacOS 10.10 (и, возможно, также на более ранних системах):

// lockscreen.c
extern void SACLockScreenImmediate ( );

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

Построить с помощью:

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

Теперь вызов ./lockscreen немедленно заблокирует экран, независимо от того, что пользователь настроил в своих настройках безопасности (блокировка заставки/системного сна) и без регистрации пользователя. Это функция, которую система использует внутри для ведения журнала экрана.

Я настоятельно рекомендую использовать его, он может разорвать ваше приложение, и я даже не уверен, что его правильно назову (возможно, ему нужны аргументы, возможно, оно имеет возвращаемое значение), поэтому может даже сломать всю вашу систему (временно - перезагрузка все исправит), кто знает. Я просто хотел опубликовать это где-то для документации. Возможно, кто-то с лучшими навыками хакера может проанализировать этот вызов еще немного.

Ответ 2

Чтобы заблокировать экран, вызовите:

/System/Library/CoreServices/Menu \ Дополнительно/User.menu/Содержание/Ресурсы/CGSession -suspend

Ответ 3

Если вы действительно хотите сделать то, что делает keychain (т.е. просто заблокировать экран, не заходите в окно входа в систему), это довольно просто:

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

Однако это работает только в том случае, если пользователь "Требовать пароль после сна или заставки" установлен на "немедленно". Но вы можете сразу установить их для них, а затем вернуть обратно к тому, что было, когда вы закончили. Оказывается, что вступление в силу может быть довольно сложным (см. этот ответ для получения дополнительной информации), но это можно сделать. Объедините все это, и у вас есть что-то вроде:

- (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];
}

Ответ 4

Просто ответ 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

Ответ 5

Престон прав, я использую следующий метод, и он работает как прелесть:

- (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");
} 

Ответ 6

Я не вижу ничего документированного как такового, но в меню используется среда ScreenSaver, которая определяет это:

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

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

@end

Ответ 7

Следующий код делает именно то, что делает элемент меню Keychain, поскольку он просто вызывает это. Раньше я использовал это (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];
}

Ответ 8

Чтобы заблокировать компьютер и показать пароль 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;
}