使用 Bash 防止猫咪干扰屏幕锁

 

我在卧室里有一台电脑。我也养了猫。不幸的是,猫咪和屏幕锁不太相容,尤其是在晚上。准确地说,这更多是显示器电源管理的问题,而不是实际的屏幕锁定。情况是这样的:我运行一个脚本来“晚上关灯”(即,锁定屏幕并强制显示器断电),这效果很好,直到其中一只猫跳到桌子上,导致鼠标移动并重新打开显示器。而且猫咪甚至不必碰到鼠标;桌子的轻微移动就足以引起鼠标的反应。最近,我受够了这种情况,并认为必须有一种方法来禁用鼠标并“重构”脚本。

脚本的初始版本非常简单

qdbus org.kde.screensaver /ScreenSaver Lock
sleep 2
xset +dpms
xset dpms force off

第一行锁定屏幕。第三行确保启用显示器电源管理,最后一行关闭显示器电源。

如果您使用 GNOMEqdbus行可能不起作用,因此请尝试以下方法代替

dbus-send --type=method_call --dest=org.gnome.ScreenSaver \
    /org/gnome/ScreenSaver org.gnome.ScreenSaver.Lock

使用xinput命令(您可能需要安装)来关闭鼠标也很简单

xinput --set-prop "Your-Mouse-Name" "Device Enabled" "0"

稍微棘手的部分是弄清楚“您的鼠标名称”应该使用什么。使用xinput命令再次查找也很简单

$ xinput list
⎡ Virtual core pointer                          id=2    [master pointer  (3)]
⎜   ↳ Virtual core XTEST pointer                id=4    [slave  pointer  (2)]
⎜   ↳ HOLTEK USB-HID Keyboard Mouse             id=10   [slave  pointer  (2)]
⎜   ↳ HOLTEK USB-HID Keyboard Consumer Control  id=12   [slave  pointer  (2)]
⎜   ↳   mini keyboard Mouse                     id=16   [slave  pointer  (2)]
⎜   ↳   mini keyboard Consumer Control          id=18   [slave  pointer  (2)]
⎜   ↳ USB Mouse                                 id=14   [slave  pointer  (2)]
⎣ Virtual core keyboard                         id=3    [master keyboard (2)]
    ↳ Virtual core XTEST keyboard               id=5    [slave  keyboard (3)]
    ↳ Power Button                              id=6    [slave  keyboard (3)]
    ↳ Video Bus                                 id=7    [slave  keyboard (3)]
    ↳ Power Button                              id=8    [slave  keyboard (3)]
    ↳ HOLTEK USB-HID Keyboard                   id=9    [slave  keyboard (3)]
    ↳ HOLTEK USB-HID Keyboard System Control    id=11   [slave  keyboard (3)]
    ↳ HOLTEK USB-HID Keyboard Keyboard          id=13   [slave  keyboard (3)]
    ↳   mini keyboard                           id=15   [slave  keyboard (3)]
    ↳   mini keyboard System Control            id=17   [slave  keyboard (3)]
    ↳ HOLTEK USB-HID Keyboard Consumer Control  id=19   [slave  keyboard (3)]
    ↳   mini keyboard Consumer Control          id=20   [slave  keyboard (3)]

好吧,也许并没有那么简单,因为在我的系统上,有三个东西被命名为“Mouse”。但我知道这不是前两个,因为它们的名称表明它们是键盘的一部分,只剩下通用的“USB Mouse”。

不幸的是,当我在另一个系统上尝试使用不同类型的 USB 鼠标时,鼠标名称并没有显示为“USB Mouse”,而是显示为“Logitech USB Laser Mouse”,这意味着我无法将鼠标名称硬编码到脚本中。在查看这两个列表后,我注意到我想要的鼠标名称始终是“Virtual core keyboard”行之前的名称。诚然,我的假设是基于一个非常小的测试组,但在我看到不同的情况之前,它会起作用。注意:当我写这篇文章时,我突然想到也许我可以只禁用“Virtual core pointer”,这可能是一个“通用”名称,但我还没有尝试过。

因此,通过一些 grepping,我现在可以在任何系统上获取鼠标的名称

mouse_name=$(xinput list --name-only | grep -B 1 'Virtual core keyboard' | head -n 1)

--name-only选项到xinput list消除了所有花哨的箭头和其他额外信息,只输出名称。

-B选项使 grep 输出它找到的任何匹配项的上下文前导行。在这种情况下,除了“Virtual core keyboard”行之外,它还输出它之前的行(这是我想要的行)。然后我使用head来挑选出那一行,这给了我关闭鼠标的名称(在上面的示例中为“USB Mouse”)。

提示:Grep 上下文选项

Grep 的上下文选项有时会非常方便,来自 grep 手册页

-A NUM, --after-context=NUM

打印匹配行之后 NUM 行的后续上下文。在连续的匹配组之间放置包含组分隔符 (--) 的行。使用 -o 或 --only-matching 选项,这不起作用,并且会发出警告。

-B NUM, --before-context=NUM

打印匹配行之前 NUM 行的前导上下文。在连续的匹配组之间放置包含组分隔符 (--) 的行。使用 -o 或 --only-matching 选项,这不起作用,并且会发出警告。

-C NUM, -NUM, --context=NUM

打印 NUM 行的输出上下文。在连续的匹配组之间放置包含组分隔符 (--) 的行。使用 -o 或 --only-matching 选项,这不起作用,并且会发出警告。

整个mouse-on-off脚本如下

#!/bin/bash

function usage()
{
    cat <<EOF
Usage: $0 MOUSE-STATE

MOUSE-STATE:
    on|enable|enabled|1     Enable mouse
    off|disable|disabled|0  Disable mouse
    test|mouse              Display mouse name
EOF
}

if test "$DISPLAY"; then
    mouse_name=$(xinput list --name-only | grep -B 1 'Virtual core keyboard' | head -n 1)

    if [[ "$1" =~ ^(on|enable|enabled|1)$ ]]; then
        xinput --set-prop "$mouse_name" "Device Enabled" "1"
        echo "on"
    elif [[ "$mouse_name"  &&  "$1" =~ ^(off|disable|disabled|0)$ ]]; then
        xinput --set-prop "$mouse_name" "Device Enabled" "0"
        echo "off"
    elif [[ "$1" =~ ^(test|mouse)$ ]]; then
        echo "Mouse name: ${mouse_name}"
    else
        echo "Mouse name: ${mouse_name}" >&2
        usage >&2
    fi
else
    echo "Mouse name: UNKNOWN (No X server ???)"
    if [[ "$1" =~ ^(on|enable|enabled|1|off|disable|disabled|0)$ ]]; then
        echo "on"
    elif [[ "$1" =~ ^(test|mouse)$ ]]; then
        :
    else
        usage >&2
    fi
fi

一些使用示例

$ mouse-on-off mouse      # Show mouse name
Mouse name: USB Mouse
$ mouse-on-off off        # Turn off mouse
off
$ mouse-on-off on         # Turn on mouse
on

出错示例

$ mouse-on-off mouse      # Unable to get mouse name
Mouse name: UNKNOWN (No X server ???)
$ mouse-on-off off        # Unable to turn off mouse
Mouse name: UNKNOWN (No X server ???)
on                        # Mouse is still on

现在我需要做的就是修改原始脚本以使用 mouse-on-off 命令

#!/bin/bash

qdbus org.kde.screensaver /ScreenSaver Lock
sleep 2

mouse=$(mouse-on-off off)

xset +dpms
xset dpms force off

if [[ "$mouse" == 'off' ]]; then
    kdialog --msgbox "Enter to re-enable the mouse"
    mouse-on-off on
fi

mouse=$(mouse-on-off off)调用新命令并捕获其标准输出,标准输出应该是“on”或“off”(错误消息会转到标准错误)。关闭显示器后,假设我能够关闭鼠标,我弹出一个消息框。当我解锁计算机时,我只需按 Enter 键即可关闭迎接我的消息框,并且脚本会重新打开鼠标并退出。以防您想知道,是的,在使用这个脚本的头几天,当我早上摇晃鼠标试图唤醒显示器时,我一直认为鼠标在夜间坏死了 [在此处插入猫/鼠标笑话]。旧习惯很难改掉,但最终还是会改掉的。

Mitch Frazier 是 Emerson Electric Co. 的嵌入式系统程序员。自 2000 年代初期以来,Mitch 一直是 Linux Journal 的贡献者和朋友。

加载 Disqus 评论