Gaze first: test results; treadmill from the start, muted compositor binding

From the first headset tests (docs/gaze-first.md, "Test results"):
- SteamVR gives the treadmill path only to a device that hints it when
  it's added, so the driver hints a role that's no hand from Activate
  (a hand still only while shown). With it, our device held the
  dashboard laser with no hand role. The helper doesn't release the
  pointer for having no hand role when POINTER_ROLE is treadmill.
- The helper's global action sets can't mute the compositor (SteamVR
  reports them inactive while the laser mouse has focus), but selecting
  pointer/bindings/vrcompositor_frame_controller_gazefirst.json (the
  stock binding without its trigger and bumper laser entries) through
  vrserver's /input/selectconfig.action does.
- input/vrws.py follows devices that connect later.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
DeeJanuzandClaude Opus 5.5 committed 2026-09-30 17:23:30 -06:00
1 parent bd06207db9
commit 87a63932c0
5 files changed
+506 -13

No files matched your search

+10 -5
View File
@@ -117,7 +117,9 @@ public:
props->SetStringProperty(c, Prop_ControllerType_String, "ft_pointer");
props->SetStringProperty(c, Prop_InputProfilePath_String, "{ft_pointer}/input/ft_pointer_profile.json");
props->SetStringProperty(c, Prop_RenderModelName_String, "{ft_pointer}/rendermodels/ft_pointer_invisible");
props->SetInt32Property(c, Prop_ControllerRoleHint_Int32, TrackedControllerRole_OptOut); // until "show"
// A hand only while shown (see the top); a role that's no hand from the start, since
// SteamVR gives a treadmill its path only when the device is added (docs/gaze-first.md).
props->SetInt32Property(c, Prop_ControllerRoleHint_Int32, HintFor(false));
props->SetInt32Property(c, Prop_DeviceClass_Int32, TrackedDeviceClass_Controller);
props->SetBoolProperty(c, Prop_NeverTracked_Bool, false);
@@ -213,12 +215,11 @@ public:
}
if (snapshot.role > 0 && snapshot.role != role_) {
role_ = snapshot.role;
if (hinted_) VRProperties()->SetInt32Property(container_, Prop_ControllerRoleHint_Int32, role_);
VRProperties()->SetInt32Property(container_, Prop_ControllerRoleHint_Int32, HintFor(hinted_));
}
if (snapshot.visible != hinted_) {
// Claim the hand before connecting; give it up when disconnecting.
VRProperties()->SetInt32Property(container_, Prop_ControllerRoleHint_Int32,
snapshot.visible ? role_ : int32_t(TrackedControllerRole_OptOut));
VRProperties()->SetInt32Property(container_, Prop_ControllerRoleHint_Int32, HintFor(snapshot.visible));
hinted_ = snapshot.visible;
}
const bool ok = hmd.bPoseIsValid && snapshot.visible;
@@ -239,7 +240,11 @@ private:
uint32_t objectId_ = k_unTrackedDeviceIndexInvalid;
PropertyContainerHandle_t container_ = k_ulInvalidPropertyContainer;
int32_t role_ = TrackedControllerRole_RightHand;
bool hinted_ = false; // whether the role hint currently claims role_
bool hinted_ = false; // whether we're shown (a hand role is hinted only then)
int32_t HintFor(bool shown) const {
const bool hand = role_ == TrackedControllerRole_LeftHand || role_ == TrackedControllerRole_RightHand;
return shown || !hand ? role_ : int32_t(TrackedControllerRole_OptOut);
}
DriverPose_t pose_{};
VRInputComponentHandle_t buttons_[kButtons] = {};
VRInputComponentHandle_t scrollX_ = 0, scrollY_ = 0;