osc: Add parameters for Working Sets / OVR Toolkit's Profiles (#295)

* add `lowestBattery` parameter to match the casing of other parameters

* add the following parameters:
`isEditModeActive`, `ToggleEditMode`, `currentWorkingSet`, `CurrentProfile`, and `totalWorkingSets`

* treat fully transparent overlays as "not visible"

this fixes the `isWristVisible` parameter; it was always True even when not looking at it since the watch is usually always "active", which was the only condition before.
This commit is contained in:
Jay
2025-12-17 02:04:11 +11:00
committed by GitHub
parent c41c0b9b59
commit 6086dcf233
2 changed files with 61 additions and 14 deletions

View File

@@ -16,7 +16,7 @@ use crate::backend::input::TrackedDeviceRole;
pub struct OscSender { pub struct OscSender {
last_sent_overlay: Instant, last_sent_overlay: Instant,
last_sent_battery: Instant, last_sent_device: Instant,
upstream: UdpSocket, upstream: UdpSocket,
} }
@@ -35,7 +35,7 @@ impl OscSender {
Ok(Self { Ok(Self {
upstream, upstream,
last_sent_overlay: Instant::now(), last_sent_overlay: Instant::now(),
last_sent_battery: Instant::now(), last_sent_device: Instant::now(),
}) })
} }
@@ -55,24 +55,34 @@ impl OscSender {
#[allow(clippy::too_many_lines)] #[allow(clippy::too_many_lines)]
pub fn send_params<D>( pub fn send_params<D>(
&mut self, &mut self,
overlays: &OverlayWindowManager<D>, overlay_manager: &OverlayWindowManager<D>,
devices: &Vec<TrackedDevice>, devices: &Vec<TrackedDevice>,
) -> anyhow::Result<()> ) -> anyhow::Result<()>
where where
D: Default, D: Default,
{ {
// send overlay data every 0.1 seconds // send overlay parameters every 0.1 seconds
if self.last_sent_overlay.elapsed().as_millis() >= 100 { if self.last_sent_overlay.elapsed().as_millis() >= 100 {
self.last_sent_overlay = Instant::now(); self.last_sent_overlay = Instant::now();
let edit_mode = overlay_manager.get_edit_mode();
let current_set = overlay_manager.get_current_set().unwrap_or(0) as i32;
let total_sets = overlay_manager.get_total_sets() as i32;
// check state of each active overlay and count them
let mut num_overlays = 0; let mut num_overlays = 0;
let mut has_keyboard = false; let mut has_keyboard = false;
let mut has_wrist = false; let mut has_wrist = false;
for o in overlay_manager.values() {
for o in overlays.values() {
let Some(state) = o.config.active_state.as_ref() else { let Some(state) = o.config.active_state.as_ref() else {
continue; continue;
}; };
// skip overlays that are fully transparent; e.g. the watch when not looking at it
if state.alpha <= 0f32 {
continue;
}
match o.config.name.as_ref() { match o.config.name.as_ref() {
WATCH_NAME => has_wrist = true, WATCH_NAME => has_wrist = true,
KEYBOARD_NAME => has_keyboard = true, KEYBOARD_NAME => has_keyboard = true,
@@ -84,6 +94,7 @@ impl OscSender {
} }
} }
// overlays
self.send_message( self.send_message(
"/avatar/parameters/isOverlayOpen".into(), "/avatar/parameters/isOverlayOpen".into(),
vec![OscType::Bool(num_overlays > 0)], vec![OscType::Bool(num_overlays > 0)],
@@ -92,7 +103,34 @@ impl OscSender {
"/avatar/parameters/ToggleWindows".into(), "/avatar/parameters/ToggleWindows".into(),
vec![OscType::Bool(num_overlays > 0)], vec![OscType::Bool(num_overlays > 0)],
)?; )?;
self.send_message(
"/avatar/parameters/openOverlayCount".into(),
vec![OscType::Int(num_overlays)],
)?;
// working sets
self.send_message(
"/avatar/parameters/isEditModeActive".into(),
vec![OscType::Bool(edit_mode)],
)?;
self.send_message(
"/avatar/parameters/ToggleEditMode".into(),
vec![OscType::Bool(edit_mode)],
)?;
self.send_message(
"/avatar/parameters/currentWorkingSet".into(),
vec![OscType::Int(current_set)],
)?;
self.send_message(
"/avatar/parameters/CurrentProfile".into(),
vec![OscType::Int(current_set)],
)?;
self.send_message(
"/avatar/parameters/totalWorkingSets".into(),
vec![OscType::Int(total_sets)],
)?;
// keyboard
self.send_message( self.send_message(
"/avatar/parameters/isKeyboardOpen".into(), "/avatar/parameters/isKeyboardOpen".into(),
vec![OscType::Bool(has_keyboard)], vec![OscType::Bool(has_keyboard)],
@@ -102,19 +140,16 @@ impl OscSender {
vec![OscType::Bool(has_keyboard)], vec![OscType::Bool(has_keyboard)],
)?; )?;
// watch
self.send_message( self.send_message(
"/avatar/parameters/isWristVisible".into(), "/avatar/parameters/isWristVisible".into(),
vec![OscType::Bool(has_wrist)], vec![OscType::Bool(has_wrist)],
)?; )?;
self.send_message(
"/avatar/parameters/openOverlayCount".into(),
vec![OscType::Int(num_overlays)],
)?;
} }
// send battery levels every 10 seconds // send device parameters every 10 seconds
if self.last_sent_battery.elapsed().as_millis() >= 10000 { if self.last_sent_device.elapsed().as_millis() >= 10000 {
self.last_sent_battery = Instant::now(); self.last_sent_device = Instant::now();
let mut tracker_count: i8 = 0; let mut tracker_count: i8 = 0;
let mut controller_count: i8 = 0; let mut controller_count: i8 = 0;
@@ -162,7 +197,7 @@ impl OscSender {
)?; )?;
} }
// send average controller and tracker battery parameters // send controller- and tracker-specific battery parameters
self.send_message( self.send_message(
String::from("/avatar/parameters/averageControllerBattery"), String::from("/avatar/parameters/averageControllerBattery"),
vec![OscType::Float( vec![OscType::Float(
@@ -177,6 +212,10 @@ impl OscSender {
String::from("/avatar/parameters/LowestBattery"), String::from("/avatar/parameters/LowestBattery"),
vec![OscType::Float(lowest_battery)], vec![OscType::Float(lowest_battery)],
)?; )?;
self.send_message(
String::from("/avatar/parameters/lowestBattery"),
vec![OscType::Float(lowest_battery)],
)?;
} }
Ok(()) Ok(())

View File

@@ -362,6 +362,14 @@ impl<T> OverlayWindowManager<T> {
self.edit_mode self.edit_mode
} }
pub const fn get_current_set(&self) -> Option<usize> {
self.current_set
}
pub const fn get_total_sets(&self) -> usize {
self.sets.len()
}
pub fn set_edit_mode(&mut self, enabled: bool, app: &mut AppState) -> anyhow::Result<()> { pub fn set_edit_mode(&mut self, enabled: bool, app: &mut AppState) -> anyhow::Result<()> {
let changed = enabled != self.edit_mode; let changed = enabled != self.edit_mode;
self.edit_mode = enabled; self.edit_mode = enabled;