Repository navigation
Add keyboard input from the focused visualizer window - #8158
Conversation
d78dfca to
a82dd1e
Compare
|
run-ci |
|
There was a problem hiding this comment.
Isaac Lab Review Bot
Needs attention: Scope and over-engineering (2), Implementation (3), Style consistency (2), Test quality (2). Other reviewed categories look good.
- PR description: The body falsely claims a Viser implementation although the diff and capability table return
None; remove that claim and the emptyFixes #, then list focused validation commands. - Design and architecture: Architecture looks good.
- Scope and over-engineering: Minimal implementation: extend BaseVisualizer, KitVisualizer, and NewtonVisualizer; keep key_event_source.py, keep kit_key_event_source.py but inline its one-use
_kit()wrapper, and keep newton_key_event_source.py for pyglet mapping and capture. Delete both redundant_key_input_closedflags; retain lazy creation, backend hooks, event delivery, and visualizer-owned cleanup. Scope is cohesive; no split recommended. - API: API changes look good.
- Compatibility and deprecation: No breaking changes identified.
- Implementation: Backend cleanup is not failure-safe: Kit can remain marked listening after losing hooks, and Newton can retain its frame callback after unhook failure; preserve consistent state and clear callbacks during release.
- Style consistency: The new property and capabilities declaration violate required class organization: move properties before public methods and annotate backend-shared
capabilitieswithClassVar[KeyboardCapabilities]. - Test quality: The added suites cover distinct lifecycle and backend behavior, but capability-literal assertions and mirrored shift-order rows duplicate stronger behavioral coverage; remove those cases.
Minor fixes needed. Posted 9 inline findings.
Automated review; human maintainers own approval decisions.
a82dd1e to
5811c22
Compare
5811c22 to
773a726
Compare
|
run-ci |
773a726 to
1c1d547
Compare
|
The goal makes sense, but I’m concerned about how much responsibility is going into Could we first connect this to I’d expect the ownership to be roughly:
The shared source may need some bookkeeping to deliver reliable events, and focus-loss handling is important. But which actual callers need subscription/cleanup from different threads and multiple independent keyboard capture handles? Would requiring operations on the visualizer thread and providing a simple camera-keyboard toggle cover the current use case? I’d like us to validate those boundaries with one real controller before committing to the larger public API. |
Thanks Octi, agreed on validating against a real controller. There is one: the follow-up branch The ownership you describe matches how that branch splits it:
On your questions, the real caller doesn't need everything this PR provides:
That reduces the public API to |
|
Yes, that matches what I had in mind. Thanks for clarifying. Let's simplify this PR as you described: keep key/focus events and a closable subscription, remove the locks and per-listener held-key tracking, and replace capture handles with a camera-keyboard toggle. Please open the controller integration as a follow-up draft PR so we can review both together. That should make the ownership much clearer. |
1c1d547 to
3699be9
Compare
BaseVisualizer.key_event_source exposes keys typed into a visualizer's own window, or None when it has none. A KeyEventSource reports each press and release as a W3C KeyboardEvent.code string, plus a focus loss when the window stops delivering keys (blur, the visualizer's UI taking the keyboard, or close). add_key_listener returns a KeyboardSubscription, an idempotent handle the caller closes. Events are forwarded as the window reports them, so a listener tracks the keys it holds. Subscribing, closing and callbacks all happen on the thread that steps the visualizer. Closing the source is terminal: every listener gets one final focus loss. BaseVisualizer.set_camera_keys_enabled lets a keyboard consumer turn off the visualizer's keyboard camera movement while it uses those keys; it does nothing by default.
KitVisualizer reports physical keys from the Kit app window and a focus loss on window blur. Kit has no Python query for UI keyboard ownership, so keys typed into its UI are reported too. Its viewport camera keys only act while the right mouse button is held, so it keeps the default set_camera_keys_enabled. NewtonGLVisualizer and NewtonRTXVisualizer report layout-mapped keys from their shared pyglet viewer window. They withhold presses typed into its ImGui widgets, checking ImGui's keyboard ownership after every frame. set_camera_keys_enabled(False) stops the window's WASD/QE and arrow-key camera movement, including for a window opened later. Each visualizer closes its keyboard source first in its teardown, while the window is still open, and finishes that teardown when the source fails to close. Headless runs and the Viser and Rerun visualizers have no keyboard source.
3699be9 to
d4fb5e8
Compare
|
run-ci |
Kit and Newton visualizers now connect keyboard input when their window initializes. Keyboard input is optional, so a failure there is logged and key_event_source stays None instead of stopping the visualizer from starting.
Keep the deleted helper out of the direct rendering test architecture and check keyboard availability in the existing scene test. Preserve all production changes from the author branch, including optional keyboard initialization.
|
run-ci |
|
run-ci |
…ure (#8797) Keyboard, gamepad and SpaceMouse input now has one implementation in Isaac Capture. The six old SE(2)/SE(3) implementation classes, their SpaceMouse HID helpers, and the unused `hidapi` dependency are removed. The old config classes remain as data records deprecated in Isaac Lab 3.2: `select_teleop_cfg` translates them once into Isaac Capture configs before launch, preserving sensitivities, dead zones, gripper settings, activation and output device. There are no constructor adapters or automatic fallbacks for these devices. Other device types, including native OpenXR hand tracking, retain their own implementation and factory. All repository callers move in this PR so removing the implementations leaves a working tree. `teleop_se3_agent.py`, `record_demos.py`, consolidated Mimic, pick-and-place and the manual keyboard check use Isaac Capture builders directly for their defaults. Replay and annotation use the visualizers' `add_key_callbacks` for hotkeys without starting a teleop session. Isaac Capture consumers receive their windows explicitly and close the device before the environment. The demo loops handle startup and pause; consolidated Mimic consumes the flat action directly and holds the gripper state while motion is paused. The SO-101 stacking pipeline also uses the Isaac Capture 1.7 clutch API: the retired fixed orientation offset is removed, and the SDK owns engage-relative orientation seeded from the existing home transform. Its integration test executes real controller snapshots through the graph and checks numeric pose/gripper ordering, release/re-engage and reset. The six public pipeline builders remain in one flat `device_pipelines.py`, with shared action packing only where required. This builds on merged #8158 and requires Isaac Capture 1.7 through the Linux teleop extra. It incorporates the remaining-caller migration previously planned for #8798; that follow-up overlaps this change and will need rebasing. There is no dependency on #8798. **Breaking:** direct calls such as `Se3Keyboard(cfg)` are removed. Use `se3_keyboard_teleop_cfg(...)` (or the corresponding builder), pass the result to `create_isaac_teleop_device`, and enter the returned context manager. The feature guide documents standalone session setup and config migration. Existing environment config declarations continue to translate with a migration warning; they no longer point to removed constructors. Validation: - 137 focused tests passed with one skip, across 13 files run in separate processes against the pinned Isaac Capture 1.7 packages. Coverage includes real SDK numeric actions/config translation, window/session lifecycle, native factory callbacks, Haply, CLI entry points, replay, and demo startup/pause/cleanup. - Seven deliberate regressions were rejected: a retained config constructor target, lost activation, skipped subclass migration, accepted missing Isaac Capture, cleared paused gripper, ignored demo pause, and repeated hotkeys. - After the SO-101 compatibility fix, 25 focused pipeline/IK/gripper/selection tests passed. The new graph regression failed on the original constructor argument; deliberate missing-gripper and reordered-quaternion mutations are rejected by numeric output checks. - Removed the file-existence assertions requested in review; the real pipeline tests retain config translation, versioned deprecation warnings and numeric output coverage. - A centralized file audit confirmed config-only legacy packages, no imports of retired classes, no old constructor targets, no additional script wrapper, and no HID dependency. - Full Sphinx HTML build passed with warnings treated as errors. Repository formatting/changelog checks, `git diff --check`, and `uv lock --check --offline` passed. Physical devices and a full CloudXR session were not exercised locally. The legacy OpenXR constructor test could not collect in the bare test container because `carb` requires the Kit runtime; CI must cover it. --------- Signed-off-by: Rafael Wiltz <rwiltz@nvidia.com> Co-authored-by: Octi Zhang <zhengyuz@nvidia.com> Co-authored-by: AntoineRichard <antoiner@nvidia.com>
Description
Adds a keyboard input API to visualizers, so code can read the keys pressed in a visualizer's window, e.g. for keyboard teleoperation or script hotkeys, independent of Kit/carb.
BaseVisualizer.key_event_sourcereturns aKeyEventSourcefor the visualizer's window, orNonewhen it has none (the default; also before initialization, after close, and headless). It is createdon first access and closed with the visualizer.
KeyEventSource.add_key_listener(on_key, on_focus_lost)returns a closableKeyboardSubscription. Presses and releases arrive as W3CKeyboardEvent.codestrings ("KeyW"), forwarded as the windowreports them;
on_focus_lostruns on blur, when the visualizer's UI takes the keyboard, and on close. Subscribing, closing and callbacks all happen on the visualizer's thread.BaseVisualizer.set_camera_keys_enabled(enabled)lets the caller turn off keyboard camera movement (Newton WASD/QE and arrow keys) while it uses those keys; a no-op by default.typed into the ImGui UI are withheld). Viser, Rerun and headless runs return
None.close(), while the window is still open; a failure there is logged and the rest of the teardown still runs.Opt-in: nothing is hooked until a listener subscribes, and existing visualizer behavior is unchanged.
Used by #8797 (keyboard, gamepad and SpaceMouse teleop through Isaac Capture) and #8798 (remaining scripts and deprecation of the
isaaclab.deviceskeyboard, gamepad and SpaceMouse devices).Fixes # (issue)
Type of change
Release backport
developChecklist
Docker and GPU tests run on demand. Push the commits you want tested, then
comment
run-cion the pull request.pre-commitchecks withuv run isaaclab --formatsource/<pkg>/changelog.d/for every touched package (do not editCHANGELOG.rstor bump package versions — CI handles that)CONTRIBUTORS.mdor my name already exists there