I have a computer in my bedroom. I also have cats. Unfortunately, cats and screen lockers don't mix well, particularly at night. To be accurate, it's more a problem with the display power management than the actual screen locking. Here's the way it works: I run a script to "shut the lights off at night" (that is, lock the screen and force the display to power down), and that works great, until one of the cats jumps on the desk and causes the mouse to move and turn the display back on. And the cats don't even have to touch the mouse; the slight movement of the desk is enough to cause the mouse to react. Recently, I'd had enough of it and figured there had to be a way to disable the mouse and "refactor" the script.

The initial version of the script is pretty simple:

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

The first line locks the screen. The third line makes sure that display power management is enabled, and the last line powers down the display.

If you use GNOME, the qdbus line may not work, so try the following instead:

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

Turning off the mouse is also simple to do using the xinput command (which you may need to install):

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

The somewhat tricky part is figuring out what to use for "Your-Mouse-Name". This too is fairly straightforward using the xinput command again:

$ 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)]

Okay, maybe it's not that straightforward, since on my system there are three things that are named "Mouse". But I knew that it wasn't the first two, since their names gave them away as being part of the keyboard, leaving me with just the universal-sounding "USB Mouse".

Unfortunately, when I tried this on another system with a different type of USB mouse, the mouse name did not show up as just "USB Mouse", it came up as "Logitech USB Laser Mouse", which meant I the couldn't hard-code the mouse name into the script. After looking at the two lists a bit, I noticed that the mouse name that I wanted was always the name right before the "Virtual core keyboard" line. Admittedly, my assumption is based on a pretty small test group, but until I see something different, it'll work. Note: as I write this, it occurs to me that maybe I could have just disabled the "Virtual core pointer", which likely is a "universal" name, but I haven't tried that yet.

So with a bit of grepping, I can now get the name of the mouse on any system:

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

The --name-only option to xinput list eliminates all the fancy arrows and the other extra information and just outputs names.

The -B option to grep causes grep to output preceding lines of context for any matches that it finds. In this case, in addition to the "Virtual core keyboard" line, it outputs the line right before it (which is the one I want). Then I use head to pick off that line, and that gives me the name of the mouse to shut off ("USB Mouse" in the example above).

Tip: Grep Context Options Grep's context options can come in quite handy sometimes, from the grep man page: -A NUM, --after-context=NUM Print NUM lines of trailing context after matching lines. Places a line containing a group separator (--) between contiguous groups of matches. With the -o or --only-matching option, this has no effect and a warning is given. -B NUM, --before-context=NUM Print NUM lines of leading context before matching lines. Places a line containing a group separator (--) between contiguous groups of matches. With the -o or --only-matching option, this has no effect and a warning is given. -C NUM, -NUM, --context=NUM Print NUM lines of output context. Places a line containing a group separator (--) between contiguous groups of matches. With the -o or --only-matching option, this has no effect and a warning is given.

The entire mouse-on-off script follows:

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

Some examples of using it:

$ 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

Examples of things going wrong:

$ 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

Now all I need to do is modify the original script to use the mouse-on-off command:

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