Есть ли Api, который может блокировать экран как меню, которое вы можете добавить из настроек привязки ключей?
Заблокировать экран api в mac os X
Ответ 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;
}