How to detect that a user is idle?

I want to make a timer that will NOT execute if the user has been idle for X amount of time.
How do I detect that?

import bpy

def every_2_seconds():
	
	if something_has_changed_in_the_last_10_seconds():
		print("Hello World")
	
    return 2.0

bpy.app.timers.register(every_2_seconds)

How would something_has_changed_in_the_last_10_seconds() work?
I thought about comparing mouse positions, but that seems to be only available to modal operators. Not to mention that mouse position can remain the same, but the user can still be doing something else.
I know about depsgraph, but I don’t really know how to check if there was an update in the last X seconds.

You could both un-register and register a function on depsgraph update to run in 10 seconds. That way every time the depsgraph callback is run, the timer resets. However this won’t take mouse movement into account AFAIK.

IMO this would be more suited on a OS level script rather than in Blender. What exactly is your end goal here ?

2 Likes

I’m making a timelapse script that would render out the camera view and save it to a file, every X seconds. This idle detection is to avoid writing identical frames and wasting drive space when I’m alt-tabbed or not doing anything.

I’m not really sure what you mean with the depsgraph register/unregister.

Hmm, why not just testing the image frame pixels and detect if there is some change between the last saved one and the one in memory ? A user may do something in between two frames with no noticeable impact on the video. eg if I add a cube then delete the cube, your method will write 2 frames where there should be only one ?

Cheers

1 Like

Then depsgraph update might fit - set up every n seconds timer and reset it on depsgraph update. See depsgraph handlers in
https://docs.blender.org/api/current/bpy.app.handlers.html

1 Like

Ok, figured it out. I didn’t realize you could register a timer inside the depsgraph update.

This will keep printing “Hello World”, but only if the depsgraph was updated:

import bpy

def one_time_timer():
    print("Hello World")
    
def depsgraph_update(scene, depsgraph):
    if not bpy.app.timers.is_registered(one_time_timer):
        bpy.app.timers.register(one_time_timer, first_interval=1)
        
bpy.app.handlers.depsgraph_update_post.append(depsgraph_update)

@Gorgious checking the image pixels would probably be too heavy. The script already has to render and write a file every second or so, and all that while I’m doing something intensive with Blender (like sculpting).

3 Likes