24

有什么方法可以检查屏幕是否锁定在 shell 或 applescript 中?不仅检查屏幕保护程序是否正在运行,而且通过节能设置或按⌃⇧⏏</kbd> (shift+control+eject).

先感谢您。

4

3 回答 3

33

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

无论如何,APICGSessionCopyCurrentDictionary允许您为您的 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

以下是解释响应的方法:

  • 如果您一无所获,那么您就没有 UI 会话。
  • 如果字典有kCGSSessionOnConsoleKey= 0 或不存在,则您的 GUI 会话不拥有控制台,或者控制台的屏幕处于休眠状态。
  • 如果字典有CGSSessionScreenIsLocked= 1,则屏幕被锁定。

一个有问题的情况是kCGSSessionOnConsoleKey0(或缺失)和CGSSessionScreenIsLocked1。在这种情况下,要么您已将屏幕置于睡眠状态并锁定它们,要么其他人已使用控制台并锁定屏幕(无论是否放置它们)睡觉)。而且我不确定是否有办法区分这些情况。但是,如果您正在寻找“不要尝试显示对话框,因为用户必须先解锁屏幕”,那么这两种情况都意味着“不显示对话框”。

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

#!/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)

或者,把它变成一个单行,你可以直接放在一个 shell 脚本中:

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

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

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

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

于 2012-07-16T19:43:23.310 回答
8

@LevB 的答案很好,但是随着macOS中 Python“弃用”的出现(截至 Big Sur 还没有看到它被删除)我想知道是否有另一种方法可以得到CGSSessionScreenIsLocked Applecare 企业支持向我指出了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; }

请注意,这些键在屏幕锁定时存在: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
于 2021-03-20T14:55:21.207 回答
0

使用 jdk9,您可以使用

java.awt.Desktop



Desktop tempDesktop = Desktop.getDesktop();
        tempDesktop.addAppEventListener(new UserSessionListener() {

            @Override
            public void userSessionDeactivated(UserSessionEvent aE) {
                LOG.info("Desktop:userSessionDeactivated Reason=" + aE.getReason() + " Source=" + aE.getSource());
                // Windows Key L: 
                // Tue Aug 31 11:22:49 CEST 2021:info:MainController:userSessionDeactivated Reason=LOCK

                // Close Lid:
                // Tue Aug 31 11:24:38 CEST 2021:info:MainController:userSessionDeactivated Reason=LOCK
                // Tue Aug 31 11:24:39 CEST 2021:info:MainController:systemAboutToSleep Source=java.awt.Desktop@741f67cd

                ptcUserStatus = PtcUserStatus.AWAY;

            }

            @Override
            public void userSessionActivated(UserSessionEvent aE) {
                LOG.info("Desktop:userSessionActivated Reason=" + aE.getReason() + " Source=" + aE.getSource());
                // Logon after Windows Key L
                // Tue Aug 31 11:22:53 CEST 2021:info:MainController:userSessionActivated Reason=LOCK

                // Open Lid:
                // Tue Aug 31 11:24:56 CEST 2021:info:MainController:systemAwoke Source=java.awt.Desktop@741f67cd
                // Tue Aug 31 11:25:06 CEST 2021:info:MainController:userSessionActivated Reason=LOCK
                ptcUserStatus = PtcUserStatus.BACK;
            }
        });
于 2021-08-31T18:53:18.390 回答