git.lucas.co / hou-control
SideFX Houdini customization package
git clone https://git.lucas.co/hou-control.git

python3.13libs/hc/hcleader.py (1.4K)

 1 import time
 2 
 3 from . import hcstate
 4 
 5 
 6 _TIMEOUT = 1.0
 7 _pending = hcstate.Store("leader_chord", hcstate.PANE)
 8 
 9 
10 def chord(editor, action_fn):
11     """Vim-style leader chord. Returns True if action was executed, False if
12     this was the first keypress (leader registered, waiting for second).
13 
14     ``editor`` is a ``hou.NetworkEditor`` (or any ``hou.PaneTab``).
15     Houdini creates fresh Python wrappers each time a script fires, so
16     ``id()`` is unreliable and the wrapper itself must not be kept: holding
17     one past the current callback leaves a dangling SWIG pointer, and reading
18     it later segfaults Houdini. ``name()`` is a plain string that stays stable
19     across those wrappers, so that is what gets stored.
20 
21     Nothing here may touch HOM off the main thread. An earlier version
22     expired entries from a ``threading.Timer``, whose callback compared the
23     stored ``hou.PaneTab`` keys from a background thread -- HOM is not
24     thread-safe, and that crashed Houdini with SIGSEGV inside SWIG's ``__eq__``.
25     The elapsed-time check below already ignores a stale entry, so no timer is
26     needed: a leftover entry is harmless and the next keypress overwrites it."""
27     now = time.monotonic()
28     old_ts = _pending.get(editor)
29 
30     if old_ts and (now - old_ts) < _TIMEOUT:
31         _pending.pop(editor)
32         action_fn()
33         return True
34 
35     _pending.set(editor, now)
36     return False