OSX:检查屏幕是否被锁定

Lev*_*evB 19 macos shell applescript

有没有办法检查屏幕是否被锁定在shell或applescript中?不只是检查屏幕保护程序是否正在运行,而是通过节能设置或按⌃⇧⏏(shift+ control+ eject)锁定屏幕.

先感谢您.

aba*_*ert 27

首先,你的问题有点混乱.Shift + Control + Eject和Energy Saver都将屏幕置于睡眠状态,这与锁定屏幕不同.根据您的其他设置,这可能还需要锁定屏幕,但这是一个单独的问题.IIRC,在Lion上,默认情况下,任何人都不会锁定屏幕 - 但是如果你让屏幕睡眠的时间超过安全和隐私中设置的时间,那么它将锁定它.

无论如何,API CGSessionCopyCurrentDictionary允许您为GUI会话获取有关屏幕睡眠和屏幕锁定的信息.如果您没有GUI会话(例如,因为您在ssh shell中运行),或者您的会话不拥有控制台(例如,因为有人快速用户切换您),您就赢了能够获得此信息,但您至少能够检测到这些情况.

这是我所知道的唯一适用于所有操作系统的机制,从10.5(实际上是10.3)到10.8(但这并不意味着它是唯一实际存在的......).

没有直接的方法可以从bash或AppleScript中调用它.但是,您可以使用自己喜欢的桥(PyObjC,MacRuby,ASOC等)间接调用它.以下是使用Python的示例:

#!/usr/bin/python
import Quartz
d = Quartz.CGSessionCopyCurrentDictionary()
print d
Run Code Online (Sandbox Code Playgroud)

以下是解释响应的方法:

  • 如果什么都没有,那么你就没有UI会话.
  • 如果字典具有kCGSSessionOnConsoleKey= 0或不存在,则您的GUI会话不拥有控制台,或者控制台的屏幕处于睡眠状态.
  • 如果字典有CGSSessionScreenIsLocked= 1,则屏幕被锁定.

一个问题kCGSSessionOnConsoleKey是0(或缺失)并且CGSSessionScreenIsLocked是1.在这种情况下,要么你让屏幕进入睡眠并锁定它们,要么是其他人已经拿走了控制台并锁定了屏幕(有或没有放置它们)睡觉).而且我不确定是否有办法区分这些情况.但是,如果您正在寻找"不要尝试显示对话框,因为用户必须首先解锁屏幕",这两种情况都意味着"不显示对话框".

所以,这应该给你你想要的东西:

#!/usr/bin/python
import sys
import Quartz
d=Quartz.CGSessionCopyCurrentDictionary()
sys.exit(d and 
         d.get("CGSSessionScreenIsLocked", 0) == 0 and 
         d.get("kCGSSessionOnConsoleKey", 0) == 1)
Run Code Online (Sandbox Code Playgroud)

或者,将其转换为单行,您可以直接放入shell脚本:

python -c 'import sys,Quartz; d=Quartz.CGSessionCopyCurrentDictionary(); sys.exit(d and d.get("CGSSessionScreenIsLocked", 0) == 0 and d.get("kCGSSessionOnConsoleKey", 0) == 1)'
Run Code Online (Sandbox Code Playgroud)

现在,如果您已经进入Mac,并且您当前登录到Mac的GUI控制台(作为同一个用户),该怎么办?在这种情况下,您的ssh登录会话可以与控制台登录会话进行通信,其方式与本地终端登录会话完全相同.因此,CGSessionCopyCurrentDictionary将获得相同的值.

调解该连接的引导服务器将应用一些限制(例如,security authorize -u foo应该从终端工作但不能通过ssh工作),但那些没有完整记录,并且从版本更改为版本,因此可能不是您想要依赖的东西.相反,您希望实际读取您的登录会话信息

如果您想进一步了解这一点,请从阅读多用户环境编程主题开始.但是有些信息并没有真正记录在任何地方(例如,引用的Mach级会话SessionGetInfo和引用的BSD级会话utmpx如何捆绑在一起).许多相关工具和库都是开源的,这可能会有所帮助.即使阅读所有内容并没有告诉你如何做你想要的,它会告诉你你想要什么,以及用于搜索和提问的正确术语,这可能已经足够了.

  • 这非常棒,感谢分享.我在这里写了一个js-ctypes版本:https://gist.github.com/Noitidart/ff19ae88500a649c1ef9可以从firefox运行,打开暂存器设置环境到浏览器并运行它.在浏览器控制台中查看输出 我发现的问题是:如果启用了锁定,无论需要密码的延迟是什么,一旦屏幕保护程序显示,CGSSessionScreenIsLocked的值为1.我在需要密码之前有60秒的延迟,无论如何都有得到准确的价值?就像屏幕保护程序正在运行而不是60秒,它应该报告0/false? (2认同)

Joe*_*ner 20

@LevB 的答案很好,但随着macOS 中Python“弃用”的出现(截至 Big Sur尚未看到其删除),我想知道是否还有其他方法可以获取CGSSessionScreenIsLocked,Applecare Enterprise 支持向我指出了ioreg这些 CoreGraphics 的位置会话值也已生效

下面是几个 shell 函数单行代码,在 shell 风格中,它们在肯定(成功)时返回零 (0),在否定时返回非零 (1),因此可以在语句中按预期使用它们if

function screenIsLocked { [ "$(/usr/libexec/PlistBuddy -c "print :IOConsoleUsers:0:CGSSessionScreenIsLocked" /dev/stdin 2>/dev/null <<< "$(ioreg -n Root -d1 -a)")" = "true" ] && return 0 || return 1; }
function screenIsUnlocked { [ "$(/usr/libexec/PlistBuddy -c "print :IOConsoleUsers:0:CGSSessionScreenIsLocked" /dev/stdin 2>/dev/null <<< "$(ioreg -n Root -d1 -a)")" != "true" ] && return 0 || return 1; }
Run Code Online (Sandbox Code Playgroud)

请注意,这些键在屏幕锁定时存在:kCGSSessionSecureInputPIDCGSSessionScreenLockedTimeCGSSessionScreenIsLocked。当屏幕解锁时CGSSessionScreenIsLocked存在,因此!= "true"比较,因为它永远不会"false"

示例用法(因为if有时无法实现评估退出代码的简单性):

#!/bin/sh

function screenIsLocked { [ "$(/usr/libexec/PlistBuddy -c "print :IOConsoleUsers:0:CGSSessionScreenIsLocked" /dev/stdin 2>/dev/null <<< "$(ioreg -n Root -d1 -a)")" = "true" ] && return 0 || return 1; }
function screenIsUnlocked { [ "$(/usr/libexec/PlistBuddy -c "print :IOConsoleUsers:0:CGSSessionScreenIsLocked" /dev/stdin 2>/dev/null <<< "$(ioreg -n Root -d1 -a)")" != "true" ] && return 0 || return 1; }

if screenIsLocked; then
    echo "Screen locked"
fi

if screenIsUnlocked; then
    echo "Screen unlocked"
fi

if ! screenIsLocked; then
    echo "Screen unlocked (inverse logic)"
fi

if ! screenIsUnlocked; then
    echo "Screen locked (inverse logic)"
fi
Run Code Online (Sandbox Code Playgroud)