How can a script detect a user's idle time?
I want to check, inside a bash script, how long the user of a X session has been idle.
The user himself does not have to be using bash, but just X. If the user just moved the mouse, for example, a good answer would be "idle for 0 seconds". If he has not touched the computer in 5 minutes, a good answer would be "idle for 300 seconds"
The reason to not use xautolock straight away is to be able to implement some complex behavior. For example, if the user is idle for 10 minutes, try to suspend, if he is idle for more 5 minutes, shutoff (I know it sounds odd, but suspend does not always work here ...)
Solution 1:
Just found a simple way to do it.
There is a program called xprintidle that does the trick
getting the idle time (in milliseconds) is as simple as
xprintidle
and to install
apt-get install xprintidle
For sysadmins, it also works remotely
From an ssh session:
export DISPLAY=:0 && sudo -u john xprintidle
where john is the user logged into the X session on the remote machine.
Note that some programs such as MPlayer seem to reset the counter.
That might be desirable or not depending on your application. For me I meant to use it to suspend the computer and the MPlayer exception is helpful.
There is another answer (https://askubuntu.com/a/1303464/56440) for those who want no resetting, but I haven't personally tested it
Solution 2:
Using the answer by josinalvo might work for some, but it didn't quite work so well for me as some programs seem to be regularly resetting the timer, on which xprintidle
relies, unexpectedly. In addition, I also would not want a fullscreen application to reset the idle timer, at least not in my use case.
So I've strung together my own solution in a shell script which doesn't rely on the X11 Screen Saver extension. Instead it dumps all user input like mouse movement and key presses using xinput test-xi2 --root
for one second and then compares it with a dump from the last second. If they are the same, the variable $t
gets increased by 1 and gets reset in the other case. This is looped and when variable $t
gets over the treshold in $idletime
, it is printed that the user is idle.
idleloop() {
touch /tmp/.{,last_}input
cmd='stat --printf="%s"'
idletime=120
a=2
t=0
while true
do
timeout 1 xinput test-xi2 --root > /tmp/.input
if [[ `eval $cmd /tmp/.input` == `eval $cmd /tmp/.last_input` ]]
then
let t++ # increases $t by 1
else
t=0 # resets $t
fi
mv /tmp/.{,last_}input -f
if [ $t -ge $idletime ] && [[ $a == "2" ]]
then
echo "user has gone idle"
a=1
fi
if [ $t -lt $idletime ] && [[ $a == "1" ]]
then
echo "user has come back from idle"
a=2
fi
done
}
idleloop
Feel free to leave any suggestions.
Solution 3:
Answer from here:
In bash
w | tr -s " " | cut -d" " -f1,5 | tail -n+3
gives you a username/idletime pair for each shell. So basically you can get the idle information through the command w