|
| 1 | +Hold Key / Auto-Repeat |
| 2 | +====================== |
| 3 | + |
| 4 | +``type_keyboard`` is an instant down+up and ``input_macro.run_sequence`` can |
| 5 | +hand-roll a press / wait / release, but there was no primitive for "hold this key |
| 6 | +for N seconds" (game movement, hold-to-scroll) or "send it at R presses per |
| 7 | +second" (auto-repeat). |
| 8 | + |
| 9 | +:func:`plan_key_hold` builds the deterministic op-plan (pure, unit-testable); |
| 10 | +:func:`hold_key` dispatches it through an injectable ``sink`` and ``sleep`` so it |
| 11 | +is tested without real input or real waiting. Imports no ``PySide6``. |
| 12 | + |
| 13 | +Headless API |
| 14 | +------------ |
| 15 | + |
| 16 | +.. code-block:: python |
| 17 | +
|
| 18 | + from je_auto_control import hold_key, plan_key_hold |
| 19 | +
|
| 20 | + hold_key("key_d", duration_s=1.5) # press, hold 1.5s, release |
| 21 | + hold_key("key_down", duration_s=2.0, rate_hz=20) # 40 key events @ 50ms |
| 22 | +
|
| 23 | + plan_key_hold("space", 1.0) |
| 24 | + # [{'op': 'press', 'key': 'space'}, |
| 25 | + # {'op': 'wait', 'seconds': 1.0}, |
| 26 | + # {'op': 'release', 'key': 'space'}] |
| 27 | +
|
| 28 | +With ``rate_hz`` unset the key is pressed, held for ``duration_s``, then released. |
| 29 | +With ``rate_hz`` set it is sent as ``round(duration_s * rate_hz)`` discrete key |
| 30 | +events spaced ``1 / rate_hz`` apart — simulated auto-repeat for movement / scroll |
| 31 | +loops. A non-positive duration or rate raises ``ValueError``. ``hold_key`` routes |
| 32 | +the ``wait`` steps to ``sleep`` and the key steps to ``sink``, both injectable. |
| 33 | + |
| 34 | +Executor commands |
| 35 | +----------------- |
| 36 | + |
| 37 | +``AC_hold_key`` takes ``key`` plus ``duration_s`` and an optional ``rate_hz`` and |
| 38 | +returns ``{ops, plan}``. It is exposed as the MCP tool ``ac_hold_key`` and as a |
| 39 | +Script Builder command under **Keyboard**. |
0 commit comments