使用命令行锁定屏幕,就像OS X上的钥匙串访问一样

8
我注意到/System/Library/CoreServices/Menu\ Extras/User.menu/Contents/Resources/CGSession -suspend和钥匙串访问的锁屏(打开其首选项,勾选“在菜单栏中显示钥匙串状态”,然后从状态栏图标中点击锁屏)具有不同的功能。是否有办法通过Terminal.app或Cocoa API从命令行运行钥匙串访问的锁屏?
Mac OS 10.9。谢谢!
3个回答

10

我刚刚找到了解决方法:https://apple.stackexchange.com/a/123738/72534

#import <objc/runtime.h>
#import <Foundation/Foundation.h>

int main () {
    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];

    return 0;
}

另存为lockscreen.m,并使用以下方法编译:

Save as lockscreen.m and compile with:
clang -framework Foundation -o lockscreen lockscreen.m

功能完美,因为它只调用了与状态栏图标相同的例程。


1
如果链接失效,那么请发布解决方案的相关部分,否则这个答案将毫无用处。 - Popo
在 Xcode 上,我默认得到了“没有已知的实例方法选择器'_lockScreenMenuHit:'”的错误提示,但是通过编译clang它可以工作! - Nobu
1
这个警告是由于编译器无法确定对象是否实现了名为 '_lockScreenMenuHit:' 的方法而产生的。实际上,如果苹果更改了此包中主类的实现,程序可能会崩溃。我猜在 obj-c 中有一种方法可以在运行时检查方法的存在性,但我只想让示例尽可能简单。 - mrArkwright
谢谢分享!有没有一种方法可以直接从命令行触发它,类似于问题中不太理想的示例?我尝试了/Applications/Utilities/Keychain\ Access.app/Contents/Resources/Keychain.menu/Contents/MacOS/Keychain但是出现了一个错误“无法执行二进制文件”。是否有一个选项或类似解决方案的东西会产生相同的效果?创建一个激活另一个二进制可执行文件部分的二进制可执行文件似乎很复杂。 - Jonathan Whiteley
我不认为这是可能的。Keychain菜单二进制文件包含插件代码,旨在由某些主机应用程序执行(在这种情况下类似于macOS的菜单栏系统)。因此,该二进制文件不包含入口点,不能直接执行。 - mrArkwright
这在10.13上不再起作用,因为MenuExtra已被删除。取而代之的是这个:https://dev59.com/gHI-5IYBdhLWcg3wMFS0#26492632 - Lloeki

0
正如上面所述,“no known instance method for selector '_lockScreenMenuHit:'”错误发生是因为编译器在运行时之前无法确定该方法是否存在于“实例”中。为了解决这个问题,我创建了一个名为“newPrincipalClass”的NSBundle子类,在该类中创建了一个名为-(void)_lockScreenMenuHit:(id)a的实例方法。
修改后的主文件具有以下代码:
#import <objc/runtime.h>
#import <Foundation/Foundation.h>
#import "newPrincipalClass.h"

int main()
{
    NSBundle* bundle =[NSBundle bundleWithPath:@"/Applications/Utilities/Keychain Access.app/Contents/Resources/Keychain.menu"];
    Class newPrincipalClass = [bundle principalClass];
    id instance =[[newPrincipalClass alloc] init];
    [instance _lockScreenMenuHit:NULL];

    return 0
}

所以,我使用我的新子类“newPrincipalClass”创建了“instance”,其中包括一个名为“_lockScreenMenuHit:”的方法。现在,当编译器在“instance”内部检查时,它会找到该方法的名称,因此不会显示任何错误。这样,程序就可以顺利运行了!


0

https://dev59.com/gHI-5IYBdhLWcg3wMFS0#16368803 可能会有用。

本质上:

io_registry_entry_t entry = IORegistryEntryFromPath(kIOMasterPortDefault, "IOService:/IOResources/IODisplayWrangler");

if (entry) {
    IORegistryEntrySetCFProperty(entry, CFSTR("IORequestIdle"), kCFBooleanTrue);
    IOObjectRelease(entry);
}

正如原回答所提到的,该代码会进入睡眠模式,而不是通常会在锁定屏幕时询问您密码的锁定屏幕,除非您已经在“系统偏好设置”中的“安全性与隐私”中取消了“需要密码”的选项。感谢您的评论。 - Nobu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接