Would like to disconnect an nic after a minute of user inactivity, where inactivity is defined as no mouse clicks or wheel scrolls. Mouse movement is to be ignored so xscreensaver is not suitable and neither is xautolock. How can mouse events be detected from the command line and differentiated?

  • Find the source code for xwininfo and see how it handles its -events argument. – Andrew Henle Oct 9 at 14:59

Based on meuh's instructions, here is how this "screen saver" was done:

evemu-record /dev/input/event2 |
stdbuf -oL egrep 'EV_KEY|REL_WHEEL' |

Where network_saver.sh is this:

while [ 1 ]
    echo Waiting for $WAIT seconds of mouse button inactivity
    while read -t $WAIT line
        echo -n .
    echo; echo Disabling networking
    nmcli n off
    echo Waiting for a mouse button press
    while read line
        echo -n .
    echo; echo Enabling networking
    nmcli n on
    # Connect the main nic as soon as possible
    nmcli conn up "Ethernet connection 1" >/dev/null

If you don't want to write a program to do this, there are several programs that will show you mouse events. For example, evemu-record on a mouse input device will show each button press, wheel scroll, and movement in a very verbose output such as (shown edited):

E: 0001 0111 0001  # EV_KEY / BTN_RIGHT            1
E: 0000 0000 0000  # ------------ SYN_REPORT (0) ---------- +552ms
E: 0002 0008 -001  # EV_REL / REL_WHEEL            -1
E: 0000 0000 0000  # ------------ SYN_REPORT (0) ---------- +1016ms
E: 0002 0000 0001  # EV_REL / REL_X                1
E: 0002 0001 0003  # EV_REL / REL_Y                3

Run evemu-record with no arguments for it to list the input devices. In my case it was

/dev/input/event5:      Logitech USB Optical Mouse

then you can write a bash shell script such as:

( pid=$BASHPID
  evemu-record /dev/input/event5 |
  stdbuf -oL egrep 'EV_KEY|REL_WHEEL' |
  ( while read -t 5 junk
    do echo -n .
    echo ok
    kill -pipe $pid

This uses egrep to filter out all but the button and wheel lines, using stdbuf to ensure output is not buffered (though your grep may accept the option --line-buffered which does the same). The while loop reads each line and echoes a ".", but if there is no input for 5 seconds (-t 5) the loop stops. Finally, a kill is needed for the pipeline, which will otherwise not end until a new event is detected and the egrep dies with a SIGPIPE. Using kill -pipe sends a SIGPIPE signal, which avoids the error messages you would get from kill -hup. The outer shell (...) is needed to get a process id for the shell ($BASHPID) that will not kill any surrounding shell code.

Alternatively, you can get a stream of PS/2 data from /dev/input/mice, but I don't know the full details of the format. You can see the 3 byte records with

od -v -An -w3 -tx1 /dev/input/mice
  • Having an issue with kill. It ends my calling script which looks like this: – Ulysses_ Oct 10 at 9:32
  • while [ 1 ] do ./wait_for_inactivity.sh echo disconnecting nic ./wait_for_activity.sh echo connecting nic done – Ulysses_ Oct 10 at 9:34
  • What should the wait_for_activity.sh script be so the above works? – Ulysses_ Oct 10 at 10:42
  • Sorry, I didn't test the effect of the kill enough. I've updated my answer. To avoid killing the surrounding shell you need to use $BASHPID to get the right process id, and an extra set of () if including this in an existing script. Note: this only works with bash. – meuh Oct 10 at 12:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.