feat: Add automatic button mapping system (internal) (#1817)

This commit is contained in:
Riccardo Zaglia 2023-09-05 18:46:04 +08:00
parent 79eff14c25
commit 0141ec2074
22 changed files with 2086 additions and 1578 deletions

View File

@ -167,6 +167,17 @@ pub fn send_playspace(area: Option<Vec2>) {
}
}
pub fn send_active_interaction_profile(device_id: u64, profile_id: u64) {
if let Some(sender) = &mut *CONTROL_SENDER.lock() {
sender
.send(&ClientControlPacket::ActiveInteractionProfile {
device_id,
profile_id,
})
.ok();
}
}
pub fn send_buttons(entries: Vec<ButtonEntry>) {
if let Some(sender) = &mut *CONTROL_SENDER.lock() {
sender.send(&ClientControlPacket::Buttons(entries)).ok();

View File

@ -4,11 +4,6 @@ use alvr_packets::{ButtonEntry, ButtonValue};
use openxr as xr;
use std::collections::HashMap;
enum BindingType {
Binary,
Scalar,
}
pub enum ButtonAction {
Binary(xr::Action<bool>),
Scalar(xr::Action<f32>),
@ -21,281 +16,8 @@ pub struct HandSource {
pub vibration_action: xr::Action<xr::Haptic>,
}
pub struct ButtonBindingInfo {
name: String,
//note: this might be different than the path that generated the id
binding_path: String,
binding_type: BindingType,
}
const QUEST_CONTROLLER_PROFILE: &str = "/interaction_profiles/oculus/touch_controller";
const PICO_NEO3_CONTROLLER_PROFILE: &str = "/interaction_profiles/bytedance/pico_neo3_controller";
const PICO4_CONTROLLER_PROFILE: &str = "/interaction_profiles/bytedance/pico4_controller";
const FOCUS3_CONTROLLER_PROFILE: &str = "/interaction_profiles/htc/vive_focus3_controller";
const YVR_CONTROLLER_PROFILE: &str = "/interaction_profiles/yvr/touch_controller";
fn get_button_bindings(platform: Platform) -> HashMap<u64, ButtonBindingInfo> {
let mut map = HashMap::new();
// Baseline bindings for the Touch controller
map.insert(
*MENU_CLICK_ID,
ButtonBindingInfo {
name: "menu_click".into(),
binding_path: MENU_CLICK_PATH.into(),
binding_type: BindingType::Binary,
},
);
map.insert(
*A_CLICK_ID,
ButtonBindingInfo {
name: "a_click".into(),
binding_path: A_CLICK_PATH.into(),
binding_type: BindingType::Binary,
},
);
map.insert(
*A_TOUCH_ID,
ButtonBindingInfo {
name: "a_touch".into(),
binding_path: A_TOUCH_PATH.into(),
binding_type: BindingType::Binary,
},
);
map.insert(
*B_CLICK_ID,
ButtonBindingInfo {
name: "b_click".into(),
binding_path: B_CLICK_PATH.into(),
binding_type: BindingType::Binary,
},
);
map.insert(
*B_TOUCH_ID,
ButtonBindingInfo {
name: "b_touch".into(),
binding_path: B_TOUCH_PATH.into(),
binding_type: BindingType::Binary,
},
);
map.insert(
*X_CLICK_ID,
ButtonBindingInfo {
name: "x_click".into(),
binding_path: X_CLICK_PATH.into(),
binding_type: BindingType::Binary,
},
);
map.insert(
*X_TOUCH_ID,
ButtonBindingInfo {
name: "x_touch".into(),
binding_path: X_TOUCH_PATH.into(),
binding_type: BindingType::Binary,
},
);
map.insert(
*Y_CLICK_ID,
ButtonBindingInfo {
name: "y_click".into(),
binding_path: Y_CLICK_PATH.into(),
binding_type: BindingType::Binary,
},
);
map.insert(
*Y_TOUCH_ID,
ButtonBindingInfo {
name: "y_touch".into(),
binding_path: Y_TOUCH_PATH.into(),
binding_type: BindingType::Binary,
},
);
map.insert(
*LEFT_SQUEEZE_VALUE_ID,
ButtonBindingInfo {
name: "left_squeeze_value".into(),
binding_path: LEFT_SQUEEZE_VALUE_PATH.into(),
binding_type: BindingType::Scalar,
},
);
map.insert(
*LEFT_SQUEEZE_CLICK_ID,
ButtonBindingInfo {
name: "left_squeeze_click".into(),
binding_path: "/user/hand/left/input/squeeze".into(),
binding_type: BindingType::Binary,
},
);
map.insert(
*LEFT_TRIGGER_VALUE_ID,
ButtonBindingInfo {
name: "left_trigger_value".into(),
binding_path: LEFT_TRIGGER_VALUE_PATH.into(),
binding_type: BindingType::Scalar,
},
);
map.insert(
*LEFT_TRIGGER_CLICK_ID,
ButtonBindingInfo {
name: "left_trigger_click".into(),
binding_path: "/user/hand/left/input/trigger".into(),
binding_type: BindingType::Binary,
},
);
map.insert(
*LEFT_TRIGGER_TOUCH_ID,
ButtonBindingInfo {
name: "left_trigger_touch".into(),
binding_path: LEFT_TRIGGER_TOUCH_PATH.into(),
binding_type: BindingType::Binary,
},
);
map.insert(
*LEFT_THUMBSTICK_X_ID,
ButtonBindingInfo {
name: "left_thumbstick_x".into(),
binding_path: LEFT_THUMBSTICK_X_PATH.into(),
binding_type: BindingType::Scalar,
},
);
map.insert(
*LEFT_THUMBSTICK_Y_ID,
ButtonBindingInfo {
name: "left_thumbstick_y".into(),
binding_path: LEFT_THUMBSTICK_Y_PATH.into(),
binding_type: BindingType::Scalar,
},
);
map.insert(
*LEFT_THUMBSTICK_CLICK_ID,
ButtonBindingInfo {
name: "left_thumbstick_click".into(),
binding_path: LEFT_THUMBSTICK_CLICK_PATH.into(),
binding_type: BindingType::Binary,
},
);
map.insert(
*LEFT_THUMBSTICK_TOUCH_ID,
ButtonBindingInfo {
name: "left_thumbstick_touch".into(),
binding_path: LEFT_THUMBSTICK_TOUCH_PATH.into(),
binding_type: BindingType::Binary,
},
);
map.insert(
*LEFT_THUMBREST_TOUCH_ID,
ButtonBindingInfo {
name: "left_thumbrest_touch".into(),
binding_path: LEFT_THUMBREST_TOUCH_PATH.into(),
binding_type: BindingType::Binary,
},
);
map.insert(
*RIGHT_SQUEEZE_VALUE_ID,
ButtonBindingInfo {
name: "right_squeeze_value".into(),
binding_path: RIGHT_SQUEEZE_VALUE_PATH.into(),
binding_type: BindingType::Scalar,
},
);
map.insert(
*RIGHT_SQUEEZE_CLICK_ID,
ButtonBindingInfo {
name: "right_squeeze_click".into(),
binding_path: "/user/hand/right/input/squeeze".into(),
binding_type: BindingType::Binary,
},
);
map.insert(
*RIGHT_TRIGGER_VALUE_ID,
ButtonBindingInfo {
name: "right_trigger_value".into(),
binding_path: RIGHT_TRIGGER_VALUE_PATH.into(),
binding_type: BindingType::Scalar,
},
);
map.insert(
*RIGHT_TRIGGER_CLICK_ID,
ButtonBindingInfo {
name: "right_trigger_click".into(),
binding_path: "/user/hand/right/input/trigger".into(),
binding_type: BindingType::Binary,
},
);
map.insert(
*RIGHT_TRIGGER_TOUCH_ID,
ButtonBindingInfo {
name: "right_trigger_touch".into(),
binding_path: RIGHT_TRIGGER_TOUCH_PATH.into(),
binding_type: BindingType::Binary,
},
);
map.insert(
*RIGHT_THUMBSTICK_X_ID,
ButtonBindingInfo {
name: "right_thumbstick_x".into(),
binding_path: RIGHT_THUMBSTICK_X_PATH.into(),
binding_type: BindingType::Scalar,
},
);
map.insert(
*RIGHT_THUMBSTICK_Y_ID,
ButtonBindingInfo {
name: "right_thumbstick_y".into(),
binding_path: RIGHT_THUMBSTICK_Y_PATH.into(),
binding_type: BindingType::Scalar,
},
);
map.insert(
*RIGHT_THUMBSTICK_CLICK_ID,
ButtonBindingInfo {
name: "right_thumbstick_click".into(),
binding_path: RIGHT_THUMBSTICK_CLICK_PATH.into(),
binding_type: BindingType::Binary,
},
);
map.insert(
*RIGHT_THUMBSTICK_TOUCH_ID,
ButtonBindingInfo {
name: "right_thumbstick_touch".into(),
binding_path: RIGHT_THUMBSTICK_TOUCH_PATH.into(),
binding_type: BindingType::Binary,
},
);
map.insert(
*RIGHT_THUMBREST_TOUCH_ID,
ButtonBindingInfo {
name: "right_thumbrest_touch".into(),
binding_path: RIGHT_THUMBREST_TOUCH_PATH.into(),
binding_type: BindingType::Binary,
},
);
// Tweak bindings if other platforms
match platform {
Platform::Focus3 => {
map.remove(&*A_TOUCH_ID);
map.remove(&*B_TOUCH_ID);
map.remove(&*X_TOUCH_ID);
map.remove(&*Y_TOUCH_ID);
map.remove(&*LEFT_SQUEEZE_CLICK_ID);
map.remove(&*LEFT_TRIGGER_CLICK_ID);
map.remove(&*LEFT_THUMBREST_TOUCH_ID);
map.remove(&*RIGHT_SQUEEZE_CLICK_ID);
map.remove(&*RIGHT_TRIGGER_CLICK_ID);
map.remove(&*RIGHT_THUMBREST_TOUCH_ID);
}
Platform::Yvr => {
map.remove(&*LEFT_SQUEEZE_VALUE_ID);
map.remove(&*RIGHT_SQUEEZE_VALUE_ID);
}
_ => {}
}
map
}
pub struct HandsInteractionContext {
pub interaction_profile_id: u64,
pub action_set: xr::ActionSet,
pub button_actions: HashMap<u64, ButtonAction>,
pub hand_sources: [HandSource; 2],
@ -317,31 +39,42 @@ pub fn initialize_hands_interaction(
xr::Binding::new(action, action.instance().string_to_path(path).unwrap())
}
let bindings_info = get_button_bindings(platform);
let interaction_profile_path = match platform {
Platform::Quest => QUEST_CONTROLLER_PROFILE_PATH,
Platform::PicoNeo3 => PICO_NEO3_CONTROLLER_PROFILE_PATH,
Platform::Pico4 => PICO4_CONTROLLER_PROFILE_PATH,
Platform::Focus3 => FOCUS3_CONTROLLER_PROFILE_PATH,
Platform::Yvr => YVR_CONTROLLER_PROFILE_PATH,
Platform::Other => QUEST_CONTROLLER_PROFILE_PATH,
};
let interaction_profile_id = alvr_common::hash_string(interaction_profile_path);
// Create actions:
let mut button_actions = HashMap::new();
for (id, info) in &bindings_info {
for button_id in &CONTROLLER_PROFILE_INFO
.get(&interaction_profile_id)
.unwrap()
.button_set
{
let info = BUTTON_INFO.get(button_id).unwrap();
let name = info.path[1..].replace('/', "_");
let display_name = format!(
"{}{}",
info.name[0..1].to_uppercase(),
info.name[1..].replace('_', " ")
name[0..1].to_uppercase(),
name[1..].replace('_', " ")
);
let action = match info.binding_type {
BindingType::Binary => ButtonAction::Binary(
action_set
.create_action(&info.name, &display_name, &[])
.unwrap(),
),
BindingType::Scalar => ButtonAction::Scalar(
action_set
.create_action(&info.name, &display_name, &[])
.unwrap(),
),
let action = match info.button_type {
ButtonType::Binary => {
ButtonAction::Binary(action_set.create_action(&name, &display_name, &[]).unwrap())
}
ButtonType::Scalar => {
ButtonAction::Scalar(action_set.create_action(&name, &display_name, &[]).unwrap())
}
};
button_actions.insert(*id, action);
button_actions.insert(*button_id, action);
}
let left_grip_action = action_set
@ -361,7 +94,7 @@ pub fn initialize_hands_interaction(
// Create action bindings:
for (id, action) in &button_actions {
let path = &bindings_info.get(id).unwrap().binding_path;
let path = &BUTTON_INFO.get(id).unwrap().path;
match action {
ButtonAction::Binary(action) => {
bindings.push(binding(action, path));
@ -391,19 +124,11 @@ pub fn initialize_hands_interaction(
));
// Apply bindings:
let controller_profile = match platform {
Platform::Quest => QUEST_CONTROLLER_PROFILE,
Platform::PicoNeo3 => PICO_NEO3_CONTROLLER_PROFILE,
Platform::Pico4 => PICO4_CONTROLLER_PROFILE,
Platform::Focus3 => FOCUS3_CONTROLLER_PROFILE,
Platform::Yvr => YVR_CONTROLLER_PROFILE,
Platform::Other => QUEST_CONTROLLER_PROFILE,
};
xr_instance
.suggest_interaction_profile_bindings(
xr_instance.string_to_path(controller_profile).unwrap(),
xr_instance
.string_to_path(interaction_profile_path)
.unwrap(),
&bindings,
)
.unwrap();
@ -444,6 +169,7 @@ pub fn initialize_hands_interaction(
];
HandsInteractionContext {
interaction_profile_id,
action_set,
button_actions,
hand_sources,
@ -528,73 +254,7 @@ pub fn get_hand_motion(
(Some(hand_motion), None)
}
// todo: move emulation to server
fn emulate_missing_button_value(
platform: Platform,
click_action_id: u64,
state: bool,
) -> Option<ButtonEntry> {
let value = ButtonValue::Scalar(if state { 1_f32 } else { 0_f32 });
if platform == Platform::Yvr {
if click_action_id == *LEFT_SQUEEZE_CLICK_ID {
Some(ButtonEntry {
path_id: *LEFT_SQUEEZE_VALUE_ID,
value,
})
} else if click_action_id == *RIGHT_SQUEEZE_CLICK_ID {
Some(ButtonEntry {
path_id: *RIGHT_SQUEEZE_VALUE_ID,
value,
})
} else {
None
}
} else {
None
}
}
// todo: use hysteresis
// todo: move emulation to server
fn emulate_missing_button_click(
platform: Platform,
value_action_id: u64,
state: f32,
) -> Option<ButtonEntry> {
let value = ButtonValue::Binary(state > 0.5);
if platform == Platform::Focus3 {
if value_action_id == *LEFT_SQUEEZE_VALUE_ID {
Some(ButtonEntry {
path_id: *LEFT_SQUEEZE_CLICK_ID,
value,
})
} else if value_action_id == *LEFT_TRIGGER_VALUE_ID {
Some(ButtonEntry {
path_id: *LEFT_TRIGGER_CLICK_ID,
value,
})
} else if value_action_id == *RIGHT_SQUEEZE_VALUE_ID {
Some(ButtonEntry {
path_id: *RIGHT_SQUEEZE_CLICK_ID,
value,
})
} else if value_action_id == *RIGHT_TRIGGER_VALUE_ID {
Some(ButtonEntry {
path_id: *RIGHT_TRIGGER_CLICK_ID,
value,
})
} else {
None
}
} else {
None
}
}
pub fn update_buttons(
platform: Platform,
xr_session: &xr::Session<xr::AnyGraphics>,
button_actions: &HashMap<u64, ButtonAction>,
) -> Vec<ButtonEntry> {
@ -611,12 +271,6 @@ pub fn update_buttons(
path_id: *id,
value: ButtonValue::Binary(state.current_state),
});
if let Some(entry) =
emulate_missing_button_value(platform, *id, state.current_state)
{
button_entries.push(entry);
}
}
}
ButtonAction::Scalar(action) => {
@ -629,12 +283,6 @@ pub fn update_buttons(
path_id: *id,
value: ButtonValue::Scalar(state.current_state),
});
if let Some(entry) =
emulate_missing_button_click(platform, *id, state.current_state)
{
button_entries.push(entry);
}
}
}
}

View File

@ -44,7 +44,6 @@ struct HistoryView {
}
struct StreamingInputContext {
platform: Platform,
xr_instance: xr::Instance,
xr_session: xr::Session<xr::AnyGraphics>,
hands_context: Arc<HandsInteractionContext>,
@ -341,11 +340,8 @@ fn update_streaming_input(ctx: &mut StreamingInputContext) {
face_data,
});
let button_entries = interaction::update_buttons(
ctx.platform,
&ctx.xr_session,
&ctx.hands_context.button_actions,
);
let button_entries =
interaction::update_buttons(&ctx.xr_session, &ctx.hands_context.button_actions);
if !button_entries.is_empty() {
alvr_client_core::send_buttons(button_entries);
}
@ -691,7 +687,6 @@ pub fn entry_point() {
};
let mut context = StreamingInputContext {
platform,
xr_instance: xr_instance.clone(),
xr_session: xr_session.clone().into_any_graphics(),
hands_context: Arc::clone(&hands_context),
@ -797,6 +792,15 @@ pub fn entry_point() {
.unwrap()
.map(|a| Vec2::new(a.width, a.height)),
);
alvr_client_core::send_active_interaction_profile(
*LEFT_HAND_ID,
hands_context.interaction_profile_id,
);
alvr_client_core::send_active_interaction_profile(
*RIGHT_HAND_ID,
hands_context.interaction_profile_id,
);
}
ClientCoreEvent::StreamingStopped => {
stream_swapchains.take();

907
alvr/common/src/inputs.rs Normal file
View File

@ -0,0 +1,907 @@
use crate::hash_string;
use once_cell::sync::Lazy;
use std::collections::{HashMap, HashSet};
// OpenXR interaction paths. They are used for the communication protocol and can also be used
// directly for OpenXR interop.
pub const HEAD_PATH: &str = "/user/head";
pub const LEFT_HAND_PATH: &str = "/user/hand/left";
pub const RIGHT_HAND_PATH: &str = "/user/hand/right";
pub const QUEST_CONTROLLER_PROFILE_PATH: &str = "/interaction_profiles/oculus/touch_controller";
pub const VIVE_CONTROLLER_PROFILE_PATH: &str = "/interaction_profiles/htc/vive_controller";
pub const INDEX_CONTROLLER_PROFILE_PATH: &str = "/interaction_profiles/valve/index_controller";
pub const PICO_NEO3_CONTROLLER_PROFILE_PATH: &str =
"/interaction_profiles/bytedance/pico_neo3_controller";
pub const PICO4_CONTROLLER_PROFILE_PATH: &str = "/interaction_profiles/bytedance/pico4_controller";
pub const FOCUS3_CONTROLLER_PROFILE_PATH: &str = "/interaction_profiles/htc/vive_focus3_controller";
pub const YVR_CONTROLLER_PROFILE_PATH: &str = "/interaction_profiles/yvr/touch_controller";
pub const HEAD_ENTER_CLICK_PATH: &str = "/user/head/input/enter/click";
pub const LEFT_SYSTEM_CLICK_PATH: &str = "/user/hand/left/input/system/click";
pub const LEFT_SYSTEM_TOUCH_PATH: &str = "/user/hand/left/input/system/touch";
pub const LEFT_MENU_CLICK_PATH: &str = "/user/hand/left/input/menu/click";
pub const LEFT_BACK_CLICK_PATH: &str = "/user/hand/left/input/back/click";
pub const LEFT_A_CLICK_PATH: &str = "/user/hand/left/input/a/click";
pub const LEFT_A_TOUCH_PATH: &str = "/user/hand/left/input/a/touch";
pub const LEFT_B_CLICK_PATH: &str = "/user/hand/left/input/b/click";
pub const LEFT_B_TOUCH_PATH: &str = "/user/hand/left/input/b/touch";
pub const LEFT_X_CLICK_PATH: &str = "/user/hand/left/input/x/click";
pub const LEFT_X_TOUCH_PATH: &str = "/user/hand/left/input/x/touch";
pub const LEFT_Y_CLICK_PATH: &str = "/user/hand/left/input/y/click";
pub const LEFT_Y_TOUCH_PATH: &str = "/user/hand/left/input/y/touch";
pub const LEFT_SQUEEZE_CLICK_PATH: &str = "/user/hand/left/input/squeeze/click";
pub const LEFT_SQUEEZE_TOUCH_PATH: &str = "/user/hand/left/input/squeeze/touch";
pub const LEFT_SQUEEZE_VALUE_PATH: &str = "/user/hand/left/input/squeeze/value";
pub const LEFT_SQUEEZE_FORCE_PATH: &str = "/user/hand/left/input/squeeze/force";
pub const LEFT_TRIGGER_CLICK_PATH: &str = "/user/hand/left/input/trigger/click";
pub const LEFT_TRIGGER_TOUCH_PATH: &str = "/user/hand/left/input/trigger/touch";
pub const LEFT_TRIGGER_VALUE_PATH: &str = "/user/hand/left/input/trigger/value";
pub const LEFT_THUMBSTICK_X_PATH: &str = "/user/hand/left/input/thumbstick/x";
pub const LEFT_THUMBSTICK_Y_PATH: &str = "/user/hand/left/input/thumbstick/y";
pub const LEFT_THUMBSTICK_CLICK_PATH: &str = "/user/hand/left/input/thumbstick/click";
pub const LEFT_THUMBSTICK_TOUCH_PATH: &str = "/user/hand/left/input/thumbstick/touch";
pub const LEFT_TRACKPAD_X_PATH: &str = "/user/hand/left/input/trackpad/x";
pub const LEFT_TRACKPAD_Y_PATH: &str = "/user/hand/left/input/trackpad/y";
pub const LEFT_TRACKPAD_CLICK_PATH: &str = "/user/hand/left/input/trackpad/click";
pub const LEFT_TRACKPAD_FORCE_PATH: &str = "/user/hand/left/input/trackpad/force";
pub const LEFT_TRACKPAD_TOUCH_PATH: &str = "/user/hand/left/input/trackpad/touch";
pub const LEFT_THUMBREST_TOUCH_PATH: &str = "/user/hand/left/input/thumbrest/touch";
pub const RIGHT_SYSTEM_CLICK_PATH: &str = "/user/hand/right/input/system/click";
pub const RIGHT_SYSTEM_TOUCH_PATH: &str = "/user/hand/right/input/system/touch";
pub const RIGHT_MENU_CLICK_PATH: &str = "/user/hand/right/input/menu/click";
pub const RIGHT_BACK_CLICK_PATH: &str = "/user/hand/right/input/back/click";
pub const RIGHT_A_CLICK_PATH: &str = "/user/hand/right/input/a/click";
pub const RIGHT_A_TOUCH_PATH: &str = "/user/hand/right/input/a/touch";
pub const RIGHT_B_CLICK_PATH: &str = "/user/hand/right/input/b/click";
pub const RIGHT_B_TOUCH_PATH: &str = "/user/hand/right/input/b/touch";
pub const RIGHT_SQUEEZE_CLICK_PATH: &str = "/user/hand/right/input/squeeze/click";
pub const RIGHT_SQUEEZE_TOUCH_PATH: &str = "/user/hand/right/input/squeeze/touch";
pub const RIGHT_SQUEEZE_VALUE_PATH: &str = "/user/hand/right/input/squeeze/value";
pub const RIGHT_SQUEEZE_FORCE_PATH: &str = "/user/hand/right/input/squeeze/force";
pub const RIGHT_TRIGGER_CLICK_PATH: &str = "/user/hand/right/input/trigger/click";
pub const RIGHT_TRIGGER_VALUE_PATH: &str = "/user/hand/right/input/trigger/value";
pub const RIGHT_TRIGGER_TOUCH_PATH: &str = "/user/hand/right/input/trigger/touch";
pub const RIGHT_THUMBSTICK_X_PATH: &str = "/user/hand/right/input/thumbstick/x";
pub const RIGHT_THUMBSTICK_Y_PATH: &str = "/user/hand/right/input/thumbstick/y";
pub const RIGHT_THUMBSTICK_CLICK_PATH: &str = "/user/hand/right/input/thumbstick/click";
pub const RIGHT_THUMBSTICK_TOUCH_PATH: &str = "/user/hand/right/input/thumbstick/touch";
pub const RIGHT_TRACKPAD_X_PATH: &str = "/user/hand/right/input/trackpad/x";
pub const RIGHT_TRACKPAD_Y_PATH: &str = "/user/hand/right/input/trackpad/y";
pub const RIGHT_TRACKPAD_CLICK_PATH: &str = "/user/hand/right/input/trackpad/click";
pub const RIGHT_TRACKPAD_FORCE_PATH: &str = "/user/hand/right/input/trackpad/force";
pub const RIGHT_TRACKPAD_TOUCH_PATH: &str = "/user/hand/right/input/trackpad/touch";
pub const RIGHT_THUMBREST_TOUCH_PATH: &str = "/user/hand/right/input/thumbrest/touch";
pub static HEAD_ID: Lazy<u64> = Lazy::new(|| hash_string(HEAD_PATH));
pub static LEFT_HAND_ID: Lazy<u64> = Lazy::new(|| hash_string(LEFT_HAND_PATH));
pub static RIGHT_HAND_ID: Lazy<u64> = Lazy::new(|| hash_string(RIGHT_HAND_PATH));
pub static QUEST_CONTROLLER_PROFILE_ID: Lazy<u64> =
Lazy::new(|| hash_string(QUEST_CONTROLLER_PROFILE_PATH));
pub static VIVE_CONTROLLER_PROFILE_ID: Lazy<u64> =
Lazy::new(|| hash_string(VIVE_CONTROLLER_PROFILE_PATH));
pub static INDEX_CONTROLLER_PROFILE_ID: Lazy<u64> =
Lazy::new(|| hash_string(INDEX_CONTROLLER_PROFILE_PATH));
pub static PICO_NEO3_CONTROLLER_PROFILE_ID: Lazy<u64> =
Lazy::new(|| hash_string(PICO_NEO3_CONTROLLER_PROFILE_PATH));
pub static PICO4_CONTROLLER_PROFILE_ID: Lazy<u64> =
Lazy::new(|| hash_string(PICO4_CONTROLLER_PROFILE_PATH));
pub static FOCUS3_CONTROLLER_PROFILE_ID: Lazy<u64> =
Lazy::new(|| hash_string(FOCUS3_CONTROLLER_PROFILE_PATH));
pub static YVR_CONTROLLER_PROFILE_ID: Lazy<u64> =
Lazy::new(|| hash_string(YVR_CONTROLLER_PROFILE_PATH));
pub static HEAD_ENTER_CLICK_ID: Lazy<u64> = Lazy::new(|| hash_string(HEAD_ENTER_CLICK_PATH));
pub static LEFT_SYSTEM_CLICK_ID: Lazy<u64> = Lazy::new(|| hash_string(LEFT_SYSTEM_CLICK_PATH));
pub static LEFT_SYSTEM_TOUCH_ID: Lazy<u64> = Lazy::new(|| hash_string(LEFT_SYSTEM_TOUCH_PATH));
pub static LEFT_MENU_CLICK_ID: Lazy<u64> = Lazy::new(|| hash_string(LEFT_MENU_CLICK_PATH));
pub static LEFT_BACK_CLICK_ID: Lazy<u64> = Lazy::new(|| hash_string(LEFT_BACK_CLICK_PATH));
pub static LEFT_A_CLICK_ID: Lazy<u64> = Lazy::new(|| hash_string(LEFT_A_CLICK_PATH));
pub static LEFT_A_TOUCH_ID: Lazy<u64> = Lazy::new(|| hash_string(LEFT_A_TOUCH_PATH));
pub static LEFT_B_CLICK_ID: Lazy<u64> = Lazy::new(|| hash_string(LEFT_B_CLICK_PATH));
pub static LEFT_B_TOUCH_ID: Lazy<u64> = Lazy::new(|| hash_string(LEFT_B_TOUCH_PATH));
pub static LEFT_X_CLICK_ID: Lazy<u64> = Lazy::new(|| hash_string(LEFT_X_CLICK_PATH));
pub static LEFT_X_TOUCH_ID: Lazy<u64> = Lazy::new(|| hash_string(LEFT_X_TOUCH_PATH));
pub static LEFT_Y_CLICK_ID: Lazy<u64> = Lazy::new(|| hash_string(LEFT_Y_CLICK_PATH));
pub static LEFT_Y_TOUCH_ID: Lazy<u64> = Lazy::new(|| hash_string(LEFT_Y_TOUCH_PATH));
pub static LEFT_SQUEEZE_CLICK_ID: Lazy<u64> = Lazy::new(|| hash_string(LEFT_SQUEEZE_CLICK_PATH));
pub static LEFT_SQUEEZE_VALUE_ID: Lazy<u64> = Lazy::new(|| hash_string(LEFT_SQUEEZE_VALUE_PATH));
pub static LEFT_SQUEEZE_TOUCH_ID: Lazy<u64> = Lazy::new(|| hash_string(LEFT_SQUEEZE_TOUCH_PATH));
pub static LEFT_SQUEEZE_FORCE_ID: Lazy<u64> = Lazy::new(|| hash_string(LEFT_SQUEEZE_FORCE_PATH));
pub static LEFT_TRIGGER_CLICK_ID: Lazy<u64> = Lazy::new(|| hash_string(LEFT_TRIGGER_CLICK_PATH));
pub static LEFT_TRIGGER_VALUE_ID: Lazy<u64> = Lazy::new(|| hash_string(LEFT_TRIGGER_VALUE_PATH));
pub static LEFT_TRIGGER_TOUCH_ID: Lazy<u64> = Lazy::new(|| hash_string(LEFT_TRIGGER_TOUCH_PATH));
pub static LEFT_THUMBSTICK_X_ID: Lazy<u64> = Lazy::new(|| hash_string(LEFT_THUMBSTICK_X_PATH));
pub static LEFT_THUMBSTICK_Y_ID: Lazy<u64> = Lazy::new(|| hash_string(LEFT_THUMBSTICK_Y_PATH));
pub static LEFT_THUMBSTICK_CLICK_ID: Lazy<u64> =
Lazy::new(|| hash_string(LEFT_THUMBSTICK_CLICK_PATH));
pub static LEFT_THUMBSTICK_TOUCH_ID: Lazy<u64> =
Lazy::new(|| hash_string(LEFT_THUMBSTICK_TOUCH_PATH));
pub static LEFT_TRACKPAD_X_ID: Lazy<u64> = Lazy::new(|| hash_string(LEFT_TRACKPAD_X_PATH));
pub static LEFT_TRACKPAD_Y_ID: Lazy<u64> = Lazy::new(|| hash_string(LEFT_TRACKPAD_Y_PATH));
pub static LEFT_TRACKPAD_CLICK_ID: Lazy<u64> = Lazy::new(|| hash_string(LEFT_TRACKPAD_CLICK_PATH));
pub static LEFT_TRACKPAD_FORCE_ID: Lazy<u64> = Lazy::new(|| hash_string(LEFT_TRACKPAD_FORCE_PATH));
pub static LEFT_TRACKPAD_TOUCH_ID: Lazy<u64> = Lazy::new(|| hash_string(LEFT_TRACKPAD_TOUCH_PATH));
pub static LEFT_THUMBREST_TOUCH_ID: Lazy<u64> =
Lazy::new(|| hash_string(LEFT_THUMBREST_TOUCH_PATH));
pub static RIGHT_SYSTEM_CLICK_ID: Lazy<u64> = Lazy::new(|| hash_string(RIGHT_SYSTEM_CLICK_PATH));
pub static RIGHT_SYSTEM_TOUCH_ID: Lazy<u64> = Lazy::new(|| hash_string(RIGHT_SYSTEM_TOUCH_PATH));
pub static RIGHT_MENU_CLICK_ID: Lazy<u64> = Lazy::new(|| hash_string(RIGHT_MENU_CLICK_PATH));
pub static RIGHT_BACK_CLICK_ID: Lazy<u64> = Lazy::new(|| hash_string(RIGHT_BACK_CLICK_PATH));
pub static RIGHT_A_CLICK_ID: Lazy<u64> = Lazy::new(|| hash_string(RIGHT_A_CLICK_PATH));
pub static RIGHT_A_TOUCH_ID: Lazy<u64> = Lazy::new(|| hash_string(RIGHT_A_TOUCH_PATH));
pub static RIGHT_B_CLICK_ID: Lazy<u64> = Lazy::new(|| hash_string(RIGHT_B_CLICK_PATH));
pub static RIGHT_B_TOUCH_ID: Lazy<u64> = Lazy::new(|| hash_string(RIGHT_B_TOUCH_PATH));
pub static RIGHT_SQUEEZE_CLICK_ID: Lazy<u64> = Lazy::new(|| hash_string(RIGHT_SQUEEZE_CLICK_PATH));
pub static RIGHT_SQUEEZE_VALUE_ID: Lazy<u64> = Lazy::new(|| hash_string(RIGHT_SQUEEZE_VALUE_PATH));
pub static RIGHT_SQUEEZE_TOUCH_ID: Lazy<u64> = Lazy::new(|| hash_string(RIGHT_SQUEEZE_TOUCH_PATH));
pub static RIGHT_SQUEEZE_FORCE_ID: Lazy<u64> = Lazy::new(|| hash_string(RIGHT_SQUEEZE_FORCE_PATH));
pub static RIGHT_TRIGGER_CLICK_ID: Lazy<u64> = Lazy::new(|| hash_string(RIGHT_TRIGGER_CLICK_PATH));
pub static RIGHT_TRIGGER_VALUE_ID: Lazy<u64> = Lazy::new(|| hash_string(RIGHT_TRIGGER_VALUE_PATH));
pub static RIGHT_TRIGGER_TOUCH_ID: Lazy<u64> = Lazy::new(|| hash_string(RIGHT_TRIGGER_TOUCH_PATH));
pub static RIGHT_THUMBSTICK_X_ID: Lazy<u64> = Lazy::new(|| hash_string(RIGHT_THUMBSTICK_X_PATH));
pub static RIGHT_THUMBSTICK_Y_ID: Lazy<u64> = Lazy::new(|| hash_string(RIGHT_THUMBSTICK_Y_PATH));
pub static RIGHT_THUMBSTICK_CLICK_ID: Lazy<u64> =
Lazy::new(|| hash_string(RIGHT_THUMBSTICK_CLICK_PATH));
pub static RIGHT_THUMBSTICK_TOUCH_ID: Lazy<u64> =
Lazy::new(|| hash_string(RIGHT_THUMBSTICK_TOUCH_PATH));
pub static RIGHT_TRACKPAD_X_ID: Lazy<u64> = Lazy::new(|| hash_string(RIGHT_TRACKPAD_X_PATH));
pub static RIGHT_TRACKPAD_Y_ID: Lazy<u64> = Lazy::new(|| hash_string(RIGHT_TRACKPAD_Y_PATH));
pub static RIGHT_TRACKPAD_CLICK_ID: Lazy<u64> =
Lazy::new(|| hash_string(RIGHT_TRACKPAD_CLICK_PATH));
pub static RIGHT_TRACKPAD_FORCE_ID: Lazy<u64> =
Lazy::new(|| hash_string(RIGHT_TRACKPAD_FORCE_PATH));
pub static RIGHT_TRACKPAD_TOUCH_ID: Lazy<u64> =
Lazy::new(|| hash_string(RIGHT_TRACKPAD_TOUCH_PATH));
pub static RIGHT_THUMBREST_TOUCH_ID: Lazy<u64> =
Lazy::new(|| hash_string(RIGHT_THUMBREST_TOUCH_PATH));
pub static DEVICE_ID_TO_PATH: Lazy<HashMap<u64, &str>> = Lazy::new(|| {
[
(*HEAD_ID, HEAD_PATH),
(*LEFT_HAND_ID, LEFT_HAND_PATH),
(*RIGHT_HAND_ID, RIGHT_HAND_PATH),
]
.into_iter()
.collect()
});
pub enum ButtonType {
Binary,
Scalar,
}
pub struct ButtonInfo {
pub path: &'static str,
pub button_type: ButtonType,
pub device_id: u64,
}
pub static BUTTON_INFO: Lazy<HashMap<u64, ButtonInfo>> = Lazy::new(|| {
[
(
*HEAD_ENTER_CLICK_ID,
ButtonInfo {
path: HEAD_ENTER_CLICK_PATH,
button_type: ButtonType::Binary,
device_id: *HEAD_ID,
},
),
(
*LEFT_SYSTEM_CLICK_ID,
ButtonInfo {
path: LEFT_SYSTEM_CLICK_PATH,
button_type: ButtonType::Binary,
device_id: *LEFT_HAND_ID,
},
),
(
*LEFT_SYSTEM_TOUCH_ID,
ButtonInfo {
path: LEFT_SYSTEM_TOUCH_PATH,
button_type: ButtonType::Binary,
device_id: *LEFT_HAND_ID,
},
),
(
*LEFT_MENU_CLICK_ID,
ButtonInfo {
path: LEFT_MENU_CLICK_PATH,
button_type: ButtonType::Binary,
device_id: *LEFT_HAND_ID,
},
),
(
*LEFT_BACK_CLICK_ID,
ButtonInfo {
path: LEFT_BACK_CLICK_PATH,
button_type: ButtonType::Binary,
device_id: *LEFT_HAND_ID,
},
),
(
*LEFT_A_CLICK_ID,
ButtonInfo {
path: LEFT_A_CLICK_PATH,
button_type: ButtonType::Binary,
device_id: *LEFT_HAND_ID,
},
),
(
*LEFT_A_TOUCH_ID,
ButtonInfo {
path: LEFT_A_TOUCH_PATH,
button_type: ButtonType::Binary,
device_id: *LEFT_HAND_ID,
},
),
(
*LEFT_B_CLICK_ID,
ButtonInfo {
path: LEFT_B_CLICK_PATH,
button_type: ButtonType::Binary,
device_id: *LEFT_HAND_ID,
},
),
(
*LEFT_B_TOUCH_ID,
ButtonInfo {
path: LEFT_B_TOUCH_PATH,
button_type: ButtonType::Binary,
device_id: *LEFT_HAND_ID,
},
),
(
*LEFT_X_CLICK_ID,
ButtonInfo {
path: LEFT_X_CLICK_PATH,
button_type: ButtonType::Binary,
device_id: *LEFT_HAND_ID,
},
),
(
*LEFT_X_TOUCH_ID,
ButtonInfo {
path: LEFT_X_TOUCH_PATH,
button_type: ButtonType::Binary,
device_id: *LEFT_HAND_ID,
},
),
(
*LEFT_Y_CLICK_ID,
ButtonInfo {
path: LEFT_Y_CLICK_PATH,
button_type: ButtonType::Binary,
device_id: *LEFT_HAND_ID,
},
),
(
*LEFT_Y_TOUCH_ID,
ButtonInfo {
path: LEFT_Y_TOUCH_PATH,
button_type: ButtonType::Binary,
device_id: *LEFT_HAND_ID,
},
),
(
*LEFT_SQUEEZE_CLICK_ID,
ButtonInfo {
path: LEFT_SQUEEZE_CLICK_PATH,
button_type: ButtonType::Binary,
device_id: *LEFT_HAND_ID,
},
),
(
*LEFT_SQUEEZE_VALUE_ID,
ButtonInfo {
path: LEFT_SQUEEZE_VALUE_PATH,
button_type: ButtonType::Scalar,
device_id: *LEFT_HAND_ID,
},
),
(
*LEFT_SQUEEZE_TOUCH_ID,
ButtonInfo {
path: LEFT_SQUEEZE_TOUCH_PATH,
button_type: ButtonType::Binary,
device_id: *LEFT_HAND_ID,
},
),
(
*LEFT_SQUEEZE_FORCE_ID,
ButtonInfo {
path: LEFT_SQUEEZE_FORCE_PATH,
button_type: ButtonType::Scalar,
device_id: *LEFT_HAND_ID,
},
),
(
*LEFT_TRIGGER_CLICK_ID,
ButtonInfo {
path: LEFT_TRIGGER_CLICK_PATH,
button_type: ButtonType::Binary,
device_id: *LEFT_HAND_ID,
},
),
(
*LEFT_TRIGGER_VALUE_ID,
ButtonInfo {
path: LEFT_TRIGGER_VALUE_PATH,
button_type: ButtonType::Scalar,
device_id: *LEFT_HAND_ID,
},
),
(
*LEFT_TRIGGER_TOUCH_ID,
ButtonInfo {
path: LEFT_TRIGGER_TOUCH_PATH,
button_type: ButtonType::Binary,
device_id: *LEFT_HAND_ID,
},
),
(
*LEFT_THUMBSTICK_X_ID,
ButtonInfo {
path: LEFT_THUMBSTICK_X_PATH,
button_type: ButtonType::Scalar,
device_id: *LEFT_HAND_ID,
},
),
(
*LEFT_THUMBSTICK_Y_ID,
ButtonInfo {
path: LEFT_THUMBSTICK_Y_PATH,
button_type: ButtonType::Scalar,
device_id: *LEFT_HAND_ID,
},
),
(
*LEFT_THUMBSTICK_CLICK_ID,
ButtonInfo {
path: LEFT_THUMBSTICK_CLICK_PATH,
button_type: ButtonType::Binary,
device_id: *LEFT_HAND_ID,
},
),
(
*LEFT_THUMBSTICK_TOUCH_ID,
ButtonInfo {
path: LEFT_THUMBSTICK_TOUCH_PATH,
button_type: ButtonType::Binary,
device_id: *LEFT_HAND_ID,
},
),
(
*LEFT_TRACKPAD_X_ID,
ButtonInfo {
path: LEFT_TRACKPAD_X_PATH,
button_type: ButtonType::Scalar,
device_id: *LEFT_HAND_ID,
},
),
(
*LEFT_TRACKPAD_Y_ID,
ButtonInfo {
path: LEFT_TRACKPAD_Y_PATH,
button_type: ButtonType::Scalar,
device_id: *LEFT_HAND_ID,
},
),
(
*LEFT_TRACKPAD_CLICK_ID,
ButtonInfo {
path: LEFT_TRACKPAD_CLICK_PATH,
button_type: ButtonType::Binary,
device_id: *LEFT_HAND_ID,
},
),
(
*LEFT_TRACKPAD_FORCE_ID,
ButtonInfo {
path: LEFT_TRACKPAD_FORCE_PATH,
button_type: ButtonType::Scalar,
device_id: *LEFT_HAND_ID,
},
),
(
*LEFT_TRACKPAD_TOUCH_ID,
ButtonInfo {
path: LEFT_TRACKPAD_TOUCH_PATH,
button_type: ButtonType::Binary,
device_id: *LEFT_HAND_ID,
},
),
(
*LEFT_THUMBREST_TOUCH_ID,
ButtonInfo {
path: LEFT_THUMBREST_TOUCH_PATH,
button_type: ButtonType::Binary,
device_id: *LEFT_HAND_ID,
},
),
(
*RIGHT_SYSTEM_CLICK_ID,
ButtonInfo {
path: RIGHT_SYSTEM_CLICK_PATH,
button_type: ButtonType::Binary,
device_id: *RIGHT_HAND_ID,
},
),
(
*RIGHT_SYSTEM_TOUCH_ID,
ButtonInfo {
path: RIGHT_SYSTEM_TOUCH_PATH,
button_type: ButtonType::Binary,
device_id: *RIGHT_HAND_ID,
},
),
(
*RIGHT_MENU_CLICK_ID,
ButtonInfo {
path: RIGHT_MENU_CLICK_PATH,
button_type: ButtonType::Binary,
device_id: *RIGHT_HAND_ID,
},
),
(
*RIGHT_BACK_CLICK_ID,
ButtonInfo {
path: RIGHT_BACK_CLICK_PATH,
button_type: ButtonType::Binary,
device_id: *RIGHT_HAND_ID,
},
),
(
*RIGHT_A_CLICK_ID,
ButtonInfo {
path: RIGHT_A_CLICK_PATH,
button_type: ButtonType::Binary,
device_id: *RIGHT_HAND_ID,
},
),
(
*RIGHT_A_TOUCH_ID,
ButtonInfo {
path: RIGHT_A_TOUCH_PATH,
button_type: ButtonType::Binary,
device_id: *RIGHT_HAND_ID,
},
),
(
*RIGHT_B_CLICK_ID,
ButtonInfo {
path: RIGHT_B_CLICK_PATH,
button_type: ButtonType::Binary,
device_id: *RIGHT_HAND_ID,
},
),
(
*RIGHT_B_TOUCH_ID,
ButtonInfo {
path: RIGHT_B_TOUCH_PATH,
button_type: ButtonType::Binary,
device_id: *RIGHT_HAND_ID,
},
),
(
*RIGHT_SQUEEZE_CLICK_ID,
ButtonInfo {
path: RIGHT_SQUEEZE_CLICK_PATH,
button_type: ButtonType::Binary,
device_id: *RIGHT_HAND_ID,
},
),
(
*RIGHT_SQUEEZE_VALUE_ID,
ButtonInfo {
path: RIGHT_SQUEEZE_VALUE_PATH,
button_type: ButtonType::Scalar,
device_id: *RIGHT_HAND_ID,
},
),
(
*RIGHT_SQUEEZE_TOUCH_ID,
ButtonInfo {
path: RIGHT_SQUEEZE_TOUCH_PATH,
button_type: ButtonType::Binary,
device_id: *RIGHT_HAND_ID,
},
),
(
*RIGHT_SQUEEZE_FORCE_ID,
ButtonInfo {
path: RIGHT_SQUEEZE_FORCE_PATH,
button_type: ButtonType::Scalar,
device_id: *RIGHT_HAND_ID,
},
),
(
*RIGHT_TRIGGER_CLICK_ID,
ButtonInfo {
path: RIGHT_TRIGGER_CLICK_PATH,
button_type: ButtonType::Binary,
device_id: *RIGHT_HAND_ID,
},
),
(
*RIGHT_TRIGGER_VALUE_ID,
ButtonInfo {
path: RIGHT_TRIGGER_VALUE_PATH,
button_type: ButtonType::Scalar,
device_id: *RIGHT_HAND_ID,
},
),
(
*RIGHT_TRIGGER_TOUCH_ID,
ButtonInfo {
path: RIGHT_TRIGGER_TOUCH_PATH,
button_type: ButtonType::Binary,
device_id: *RIGHT_HAND_ID,
},
),
(
*RIGHT_THUMBSTICK_X_ID,
ButtonInfo {
path: RIGHT_THUMBSTICK_X_PATH,
button_type: ButtonType::Scalar,
device_id: *RIGHT_HAND_ID,
},
),
(
*RIGHT_THUMBSTICK_Y_ID,
ButtonInfo {
path: RIGHT_THUMBSTICK_Y_PATH,
button_type: ButtonType::Scalar,
device_id: *RIGHT_HAND_ID,
},
),
(
*RIGHT_THUMBSTICK_CLICK_ID,
ButtonInfo {
path: RIGHT_THUMBSTICK_CLICK_PATH,
button_type: ButtonType::Binary,
device_id: *RIGHT_HAND_ID,
},
),
(
*RIGHT_THUMBSTICK_TOUCH_ID,
ButtonInfo {
path: RIGHT_THUMBSTICK_TOUCH_PATH,
button_type: ButtonType::Binary,
device_id: *RIGHT_HAND_ID,
},
),
(
*RIGHT_TRACKPAD_X_ID,
ButtonInfo {
path: RIGHT_TRACKPAD_X_PATH,
button_type: ButtonType::Scalar,
device_id: *RIGHT_HAND_ID,
},
),
(
*RIGHT_TRACKPAD_Y_ID,
ButtonInfo {
path: RIGHT_TRACKPAD_Y_PATH,
button_type: ButtonType::Scalar,
device_id: *RIGHT_HAND_ID,
},
),
(
*RIGHT_TRACKPAD_CLICK_ID,
ButtonInfo {
path: RIGHT_TRACKPAD_CLICK_PATH,
button_type: ButtonType::Binary,
device_id: *RIGHT_HAND_ID,
},
),
(
*RIGHT_TRACKPAD_FORCE_ID,
ButtonInfo {
path: RIGHT_TRACKPAD_FORCE_PATH,
button_type: ButtonType::Scalar,
device_id: *RIGHT_HAND_ID,
},
),
(
*RIGHT_TRACKPAD_TOUCH_ID,
ButtonInfo {
path: RIGHT_TRACKPAD_TOUCH_PATH,
button_type: ButtonType::Binary,
device_id: *RIGHT_HAND_ID,
},
),
(
*RIGHT_THUMBREST_TOUCH_ID,
ButtonInfo {
path: RIGHT_THUMBREST_TOUCH_PATH,
button_type: ButtonType::Binary,
device_id: *RIGHT_HAND_ID,
},
),
]
.into_iter()
.collect()
});
pub struct InteractionProfileInfo {
pub path: &'static str,
pub button_set: HashSet<u64>,
}
pub static CONTROLLER_PROFILE_INFO: Lazy<HashMap<u64, InteractionProfileInfo>> = Lazy::new(|| {
[
(
*QUEST_CONTROLLER_PROFILE_ID,
InteractionProfileInfo {
path: QUEST_CONTROLLER_PROFILE_PATH,
button_set: [
*LEFT_X_CLICK_ID,
*LEFT_X_TOUCH_ID,
*LEFT_Y_CLICK_ID,
*LEFT_Y_TOUCH_ID,
*LEFT_MENU_CLICK_ID,
*LEFT_SQUEEZE_VALUE_ID,
*LEFT_TRIGGER_VALUE_ID,
*LEFT_TRIGGER_TOUCH_ID,
*LEFT_THUMBSTICK_X_ID,
*LEFT_THUMBSTICK_Y_ID,
*LEFT_THUMBSTICK_CLICK_ID,
*LEFT_THUMBSTICK_TOUCH_ID,
*LEFT_THUMBREST_TOUCH_ID,
*RIGHT_A_CLICK_ID,
*RIGHT_A_TOUCH_ID,
*RIGHT_B_CLICK_ID,
*RIGHT_B_TOUCH_ID,
*RIGHT_SYSTEM_CLICK_ID,
*RIGHT_SQUEEZE_VALUE_ID,
*RIGHT_TRIGGER_VALUE_ID,
*RIGHT_TRIGGER_TOUCH_ID,
*RIGHT_THUMBSTICK_X_ID,
*RIGHT_THUMBSTICK_Y_ID,
*RIGHT_THUMBSTICK_CLICK_ID,
*RIGHT_THUMBSTICK_TOUCH_ID,
*RIGHT_THUMBREST_TOUCH_ID,
]
.into_iter()
.collect(),
},
),
(
*VIVE_CONTROLLER_PROFILE_ID,
InteractionProfileInfo {
path: VIVE_CONTROLLER_PROFILE_PATH,
button_set: [
*LEFT_SYSTEM_CLICK_ID,
*LEFT_SQUEEZE_CLICK_ID,
*LEFT_MENU_CLICK_ID,
*LEFT_TRIGGER_CLICK_ID,
*LEFT_TRIGGER_VALUE_ID,
*LEFT_TRACKPAD_X_ID,
*LEFT_TRACKPAD_Y_ID,
*LEFT_TRACKPAD_CLICK_ID,
*LEFT_TRACKPAD_TOUCH_ID,
*RIGHT_SYSTEM_CLICK_ID,
*RIGHT_SQUEEZE_CLICK_ID,
*RIGHT_MENU_CLICK_ID,
*RIGHT_TRIGGER_CLICK_ID,
*RIGHT_TRIGGER_VALUE_ID,
*RIGHT_TRACKPAD_X_ID,
*RIGHT_TRACKPAD_Y_ID,
*RIGHT_TRACKPAD_CLICK_ID,
*RIGHT_TRACKPAD_TOUCH_ID,
]
.into_iter()
.collect(),
},
),
(
*INDEX_CONTROLLER_PROFILE_ID,
InteractionProfileInfo {
path: INDEX_CONTROLLER_PROFILE_PATH,
button_set: [
*LEFT_SYSTEM_CLICK_ID,
*LEFT_SYSTEM_TOUCH_ID,
*LEFT_A_CLICK_ID,
*LEFT_A_TOUCH_ID,
*LEFT_B_CLICK_ID,
*LEFT_B_TOUCH_ID,
*LEFT_SQUEEZE_VALUE_ID,
*LEFT_SQUEEZE_FORCE_ID,
*LEFT_TRIGGER_CLICK_ID,
*LEFT_TRIGGER_VALUE_ID,
*LEFT_TRIGGER_TOUCH_ID,
*LEFT_THUMBSTICK_X_ID,
*LEFT_THUMBSTICK_Y_ID,
*LEFT_THUMBSTICK_CLICK_ID,
*LEFT_THUMBSTICK_TOUCH_ID,
*LEFT_TRACKPAD_X_ID,
*LEFT_TRACKPAD_Y_ID,
*LEFT_TRACKPAD_FORCE_ID,
*LEFT_TRACKPAD_TOUCH_ID,
*RIGHT_SYSTEM_CLICK_ID,
*RIGHT_SYSTEM_TOUCH_ID,
*RIGHT_A_CLICK_ID,
*RIGHT_A_TOUCH_ID,
*RIGHT_B_CLICK_ID,
*RIGHT_B_TOUCH_ID,
*RIGHT_SQUEEZE_VALUE_ID,
*RIGHT_SQUEEZE_FORCE_ID,
*RIGHT_TRIGGER_CLICK_ID,
*RIGHT_TRIGGER_VALUE_ID,
*RIGHT_TRIGGER_TOUCH_ID,
*RIGHT_THUMBSTICK_X_ID,
*RIGHT_THUMBSTICK_Y_ID,
*RIGHT_THUMBSTICK_CLICK_ID,
*RIGHT_THUMBSTICK_TOUCH_ID,
*RIGHT_TRACKPAD_X_ID,
*RIGHT_TRACKPAD_Y_ID,
*RIGHT_TRACKPAD_FORCE_ID,
*RIGHT_TRACKPAD_TOUCH_ID,
]
.into_iter()
.collect(),
},
),
(
*PICO_NEO3_CONTROLLER_PROFILE_ID,
InteractionProfileInfo {
path: PICO_NEO3_CONTROLLER_PROFILE_PATH,
button_set: [
*LEFT_X_CLICK_ID,
*LEFT_X_TOUCH_ID,
*LEFT_Y_CLICK_ID,
*LEFT_Y_TOUCH_ID,
*LEFT_MENU_CLICK_ID,
*LEFT_SYSTEM_CLICK_ID,
*LEFT_TRIGGER_CLICK_ID,
*LEFT_TRIGGER_VALUE_ID,
*LEFT_TRIGGER_TOUCH_ID,
*LEFT_THUMBSTICK_Y_ID,
*LEFT_THUMBSTICK_X_ID,
*LEFT_THUMBSTICK_CLICK_ID,
*LEFT_THUMBSTICK_TOUCH_ID,
*LEFT_SQUEEZE_CLICK_ID,
*LEFT_SQUEEZE_VALUE_ID,
*LEFT_THUMBREST_TOUCH_ID,
*RIGHT_A_CLICK_ID,
*RIGHT_A_TOUCH_ID,
*RIGHT_B_CLICK_ID,
*RIGHT_B_TOUCH_ID,
*RIGHT_MENU_CLICK_ID,
*RIGHT_SYSTEM_CLICK_ID,
*RIGHT_TRIGGER_CLICK_ID,
*RIGHT_TRIGGER_VALUE_ID,
*RIGHT_TRIGGER_TOUCH_ID,
*RIGHT_THUMBSTICK_Y_ID,
*RIGHT_THUMBSTICK_X_ID,
*RIGHT_THUMBSTICK_CLICK_ID,
*RIGHT_THUMBSTICK_TOUCH_ID,
*RIGHT_SQUEEZE_CLICK_ID,
*RIGHT_SQUEEZE_VALUE_ID,
*RIGHT_THUMBREST_TOUCH_ID,
]
.into_iter()
.collect(),
},
),
(
*PICO4_CONTROLLER_PROFILE_ID,
InteractionProfileInfo {
path: PICO4_CONTROLLER_PROFILE_PATH,
button_set: [
*LEFT_X_CLICK_ID,
*LEFT_X_TOUCH_ID,
*LEFT_Y_CLICK_ID,
*LEFT_Y_TOUCH_ID,
*LEFT_MENU_CLICK_ID,
*LEFT_SYSTEM_CLICK_ID,
*LEFT_TRIGGER_CLICK_ID,
*LEFT_TRIGGER_VALUE_ID,
*LEFT_TRIGGER_TOUCH_ID,
*LEFT_THUMBSTICK_Y_ID,
*LEFT_THUMBSTICK_X_ID,
*LEFT_THUMBSTICK_CLICK_ID,
*LEFT_THUMBSTICK_TOUCH_ID,
*LEFT_SQUEEZE_CLICK_ID,
*LEFT_SQUEEZE_VALUE_ID,
*LEFT_THUMBREST_TOUCH_ID,
*RIGHT_A_CLICK_ID,
*RIGHT_A_TOUCH_ID,
*RIGHT_B_CLICK_ID,
*RIGHT_B_TOUCH_ID,
*RIGHT_SYSTEM_CLICK_ID,
*RIGHT_TRIGGER_CLICK_ID,
*RIGHT_TRIGGER_VALUE_ID,
*RIGHT_TRIGGER_TOUCH_ID,
*RIGHT_THUMBSTICK_Y_ID,
*RIGHT_THUMBSTICK_X_ID,
*RIGHT_THUMBSTICK_CLICK_ID,
*RIGHT_THUMBSTICK_TOUCH_ID,
*RIGHT_SQUEEZE_CLICK_ID,
*RIGHT_SQUEEZE_VALUE_ID,
*RIGHT_THUMBREST_TOUCH_ID,
]
.into_iter()
.collect(),
},
),
(
*FOCUS3_CONTROLLER_PROFILE_ID,
InteractionProfileInfo {
path: FOCUS3_CONTROLLER_PROFILE_PATH,
button_set: [
*LEFT_X_CLICK_ID,
*LEFT_Y_CLICK_ID,
*LEFT_MENU_CLICK_ID,
*LEFT_SQUEEZE_CLICK_ID,
// *LEFT_SQUEEZE_TOUCH_ID, // not actually working
*LEFT_SQUEEZE_VALUE_ID,
*LEFT_TRIGGER_CLICK_ID,
*LEFT_TRIGGER_TOUCH_ID,
*LEFT_TRIGGER_VALUE_ID,
*LEFT_THUMBSTICK_X_ID,
*LEFT_THUMBSTICK_Y_ID,
*LEFT_THUMBSTICK_CLICK_ID,
*LEFT_THUMBSTICK_TOUCH_ID,
*LEFT_THUMBREST_TOUCH_ID,
*RIGHT_A_CLICK_ID,
*RIGHT_B_CLICK_ID,
*RIGHT_SYSTEM_CLICK_ID,
*RIGHT_SQUEEZE_CLICK_ID,
// *RIGHT_SQUEEZE_TOUCH_ID, // not actually working
*RIGHT_SQUEEZE_VALUE_ID,
*RIGHT_TRIGGER_CLICK_ID,
*RIGHT_TRIGGER_TOUCH_ID,
*RIGHT_TRIGGER_VALUE_ID,
*RIGHT_THUMBSTICK_X_ID,
*RIGHT_THUMBSTICK_Y_ID,
*RIGHT_THUMBSTICK_CLICK_ID,
*RIGHT_THUMBSTICK_TOUCH_ID,
*RIGHT_THUMBREST_TOUCH_ID,
]
.into_iter()
.collect(),
},
),
(
*YVR_CONTROLLER_PROFILE_ID,
InteractionProfileInfo {
path: YVR_CONTROLLER_PROFILE_PATH,
button_set: [
*LEFT_X_CLICK_ID,
*LEFT_Y_CLICK_ID,
*LEFT_MENU_CLICK_ID,
*LEFT_SQUEEZE_CLICK_ID,
*LEFT_TRIGGER_CLICK_ID,
*LEFT_TRIGGER_TOUCH_ID,
*LEFT_TRIGGER_VALUE_ID,
*LEFT_THUMBSTICK_X_ID,
*LEFT_THUMBSTICK_Y_ID,
*LEFT_THUMBSTICK_CLICK_ID,
*LEFT_THUMBSTICK_TOUCH_ID,
*LEFT_THUMBREST_TOUCH_ID,
*RIGHT_A_CLICK_ID,
*RIGHT_B_CLICK_ID,
*RIGHT_SYSTEM_CLICK_ID,
*RIGHT_SQUEEZE_CLICK_ID,
*RIGHT_TRIGGER_CLICK_ID,
*RIGHT_TRIGGER_TOUCH_ID,
*RIGHT_TRIGGER_VALUE_ID,
*RIGHT_THUMBSTICK_X_ID,
*RIGHT_THUMBSTICK_Y_ID,
*RIGHT_THUMBSTICK_CLICK_ID,
*RIGHT_THUMBSTICK_TOUCH_ID,
*RIGHT_THUMBREST_TOUCH_ID,
]
.into_iter()
.collect(),
},
),
]
.into_iter()
.collect()
});

View File

@ -1,7 +1,7 @@
mod average;
mod connection_result;
mod inputs;
mod logging;
mod paths;
mod primitives;
mod version;
@ -18,9 +18,9 @@ pub use settings_schema;
pub use average::*;
pub use connection_result::*;
pub use inputs::*;
pub use log::{debug, error, info, warn};
pub use logging::*;
pub use paths::*;
pub use primitives::*;
pub use version::*;

View File

@ -1,90 +0,0 @@
use crate::hash_string;
use once_cell::sync::Lazy;
use std::collections::HashMap;
pub const HEAD_PATH: &str = "/user/head";
pub const LEFT_HAND_PATH: &str = "/user/hand/left";
pub const RIGHT_HAND_PATH: &str = "/user/hand/right";
pub static HEAD_ID: Lazy<u64> = Lazy::new(|| hash_string(HEAD_PATH));
pub static LEFT_HAND_ID: Lazy<u64> = Lazy::new(|| hash_string(LEFT_HAND_PATH));
pub static RIGHT_HAND_ID: Lazy<u64> = Lazy::new(|| hash_string(RIGHT_HAND_PATH));
pub static DEVICE_ID_TO_PATH: Lazy<HashMap<u64, &str>> = Lazy::new(|| {
[
(*HEAD_ID, HEAD_PATH),
(*LEFT_HAND_ID, LEFT_HAND_PATH),
(*RIGHT_HAND_ID, RIGHT_HAND_PATH),
]
.into_iter()
.collect()
});
pub const HEAD_ENTER_CLICK_PATH: &str = "/user/head/input/enter/click";
pub const BACK_CLICK_PATH: &str = "/user/hand/left/input/back/click";
pub const MENU_CLICK_PATH: &str = "/user/hand/left/input/menu/click";
pub const A_CLICK_PATH: &str = "/user/hand/right/input/a/click";
pub const A_TOUCH_PATH: &str = "/user/hand/right/input/a/touch";
pub const B_CLICK_PATH: &str = "/user/hand/right/input/b/click";
pub const B_TOUCH_PATH: &str = "/user/hand/right/input/b/touch";
pub const X_CLICK_PATH: &str = "/user/hand/left/input/x/click";
pub const X_TOUCH_PATH: &str = "/user/hand/left/input/x/touch";
pub const Y_CLICK_PATH: &str = "/user/hand/left/input/y/click";
pub const Y_TOUCH_PATH: &str = "/user/hand/left/input/y/touch";
pub const LEFT_SQUEEZE_CLICK_PATH: &str = "/user/hand/left/input/squeeze/click";
pub const LEFT_SQUEEZE_VALUE_PATH: &str = "/user/hand/left/input/squeeze/value";
pub const LEFT_TRIGGER_CLICK_PATH: &str = "/user/hand/left/input/trigger/click";
pub const LEFT_TRIGGER_VALUE_PATH: &str = "/user/hand/left/input/trigger/value";
pub const LEFT_TRIGGER_TOUCH_PATH: &str = "/user/hand/left/input/trigger/touch";
pub const LEFT_THUMBSTICK_X_PATH: &str = "/user/hand/left/input/thumbstick/x";
pub const LEFT_THUMBSTICK_Y_PATH: &str = "/user/hand/left/input/thumbstick/y";
pub const LEFT_THUMBSTICK_CLICK_PATH: &str = "/user/hand/left/input/thumbstick/click";
pub const LEFT_THUMBSTICK_TOUCH_PATH: &str = "/user/hand/left/input/thumbstick/touch";
pub const LEFT_THUMBREST_TOUCH_PATH: &str = "/user/hand/left/input/thumbrest/touch";
pub const RIGHT_SQUEEZE_CLICK_PATH: &str = "/user/hand/right/input/squeeze/click";
pub const RIGHT_SQUEEZE_VALUE_PATH: &str = "/user/hand/right/input/squeeze/value";
pub const RIGHT_TRIGGER_CLICK_PATH: &str = "/user/hand/right/input/trigger/click";
pub const RIGHT_TRIGGER_VALUE_PATH: &str = "/user/hand/right/input/trigger/value";
pub const RIGHT_TRIGGER_TOUCH_PATH: &str = "/user/hand/right/input/trigger/touch";
pub const RIGHT_THUMBSTICK_X_PATH: &str = "/user/hand/right/input/thumbstick/x";
pub const RIGHT_THUMBSTICK_Y_PATH: &str = "/user/hand/right/input/thumbstick/y";
pub const RIGHT_THUMBSTICK_CLICK_PATH: &str = "/user/hand/right/input/thumbstick/click";
pub const RIGHT_THUMBSTICK_TOUCH_PATH: &str = "/user/hand/right/input/thumbstick/touch";
pub const RIGHT_THUMBREST_TOUCH_PATH: &str = "/user/hand/right/input/thumbrest/touch";
pub static HEAD_ENTER_CLICK_ID: Lazy<u64> = Lazy::new(|| hash_string(HEAD_ENTER_CLICK_PATH));
pub static MENU_CLICK_ID: Lazy<u64> = Lazy::new(|| hash_string(MENU_CLICK_PATH));
pub static A_CLICK_ID: Lazy<u64> = Lazy::new(|| hash_string(A_CLICK_PATH));
pub static A_TOUCH_ID: Lazy<u64> = Lazy::new(|| hash_string(A_TOUCH_PATH));
pub static B_CLICK_ID: Lazy<u64> = Lazy::new(|| hash_string(B_CLICK_PATH));
pub static B_TOUCH_ID: Lazy<u64> = Lazy::new(|| hash_string(B_TOUCH_PATH));
pub static X_CLICK_ID: Lazy<u64> = Lazy::new(|| hash_string(X_CLICK_PATH));
pub static X_TOUCH_ID: Lazy<u64> = Lazy::new(|| hash_string(X_TOUCH_PATH));
pub static Y_CLICK_ID: Lazy<u64> = Lazy::new(|| hash_string(Y_CLICK_PATH));
pub static Y_TOUCH_ID: Lazy<u64> = Lazy::new(|| hash_string(Y_TOUCH_PATH));
pub static LEFT_SQUEEZE_CLICK_ID: Lazy<u64> = Lazy::new(|| hash_string(LEFT_SQUEEZE_CLICK_PATH));
pub static LEFT_SQUEEZE_VALUE_ID: Lazy<u64> = Lazy::new(|| hash_string(LEFT_SQUEEZE_VALUE_PATH));
pub static LEFT_TRIGGER_CLICK_ID: Lazy<u64> = Lazy::new(|| hash_string(LEFT_TRIGGER_CLICK_PATH));
pub static LEFT_TRIGGER_VALUE_ID: Lazy<u64> = Lazy::new(|| hash_string(LEFT_TRIGGER_VALUE_PATH));
pub static LEFT_TRIGGER_TOUCH_ID: Lazy<u64> = Lazy::new(|| hash_string(LEFT_TRIGGER_TOUCH_PATH));
pub static LEFT_THUMBSTICK_X_ID: Lazy<u64> = Lazy::new(|| hash_string(LEFT_THUMBSTICK_X_PATH));
pub static LEFT_THUMBSTICK_Y_ID: Lazy<u64> = Lazy::new(|| hash_string(LEFT_THUMBSTICK_Y_PATH));
pub static LEFT_THUMBSTICK_CLICK_ID: Lazy<u64> =
Lazy::new(|| hash_string(LEFT_THUMBSTICK_CLICK_PATH));
pub static LEFT_THUMBSTICK_TOUCH_ID: Lazy<u64> =
Lazy::new(|| hash_string(LEFT_THUMBSTICK_TOUCH_PATH));
pub static LEFT_THUMBREST_TOUCH_ID: Lazy<u64> =
Lazy::new(|| hash_string(LEFT_THUMBREST_TOUCH_PATH));
pub static RIGHT_SQUEEZE_CLICK_ID: Lazy<u64> = Lazy::new(|| hash_string(RIGHT_SQUEEZE_CLICK_PATH));
pub static RIGHT_SQUEEZE_VALUE_ID: Lazy<u64> = Lazy::new(|| hash_string(RIGHT_SQUEEZE_VALUE_PATH));
pub static RIGHT_TRIGGER_CLICK_ID: Lazy<u64> = Lazy::new(|| hash_string(RIGHT_TRIGGER_CLICK_PATH));
pub static RIGHT_TRIGGER_VALUE_ID: Lazy<u64> = Lazy::new(|| hash_string(RIGHT_TRIGGER_VALUE_PATH));
pub static RIGHT_TRIGGER_TOUCH_ID: Lazy<u64> = Lazy::new(|| hash_string(RIGHT_TRIGGER_TOUCH_PATH));
pub static RIGHT_THUMBSTICK_X_ID: Lazy<u64> = Lazy::new(|| hash_string(RIGHT_THUMBSTICK_X_PATH));
pub static RIGHT_THUMBSTICK_Y_ID: Lazy<u64> = Lazy::new(|| hash_string(RIGHT_THUMBSTICK_Y_PATH));
pub static RIGHT_THUMBSTICK_CLICK_ID: Lazy<u64> =
Lazy::new(|| hash_string(RIGHT_THUMBSTICK_CLICK_PATH));
pub static RIGHT_THUMBSTICK_TOUCH_ID: Lazy<u64> =
Lazy::new(|| hash_string(RIGHT_THUMBSTICK_TOUCH_PATH));
pub static RIGHT_THUMBREST_TOUCH_ID: Lazy<u64> =
Lazy::new(|| hash_string(RIGHT_THUMBREST_TOUCH_PATH));

View File

@ -26,44 +26,10 @@ enum ALVR_ENCODER_QUALITY_PRESET {
};
enum ALVR_INPUT {
ALVR_INPUT_SYSTEM_CLICK,
ALVR_INPUT_APPLICATION_MENU_CLICK,
ALVR_INPUT_GRIP_CLICK,
ALVR_INPUT_GRIP_VALUE,
ALVR_INPUT_GRIP_TOUCH,
ALVR_INPUT_A_CLICK,
ALVR_INPUT_A_TOUCH,
ALVR_INPUT_B_CLICK,
ALVR_INPUT_B_TOUCH,
ALVR_INPUT_X_CLICK,
ALVR_INPUT_X_TOUCH,
ALVR_INPUT_Y_CLICK,
ALVR_INPUT_Y_TOUCH,
ALVR_INPUT_JOYSTICK_CLICK,
ALVR_INPUT_JOYSTICK_X,
ALVR_INPUT_JOYSTICK_Y,
ALVR_INPUT_JOYSTICK_TOUCH,
ALVR_INPUT_BACK_CLICK,
ALVR_INPUT_GUIDE_CLICK,
ALVR_INPUT_START_CLICK,
ALVR_INPUT_TRIGGER_CLICK,
ALVR_INPUT_TRIGGER_VALUE,
ALVR_INPUT_TRIGGER_TOUCH,
ALVR_INPUT_TRACKPAD_X,
ALVR_INPUT_TRACKPAD_Y,
ALVR_INPUT_TRACKPAD_CLICK,
ALVR_INPUT_TRACKPAD_TOUCH,
ALVR_INPUT_THUMB_REST_TOUCH,
ALVR_INPUT_FINGER_INDEX,
ALVR_INPUT_FINGER_MIDDLE,
ALVR_INPUT_FINGER_RING,
ALVR_INPUT_FINGER_PINKY,
ALVR_INPUT_GRIP_FORCE,
ALVR_INPUT_TRACKPAD_FORCE,
ALVR_INPUT_MAX = ALVR_INPUT_TRACKPAD_FORCE,
ALVR_INPUT_COUNT = ALVR_INPUT_MAX + 1
};
#define ALVR_BUTTON_FLAG(input) (1ULL << input)

File diff suppressed because it is too large Load Diff

View File

@ -33,6 +33,8 @@ class Controller : public TrackedDevice, public vr::ITrackedDeviceServerDriver {
vr::VRInputComponentHandle_t getHapticComponent();
void RegisterButton(uint64_t id);
void SetButton(uint64_t id, FfiButtonValue value);
bool onPoseUpdate(float predictionS,
@ -40,12 +42,7 @@ class Controller : public TrackedDevice, public vr::ITrackedDeviceServerDriver {
const FfiHandSkeleton *hand,
unsigned int controllersTracked);
void GetBoneTransform(bool withController,
bool isLeftHand,
float thumbAnimationProgress,
float indexAnimationProgress,
uint64_t lastPoseTouch,
vr::VRBoneTransform_t outBoneTransform[]);
void GetBoneTransform(bool withController, vr::VRBoneTransform_t outBoneTransform[]);
vr::ETrackedDeviceClass getControllerDeviceClass();
@ -53,20 +50,21 @@ class Controller : public TrackedDevice, public vr::ITrackedDeviceServerDriver {
static const int SKELETON_BONE_COUNT = 31;
static const int ANIMATION_FRAME_COUNT = 15;
vr::VRInputComponentHandle_t m_handles[ALVR_INPUT_COUNT];
std::map<uint64_t, vr::VRInputComponentHandle_t> m_buttonHandles;
vr::VRInputComponentHandle_t m_compHaptic;
vr::VRInputComponentHandle_t m_compSkeleton = vr::k_ulInvalidInputComponentHandle;
vr::DriverPose_t m_pose;
// These variables are used for controller hand animation
// todo: move to rust
float m_thumbTouchAnimationProgress = 0;
float m_indexTouchAnimationProgress = 0;
uint64_t m_lastThumbTouch = 0;
uint64_t m_lastIndexTouch = 0;
uint64_t m_buttons = 0;
bool m_currentThumbTouch = false;
bool m_lastThumbTouch = false;
bool m_currentTriggerTouch = false;
bool m_lastTriggerTouch = false;
float m_triggerValue = 0;
float m_gripValue = 0;
float m_joystickX = 0;
float m_joystickY = 0;
};

View File

@ -5,101 +5,182 @@ uint64_t HEAD_ID;
uint64_t LEFT_HAND_ID;
uint64_t RIGHT_HAND_ID;
uint64_t MENU_CLICK_ID;
uint64_t A_CLICK_ID;
uint64_t A_TOUCH_ID;
uint64_t B_CLICK_ID;
uint64_t B_TOUCH_ID;
uint64_t X_CLICK_ID;
uint64_t X_TOUCH_ID;
uint64_t Y_CLICK_ID;
uint64_t Y_TOUCH_ID;
uint64_t LEFT_SQUEEZE_CLICK_ID;
uint64_t LEFT_SQUEEZE_VALUE_ID;
uint64_t LEFT_TRIGGER_CLICK_ID;
uint64_t LEFT_TRIGGER_VALUE_ID;
uint64_t LEFT_TRIGGER_TOUCH_ID;
uint64_t LEFT_THUMBSTICK_X_ID;
uint64_t LEFT_THUMBSTICK_Y_ID;
uint64_t LEFT_THUMBSTICK_CLICK_ID;
std::map<uint64_t, ButtonInfo> LEFT_CONTROLLER_BUTTON_MAPPING;
std::map<uint64_t, ButtonInfo> RIGHT_CONTROLLER_BUTTON_MAPPING;
uint64_t LEFT_A_TOUCH_ID;
uint64_t LEFT_B_TOUCH_ID;
uint64_t LEFT_X_TOUCH_ID;
uint64_t LEFT_Y_TOUCH_ID;
uint64_t LEFT_TRACKPAD_TOUCH_ID;
uint64_t LEFT_THUMBSTICK_TOUCH_ID;
uint64_t LEFT_THUMBREST_TOUCH_ID;
uint64_t RIGHT_SQUEEZE_CLICK_ID;
uint64_t RIGHT_SQUEEZE_VALUE_ID;
uint64_t RIGHT_TRIGGER_CLICK_ID;
uint64_t RIGHT_TRIGGER_VALUE_ID;
uint64_t RIGHT_TRIGGER_TOUCH_ID;
uint64_t RIGHT_THUMBSTICK_X_ID;
uint64_t RIGHT_THUMBSTICK_Y_ID;
uint64_t RIGHT_THUMBSTICK_CLICK_ID;
uint64_t LEFT_TRIGGER_TOUCH_ID;
uint64_t LEFT_TRIGGER_VALUE_ID;
uint64_t LEFT_SQUEEZE_TOUCH_ID;
uint64_t LEFT_SQUEEZE_VALUE_ID;
uint64_t RIGHT_A_TOUCH_ID;
uint64_t RIGHT_B_TOUCH_ID;
uint64_t RIGHT_TRACKPAD_TOUCH_ID;
uint64_t RIGHT_THUMBSTICK_TOUCH_ID;
uint64_t RIGHT_THUMBREST_TOUCH_ID;
std::vector<uint64_t> LEFT_CONTROLLER_BUTTON_IDS;
std::vector<uint64_t> RIGHT_CONTROLLER_BUTTON_IDS;
uint64_t RIGHT_TRIGGER_TOUCH_ID;
uint64_t RIGHT_TRIGGER_VALUE_ID;
uint64_t RIGHT_SQUEEZE_TOUCH_ID;
uint64_t RIGHT_SQUEEZE_VALUE_ID;
void init_paths() {
HEAD_ID = PathStringToHash("/user/head");
LEFT_HAND_ID = PathStringToHash("/user/hand/left");
RIGHT_HAND_ID = PathStringToHash("/user/hand/right");
MENU_CLICK_ID = PathStringToHash("/user/hand/left/input/menu/click");
A_CLICK_ID = PathStringToHash("/user/hand/right/input/a/click");
A_TOUCH_ID = PathStringToHash("/user/hand/right/input/a/touch");
B_CLICK_ID = PathStringToHash("/user/hand/right/input/b/click");
B_TOUCH_ID = PathStringToHash("/user/hand/right/input/b/touch");
X_CLICK_ID = PathStringToHash("/user/hand/left/input/x/click");
X_TOUCH_ID = PathStringToHash("/user/hand/left/input/x/touch");
Y_CLICK_ID = PathStringToHash("/user/hand/left/input/y/click");
Y_TOUCH_ID = PathStringToHash("/user/hand/left/input/y/touch");
LEFT_SQUEEZE_CLICK_ID = PathStringToHash("/user/hand/left/input/squeeze/click");
LEFT_SQUEEZE_VALUE_ID = PathStringToHash("/user/hand/left/input/squeeze/value");
LEFT_TRIGGER_CLICK_ID = PathStringToHash("/user/hand/left/input/trigger/click");
LEFT_TRIGGER_VALUE_ID = PathStringToHash("/user/hand/left/input/trigger/value");
LEFT_TRIGGER_TOUCH_ID = PathStringToHash("/user/hand/left/input/trigger/touch");
LEFT_THUMBSTICK_X_ID = PathStringToHash("/user/hand/left/input/thumbstick/x");
LEFT_THUMBSTICK_Y_ID = PathStringToHash("/user/hand/left/input/thumbstick/y");
LEFT_THUMBSTICK_CLICK_ID = PathStringToHash("/user/hand/left/input/thumbstick/click");
HEAD_ID = PathStringToHash("/user/head");
LEFT_HAND_ID = PathStringToHash("/user/hand/left");
RIGHT_HAND_ID = PathStringToHash("/user/hand/right");
LEFT_CONTROLLER_BUTTON_MAPPING.insert({PathStringToHash("/user/hand/left/input/system/click"),
{"/input/system/click", ButtonType::Binary}});
LEFT_CONTROLLER_BUTTON_MAPPING.insert({PathStringToHash("/user/hand/left/input/system/touch"),
{"/input/system/touch", ButtonType::Binary}});
LEFT_CONTROLLER_BUTTON_MAPPING.insert({PathStringToHash("/user/hand/left/input/menu/click"),
{"/input/application_menu/click", ButtonType::Binary}});
LEFT_CONTROLLER_BUTTON_MAPPING.insert({PathStringToHash("/user/hand/left/input/a/click"),
{"/input/a/click", ButtonType::Binary}});
LEFT_CONTROLLER_BUTTON_MAPPING.insert({PathStringToHash("/user/hand/left/input/a/touch"),
{"/input/a/touch", ButtonType::Binary}});
LEFT_CONTROLLER_BUTTON_MAPPING.insert({PathStringToHash("/user/hand/left/input/b/click"),
{"/input/b/click", ButtonType::Binary}});
LEFT_CONTROLLER_BUTTON_MAPPING.insert({PathStringToHash("/user/hand/left/input/b/touch"),
{"/input/b/touch", ButtonType::Binary}});
LEFT_CONTROLLER_BUTTON_MAPPING.insert({PathStringToHash("/user/hand/left/input/x/click"),
{"/input/x/click", ButtonType::Binary}});
LEFT_CONTROLLER_BUTTON_MAPPING.insert({PathStringToHash("/user/hand/left/input/x/touch"),
{"/input/x/touch", ButtonType::Binary}});
LEFT_CONTROLLER_BUTTON_MAPPING.insert({PathStringToHash("/user/hand/left/input/y/click"),
{"/input/y/click", ButtonType::Binary}});
LEFT_CONTROLLER_BUTTON_MAPPING.insert({PathStringToHash("/user/hand/left/input/y/touch"),
{"/input/y/touch", ButtonType::Binary}});
LEFT_CONTROLLER_BUTTON_MAPPING.insert({PathStringToHash("/user/hand/left/input/squeeze/click"),
{"/input/grip/click", ButtonType::Binary}});
LEFT_CONTROLLER_BUTTON_MAPPING.insert({PathStringToHash("/user/hand/left/input/squeeze/touch"),
{"/input/grip/touch", ButtonType::Binary}});
LEFT_CONTROLLER_BUTTON_MAPPING.insert({PathStringToHash("/user/hand/left/input/squeeze/value"),
{"/input/grip/click", ButtonType::ScalarOneSided}});
LEFT_CONTROLLER_BUTTON_MAPPING.insert({PathStringToHash("/user/hand/left/input/squeeze/force"),
{"/input/grip/force", ButtonType::ScalarOneSided}});
LEFT_CONTROLLER_BUTTON_MAPPING.insert({PathStringToHash("/user/hand/left/input/trigger/click"),
{"/input/trigger/click", ButtonType::Binary}});
LEFT_CONTROLLER_BUTTON_MAPPING.insert({PathStringToHash("/user/hand/left/input/trigger/value"),
{"/input/trigger/value", ButtonType::ScalarOneSided}});
LEFT_CONTROLLER_BUTTON_MAPPING.insert({PathStringToHash("/user/hand/left/input/trigger/touch"),
{"/input/trigger/touch", ButtonType::Binary}});
LEFT_CONTROLLER_BUTTON_MAPPING.insert({PathStringToHash("/user/hand/left/input/thumbstick/x"),
{"/input/joystick/x", ButtonType::ScalarTwoSided}});
LEFT_CONTROLLER_BUTTON_MAPPING.insert({PathStringToHash("/user/hand/left/input/thumbstick/y"),
{"/input/joystick/y", ButtonType::ScalarTwoSided}});
LEFT_CONTROLLER_BUTTON_MAPPING.insert(
{PathStringToHash("/user/hand/left/input/thumbstick/click"),
{"/input/joystick/click", ButtonType::Binary}});
LEFT_CONTROLLER_BUTTON_MAPPING.insert(
{PathStringToHash("/user/hand/left/input/thumbstick/click"),
{"/input/joystick/click", ButtonType::Binary}});
LEFT_CONTROLLER_BUTTON_MAPPING.insert(
{PathStringToHash("/user/hand/left/input/thumbstick/touch"),
{"/input/joystick/touch", ButtonType::Binary}});
LEFT_CONTROLLER_BUTTON_MAPPING.insert({PathStringToHash("/user/hand/left/input/trackpad/x"),
{"/input/trackpad/x", ButtonType::ScalarTwoSided}});
LEFT_CONTROLLER_BUTTON_MAPPING.insert({PathStringToHash("/user/hand/left/input/trackpad/y"),
{"/input/trackpad/y", ButtonType::ScalarTwoSided}});
LEFT_CONTROLLER_BUTTON_MAPPING.insert({PathStringToHash("/user/hand/left/input/trackpad/click"),
{"/input/trackpad/click", ButtonType::Binary}});
LEFT_CONTROLLER_BUTTON_MAPPING.insert({PathStringToHash("/user/hand/left/input/trackpad/force"),
{"/input/trackpad/force", ButtonType::ScalarOneSided}});
LEFT_CONTROLLER_BUTTON_MAPPING.insert({PathStringToHash("/user/hand/left/input/trackpad/touch"),
{"/input/trackpad/touch", ButtonType::Binary}});
LEFT_CONTROLLER_BUTTON_MAPPING.insert(
{PathStringToHash("/user/hand/left/input/thumbrest/touch"),
{"/input/thumbrest/touch", ButtonType::Binary}});
RIGHT_CONTROLLER_BUTTON_MAPPING.insert({PathStringToHash("/user/hand/right/input/system/click"),
{"/input/system/click", ButtonType::Binary}});
RIGHT_CONTROLLER_BUTTON_MAPPING.insert({PathStringToHash("/user/hand/right/input/system/touch"),
{"/input/system/touch", ButtonType::Binary}});
RIGHT_CONTROLLER_BUTTON_MAPPING.insert({PathStringToHash("/user/hand/right/input/menu/click"),
{"/input/application_menu/click", ButtonType::Binary}});
RIGHT_CONTROLLER_BUTTON_MAPPING.insert({PathStringToHash("/user/hand/right/input/a/click"),
{"/input/a/click", ButtonType::Binary}});
RIGHT_CONTROLLER_BUTTON_MAPPING.insert({PathStringToHash("/user/hand/right/input/a/touch"),
{"/input/a/touch", ButtonType::Binary}});
RIGHT_CONTROLLER_BUTTON_MAPPING.insert({PathStringToHash("/user/hand/right/input/b/click"),
{"/input/b/click", ButtonType::Binary}});
RIGHT_CONTROLLER_BUTTON_MAPPING.insert({PathStringToHash("/user/hand/right/input/b/touch"),
{"/input/b/touch", ButtonType::Binary}});
RIGHT_CONTROLLER_BUTTON_MAPPING.insert(
{PathStringToHash("/user/hand/right/input/squeeze/click"),
{"/input/grip/click", ButtonType::Binary}});
RIGHT_CONTROLLER_BUTTON_MAPPING.insert(
{PathStringToHash("/user/hand/right/input/squeeze/touch"),
{"/input/grip/touch", ButtonType::Binary}});
RIGHT_CONTROLLER_BUTTON_MAPPING.insert(
{PathStringToHash("/user/hand/right/input/squeeze/value"),
{"/input/grip/value", ButtonType::ScalarOneSided}});
RIGHT_CONTROLLER_BUTTON_MAPPING.insert(
{PathStringToHash("/user/hand/right/input/squeeze/force"),
{"/input/grip/force", ButtonType::ScalarOneSided}});
RIGHT_CONTROLLER_BUTTON_MAPPING.insert(
{PathStringToHash("/user/hand/right/input/trigger/click"),
{"/input/trigger/click", ButtonType::Binary}});
RIGHT_CONTROLLER_BUTTON_MAPPING.insert(
{PathStringToHash("/user/hand/right/input/trigger/value"),
{"/input/trigger/value", ButtonType::ScalarOneSided}});
RIGHT_CONTROLLER_BUTTON_MAPPING.insert(
{PathStringToHash("/user/hand/right/input/trigger/touch"),
{"/input/trigger/touch", ButtonType::Binary}});
RIGHT_CONTROLLER_BUTTON_MAPPING.insert({PathStringToHash("/user/hand/right/input/thumbstick/x"),
{"/input/joystick/x", ButtonType::ScalarTwoSided}});
RIGHT_CONTROLLER_BUTTON_MAPPING.insert({PathStringToHash("/user/hand/right/input/thumbstick/y"),
{"/input/joystick/y", ButtonType::ScalarTwoSided}});
RIGHT_CONTROLLER_BUTTON_MAPPING.insert(
{PathStringToHash("/user/hand/right/input/thumbstick/click"),
{"/input/joystick/click", ButtonType::Binary}});
RIGHT_CONTROLLER_BUTTON_MAPPING.insert(
{PathStringToHash("/user/hand/right/input/thumbstick/touch"),
{"/input/joystick/touch", ButtonType::Binary}});
RIGHT_CONTROLLER_BUTTON_MAPPING.insert({PathStringToHash("/user/hand/right/input/trackpad/x"),
{"/input/trackpad/x", ButtonType::ScalarTwoSided}});
RIGHT_CONTROLLER_BUTTON_MAPPING.insert({PathStringToHash("/user/hand/right/input/trackpad/y"),
{"/input/trackpad/y", ButtonType::ScalarTwoSided}});
RIGHT_CONTROLLER_BUTTON_MAPPING.insert(
{PathStringToHash("/user/hand/right/input/trackpad/click"),
{"/input/trackpad/click", ButtonType::Binary}});
LEFT_CONTROLLER_BUTTON_MAPPING.insert(
{PathStringToHash("/user/hand/right/input/trackpad/force"),
{"/input/trackpad/force", ButtonType::ScalarOneSided}});
RIGHT_CONTROLLER_BUTTON_MAPPING.insert(
{PathStringToHash("/user/hand/right/input/trackpad/touch"),
{"/input/trackpad/touch", ButtonType::Binary}});
RIGHT_CONTROLLER_BUTTON_MAPPING.insert(
{PathStringToHash("/user/hand/right/input/thumbrest/touch"),
{"/input/thumbrest/touch", ButtonType::Binary}});
LEFT_A_TOUCH_ID = PathStringToHash("/user/hand/left/input/a/touch");
LEFT_B_TOUCH_ID = PathStringToHash("/user/hand/left/input/b/touch");
LEFT_X_TOUCH_ID = PathStringToHash("/user/hand/left/input/x/touch");
LEFT_Y_TOUCH_ID = PathStringToHash("/user/hand/left/input/y/touch");
LEFT_TRACKPAD_TOUCH_ID = PathStringToHash("/user/hand/left/input/trackpad/touch");
LEFT_THUMBSTICK_TOUCH_ID = PathStringToHash("/user/hand/left/input/thumbstick/touch");
LEFT_THUMBREST_TOUCH_ID = PathStringToHash("/user/hand/left/input/thumbrest/touch");
RIGHT_SQUEEZE_CLICK_ID = PathStringToHash("/user/hand/right/input/squeeze/click");
RIGHT_SQUEEZE_VALUE_ID = PathStringToHash("/user/hand/right/input/squeeze/value");
RIGHT_TRIGGER_CLICK_ID = PathStringToHash("/user/hand/right/input/trigger/click");
RIGHT_TRIGGER_VALUE_ID = PathStringToHash("/user/hand/right/input/trigger/value");
RIGHT_TRIGGER_TOUCH_ID = PathStringToHash("/user/hand/right/input/trigger/touch");
RIGHT_THUMBSTICK_X_ID = PathStringToHash("/user/hand/right/input/thumbstick/x");
RIGHT_THUMBSTICK_Y_ID = PathStringToHash("/user/hand/right/input/thumbstick/y");
RIGHT_THUMBSTICK_CLICK_ID = PathStringToHash("/user/hand/right/input/thumbstick/click");
LEFT_TRIGGER_TOUCH_ID = PathStringToHash("/user/hand/left/input/trigger/touch");
LEFT_TRIGGER_VALUE_ID = PathStringToHash("/user/hand/left/input/trigger/value");
LEFT_SQUEEZE_TOUCH_ID = PathStringToHash("/user/hand/left/input/squeeze/touch");
LEFT_SQUEEZE_VALUE_ID = PathStringToHash("/user/hand/left/input/squeeze/value");
RIGHT_A_TOUCH_ID = PathStringToHash("/user/hand/right/input/a/touch");
RIGHT_B_TOUCH_ID = PathStringToHash("/user/hand/right/input/b/touch");
RIGHT_TRACKPAD_TOUCH_ID = PathStringToHash("/user/hand/right/input/trackpad/touch");
RIGHT_THUMBSTICK_TOUCH_ID = PathStringToHash("/user/hand/right/input/thumbstick/touch");
RIGHT_THUMBREST_TOUCH_ID = PathStringToHash("/user/hand/right/input/thumbrest/touch");
LEFT_CONTROLLER_BUTTON_IDS.push_back(MENU_CLICK_ID);
LEFT_CONTROLLER_BUTTON_IDS.push_back(X_CLICK_ID);
LEFT_CONTROLLER_BUTTON_IDS.push_back(X_TOUCH_ID);
LEFT_CONTROLLER_BUTTON_IDS.push_back(Y_CLICK_ID);
LEFT_CONTROLLER_BUTTON_IDS.push_back(Y_TOUCH_ID);
LEFT_CONTROLLER_BUTTON_IDS.push_back(LEFT_SQUEEZE_CLICK_ID);
LEFT_CONTROLLER_BUTTON_IDS.push_back(LEFT_SQUEEZE_VALUE_ID);
LEFT_CONTROLLER_BUTTON_IDS.push_back(LEFT_TRIGGER_CLICK_ID);
LEFT_CONTROLLER_BUTTON_IDS.push_back(LEFT_TRIGGER_VALUE_ID);
LEFT_CONTROLLER_BUTTON_IDS.push_back(LEFT_TRIGGER_TOUCH_ID);
LEFT_CONTROLLER_BUTTON_IDS.push_back(LEFT_THUMBSTICK_X_ID);
LEFT_CONTROLLER_BUTTON_IDS.push_back(LEFT_THUMBSTICK_Y_ID);
LEFT_CONTROLLER_BUTTON_IDS.push_back(LEFT_THUMBSTICK_CLICK_ID);
LEFT_CONTROLLER_BUTTON_IDS.push_back(LEFT_THUMBSTICK_TOUCH_ID);
LEFT_CONTROLLER_BUTTON_IDS.push_back(LEFT_THUMBREST_TOUCH_ID);
RIGHT_CONTROLLER_BUTTON_IDS.push_back(A_CLICK_ID);
RIGHT_CONTROLLER_BUTTON_IDS.push_back(A_TOUCH_ID);
RIGHT_CONTROLLER_BUTTON_IDS.push_back(B_CLICK_ID);
RIGHT_CONTROLLER_BUTTON_IDS.push_back(B_TOUCH_ID);
RIGHT_CONTROLLER_BUTTON_IDS.push_back(RIGHT_SQUEEZE_CLICK_ID);
RIGHT_CONTROLLER_BUTTON_IDS.push_back(RIGHT_SQUEEZE_VALUE_ID);
RIGHT_CONTROLLER_BUTTON_IDS.push_back(RIGHT_TRIGGER_CLICK_ID);
RIGHT_CONTROLLER_BUTTON_IDS.push_back(RIGHT_TRIGGER_VALUE_ID);
RIGHT_CONTROLLER_BUTTON_IDS.push_back(RIGHT_TRIGGER_TOUCH_ID);
RIGHT_CONTROLLER_BUTTON_IDS.push_back(RIGHT_THUMBSTICK_X_ID);
RIGHT_CONTROLLER_BUTTON_IDS.push_back(RIGHT_THUMBSTICK_Y_ID);
RIGHT_CONTROLLER_BUTTON_IDS.push_back(RIGHT_THUMBSTICK_CLICK_ID);
RIGHT_CONTROLLER_BUTTON_IDS.push_back(RIGHT_THUMBSTICK_TOUCH_ID);
RIGHT_CONTROLLER_BUTTON_IDS.push_back(RIGHT_THUMBREST_TOUCH_ID);
RIGHT_TRIGGER_TOUCH_ID = PathStringToHash("/user/hand/right/input/trigger/touch");
RIGHT_TRIGGER_VALUE_ID = PathStringToHash("/user/hand/right/input/trigger/value");
RIGHT_SQUEEZE_TOUCH_ID = PathStringToHash("/user/hand/right/input/squeeze/touch");
RIGHT_SQUEEZE_VALUE_ID = PathStringToHash("/user/hand/right/input/squeeze/value");
}

View File

@ -1,43 +1,51 @@
#pragma once
#include <cstdint>
#include <vector>
// #include <vector>
#include <map>
#include "openvr_driver.h"
extern uint64_t HEAD_ID;
extern uint64_t LEFT_HAND_ID;
extern uint64_t RIGHT_HAND_ID;
extern uint64_t MENU_CLICK_ID;
extern uint64_t A_CLICK_ID;
extern uint64_t A_TOUCH_ID;
extern uint64_t B_CLICK_ID;
extern uint64_t B_TOUCH_ID;
extern uint64_t X_CLICK_ID;
extern uint64_t X_TOUCH_ID;
extern uint64_t Y_CLICK_ID;
extern uint64_t Y_TOUCH_ID;
extern uint64_t LEFT_SQUEEZE_CLICK_ID;
extern uint64_t LEFT_SQUEEZE_VALUE_ID;
extern uint64_t LEFT_TRIGGER_CLICK_ID;
extern uint64_t LEFT_TRIGGER_VALUE_ID;
extern uint64_t LEFT_TRIGGER_TOUCH_ID;
extern uint64_t LEFT_THUMBSTICK_X_ID;
extern uint64_t LEFT_THUMBSTICK_Y_ID;
extern uint64_t LEFT_THUMBSTICK_CLICK_ID;
enum class ButtonType {
Binary,
ScalarOneSided,
ScalarTwoSided,
};
struct ButtonInfo {
const char *steamvr_path;
ButtonType type;
};
// Map button ID to SteamVR button info
extern std::map<uint64_t, ButtonInfo> LEFT_CONTROLLER_BUTTON_MAPPING;
extern std::map<uint64_t, ButtonInfo> RIGHT_CONTROLLER_BUTTON_MAPPING;
void init_paths();
// These values are needed to determine the hand skeleton when holding a controller.
// todo: move inferred hand skeleton to rust
extern uint64_t LEFT_A_TOUCH_ID;
extern uint64_t LEFT_B_TOUCH_ID;
extern uint64_t LEFT_X_TOUCH_ID;
extern uint64_t LEFT_Y_TOUCH_ID;
extern uint64_t LEFT_TRACKPAD_TOUCH_ID;
extern uint64_t LEFT_THUMBSTICK_TOUCH_ID;
extern uint64_t LEFT_THUMBREST_TOUCH_ID;
extern uint64_t RIGHT_SQUEEZE_CLICK_ID;
extern uint64_t RIGHT_SQUEEZE_VALUE_ID;
extern uint64_t RIGHT_TRIGGER_CLICK_ID;
extern uint64_t RIGHT_TRIGGER_VALUE_ID;
extern uint64_t RIGHT_TRIGGER_TOUCH_ID;
extern uint64_t RIGHT_THUMBSTICK_X_ID;
extern uint64_t RIGHT_THUMBSTICK_Y_ID;
extern uint64_t RIGHT_THUMBSTICK_CLICK_ID;
extern uint64_t LEFT_TRIGGER_TOUCH_ID;
extern uint64_t LEFT_TRIGGER_VALUE_ID;
extern uint64_t LEFT_SQUEEZE_TOUCH_ID;
extern uint64_t LEFT_SQUEEZE_VALUE_ID;
extern uint64_t RIGHT_A_TOUCH_ID;
extern uint64_t RIGHT_B_TOUCH_ID;
extern uint64_t RIGHT_TRACKPAD_TOUCH_ID;
extern uint64_t RIGHT_THUMBSTICK_TOUCH_ID;
extern uint64_t RIGHT_THUMBREST_TOUCH_ID;
extern std::vector<uint64_t> LEFT_CONTROLLER_BUTTON_IDS;
extern std::vector<uint64_t> RIGHT_CONTROLLER_BUTTON_IDS;
void init_paths();
extern uint64_t RIGHT_TRIGGER_TOUCH_ID;
extern uint64_t RIGHT_TRIGGER_VALUE_ID;
extern uint64_t RIGHT_SQUEEZE_TOUCH_ID;
extern uint64_t RIGHT_SQUEEZE_VALUE_ID;

View File

@ -102,11 +102,7 @@ void Settings::Load() {
m_enableLinuxAsyncReprojection = config.get("linux_async_reprojection").get<bool>();
m_enableControllers = config.get("controllers_enabled").get<bool>();
m_controllerMode = (int32_t)config.get("controllers_mode_idx").get<int64_t>();
m_overrideTriggerThreshold = config.get("override_trigger_threshold").get<bool>();
m_triggerThreshold = config.get("trigger_threshold").get<double>();
m_overrideGripThreshold = config.get("override_grip_threshold").get<bool>();
m_gripThreshold = config.get("grip_threshold").get<double>();
m_controllerIsTracker = config.get("controller_is_tracker").get<bool>();
m_constantBitrate = v.get("session_settings")
.get("video")

View File

@ -79,11 +79,7 @@ class Settings {
bool m_enableLinuxAsyncReprojection;
bool m_enableControllers;
int m_controllerMode = 0;
bool m_overrideTriggerThreshold;
float m_triggerThreshold;
bool m_overrideGripThreshold;
float m_gripThreshold;
int m_controllerIsTracker = false;
bool m_constantBitrate;
};

View File

@ -193,6 +193,7 @@ void (*ReportComposed)(unsigned long long timestamp_ns, unsigned long long offse
FfiDynamicEncoderParams (*GetDynamicEncoderParams)();
unsigned long long (*GetSerialNumber)(unsigned long long deviceID, char *outString);
void (*SetOpenvrProps)(unsigned long long deviceID);
void (*RegisterButtons)(unsigned long long deviceID);
void (*WaitForVSync)();
void *CppEntryPoint(const char *interface_name, int *return_code) {
@ -280,6 +281,17 @@ void SetOpenvrProperty(unsigned long long deviceID, FfiOpenvrProperty prop) {
}
}
void RegisterButton(unsigned long long buttonID) {
if (g_driver_provider.left_controller &&
LEFT_CONTROLLER_BUTTON_MAPPING.find(buttonID) != LEFT_CONTROLLER_BUTTON_MAPPING.end()) {
g_driver_provider.left_controller->RegisterButton(buttonID);
} else if (g_driver_provider.right_controller &&
RIGHT_CONTROLLER_BUTTON_MAPPING.find(buttonID) !=
RIGHT_CONTROLLER_BUTTON_MAPPING.end()) {
g_driver_provider.right_controller->RegisterButton(buttonID);
}
}
void SetViewsConfig(FfiViewsConfig config) {
if (g_driver_provider.hmd) {
g_driver_provider.hmd->SetViewsConfig(config);
@ -297,16 +309,14 @@ void SetBattery(unsigned long long deviceID, float gauge_value, bool is_plugged)
}
}
void SetButton(unsigned long long path, FfiButtonValue value) {
void SetButton(unsigned long long buttonID, FfiButtonValue value) {
if (g_driver_provider.left_controller &&
std::find(LEFT_CONTROLLER_BUTTON_IDS.begin(), LEFT_CONTROLLER_BUTTON_IDS.end(), path) !=
LEFT_CONTROLLER_BUTTON_IDS.end()) {
g_driver_provider.left_controller->SetButton(path, value);
LEFT_CONTROLLER_BUTTON_MAPPING.find(buttonID) != LEFT_CONTROLLER_BUTTON_MAPPING.end()) {
g_driver_provider.left_controller->SetButton(buttonID, value);
} else if (g_driver_provider.right_controller &&
std::find(RIGHT_CONTROLLER_BUTTON_IDS.begin(),
RIGHT_CONTROLLER_BUTTON_IDS.end(),
path) != RIGHT_CONTROLLER_BUTTON_IDS.end()) {
g_driver_provider.right_controller->SetButton(path, value);
RIGHT_CONTROLLER_BUTTON_MAPPING.find(buttonID) !=
RIGHT_CONTROLLER_BUTTON_MAPPING.end()) {
g_driver_provider.right_controller->SetButton(buttonID, value);
}
}

View File

@ -122,6 +122,7 @@ extern "C" void (*ReportComposed)(unsigned long long timestamp_ns, unsigned long
extern "C" FfiDynamicEncoderParams (*GetDynamicEncoderParams)();
extern "C" unsigned long long (*GetSerialNumber)(unsigned long long deviceID, char *outString);
extern "C" void (*SetOpenvrProps)(unsigned long long deviceID);
extern "C" void (*RegisterButtons)(unsigned long long deviceID);
extern "C" void (*WaitForVSync)();
extern "C" void *CppEntryPoint(const char *pInterfaceName, int *pReturnCode);
@ -140,10 +141,11 @@ extern "C" void VideoErrorReportReceive();
extern "C" void ShutdownSteamvr();
extern "C" void SetOpenvrProperty(unsigned long long deviceID, FfiOpenvrProperty prop);
extern "C" void RegisterButton(unsigned long long buttonID);
extern "C" void SetChaperone(float areaWidth, float areaHeight);
extern "C" void SetViewsConfig(FfiViewsConfig config);
extern "C" void SetBattery(unsigned long long deviceID, float gauge_value, bool is_plugged);
extern "C" void SetButton(unsigned long long path, FfiButtonValue value);
extern "C" void SetButton(unsigned long long buttonID, FfiButtonValue value);
extern "C" void CaptureFrame();

View File

@ -1,45 +0,0 @@
use alvr_common::{once_cell::sync::Lazy, *};
use std::collections::HashMap;
pub static BUTTON_PATH_FROM_ID: Lazy<HashMap<u64, String>> = Lazy::new(|| {
[
(*HEAD_ENTER_CLICK_ID, HEAD_ENTER_CLICK_PATH.into()),
(*MENU_CLICK_ID, MENU_CLICK_PATH.into()),
(*A_CLICK_ID, A_CLICK_PATH.into()),
(*A_TOUCH_ID, A_TOUCH_PATH.into()),
(*B_CLICK_ID, B_CLICK_PATH.into()),
(*B_TOUCH_ID, B_TOUCH_PATH.into()),
(*X_CLICK_ID, X_CLICK_PATH.into()),
(*X_TOUCH_ID, X_TOUCH_PATH.into()),
(*Y_CLICK_ID, Y_CLICK_PATH.into()),
(*Y_TOUCH_ID, Y_TOUCH_PATH.into()),
(*LEFT_SQUEEZE_CLICK_ID, LEFT_SQUEEZE_CLICK_PATH.into()),
(*LEFT_SQUEEZE_VALUE_ID, LEFT_SQUEEZE_VALUE_PATH.into()),
(*LEFT_TRIGGER_CLICK_ID, LEFT_TRIGGER_CLICK_PATH.into()),
(*LEFT_TRIGGER_VALUE_ID, LEFT_TRIGGER_VALUE_PATH.into()),
(*LEFT_TRIGGER_TOUCH_ID, LEFT_TRIGGER_TOUCH_PATH.into()),
(*LEFT_THUMBSTICK_X_ID, LEFT_THUMBSTICK_X_PATH.into()),
(*LEFT_THUMBSTICK_Y_ID, LEFT_THUMBSTICK_Y_PATH.into()),
(*LEFT_THUMBSTICK_CLICK_ID, LEFT_THUMBSTICK_CLICK_PATH.into()),
(*LEFT_THUMBSTICK_TOUCH_ID, LEFT_THUMBSTICK_TOUCH_PATH.into()),
(*LEFT_THUMBREST_TOUCH_ID, LEFT_THUMBREST_TOUCH_PATH.into()),
(*RIGHT_SQUEEZE_CLICK_ID, RIGHT_SQUEEZE_CLICK_PATH.into()),
(*RIGHT_SQUEEZE_VALUE_ID, RIGHT_SQUEEZE_VALUE_PATH.into()),
(*RIGHT_TRIGGER_CLICK_ID, RIGHT_TRIGGER_CLICK_PATH.into()),
(*RIGHT_TRIGGER_VALUE_ID, RIGHT_TRIGGER_VALUE_PATH.into()),
(*RIGHT_TRIGGER_TOUCH_ID, RIGHT_TRIGGER_TOUCH_PATH.into()),
(*RIGHT_THUMBSTICK_X_ID, RIGHT_THUMBSTICK_X_PATH.into()),
(*RIGHT_THUMBSTICK_Y_ID, RIGHT_THUMBSTICK_Y_PATH.into()),
(
*RIGHT_THUMBSTICK_CLICK_ID,
RIGHT_THUMBSTICK_CLICK_PATH.into(),
),
(
*RIGHT_THUMBSTICK_TOUCH_ID,
RIGHT_THUMBSTICK_TOUCH_PATH.into(),
),
(*RIGHT_THUMBREST_TOUCH_ID, RIGHT_THUMBREST_TOUCH_PATH.into()),
]
.into_iter()
.collect()
});

View File

@ -1,14 +1,13 @@
use crate::{
bitrate::BitrateManager,
buttons::BUTTON_PATH_FROM_ID,
create_recording_file,
face_tracking::FaceTrackingSink,
haptics,
input_mapping::ButtonMappingManager,
sockets::WelcomeSocket,
statistics::StatisticsManager,
tracking::{self, TrackingManager},
FfiButtonValue, FfiFov, FfiViewsConfig, VideoPacket, BITRATE_MANAGER, DECODER_CONFIG,
SERVER_DATA_MANAGER, STATISTICS_MANAGER, VIDEO_MIRROR_SENDER, VIDEO_RECORDING_FILE,
FfiFov, FfiViewsConfig, VideoPacket, BITRATE_MANAGER, DECODER_CONFIG, SERVER_DATA_MANAGER,
STATISTICS_MANAGER, VIDEO_MIRROR_SENDER, VIDEO_RECORDING_FILE,
};
use alvr_audio::AudioDevice;
use alvr_common::{
@ -18,13 +17,14 @@ use alvr_common::{
once_cell::sync::Lazy,
parking_lot::Mutex,
settings_schema::Switch,
warn, AnyhowToCon, ConResult, ConnectionError, LazyMutOpt, RelaxedAtomic, ToCon,
DEVICE_ID_TO_PATH, HEAD_ID, LEFT_HAND_ID, RIGHT_HAND_ID,
warn, AnyhowToCon, ConResult, ConnectionError, LazyMutOpt, RelaxedAtomic, ToCon, BUTTON_INFO,
CONTROLLER_PROFILE_INFO, DEVICE_ID_TO_PATH, HEAD_ID, LEFT_HAND_ID,
QUEST_CONTROLLER_PROFILE_PATH, RIGHT_HAND_ID,
};
use alvr_events::{ButtonEvent, EventType, HapticsEvent, TrackingEvent};
use alvr_packets::{
ButtonValue, ClientConnectionResult, ClientControlPacket, ClientListAction, ClientStatistics,
Haptics, ServerControlPacket, StreamConfigPacket, Tracking, VideoPacketHeader, AUDIO, HAPTICS,
ClientConnectionResult, ClientControlPacket, ClientListAction, ClientStatistics, Haptics,
ServerControlPacket, StreamConfigPacket, Tracking, VideoPacketHeader, AUDIO, HAPTICS,
STATISTICS, TRACKING, VIDEO,
};
use alvr_session::{CodecType, ConnectionState, ControllersEmulationMode, FrameSize, OpenvrConfig};
@ -78,32 +78,11 @@ pub fn contruct_openvr_config() -> OpenvrConfig {
let old_config = data_manager_lock.session().openvr_config.clone();
let settings = data_manager_lock.settings().clone();
let mut controllers_mode_idx = 0;
let mut override_trigger_threshold = false;
let mut trigger_threshold = 0.0;
let mut override_grip_threshold = false;
let mut grip_threshold = 0.0;
let mut controller_is_tracker = false;
let controllers_enabled = if let Switch::Enabled(config) = settings.headset.controllers {
controllers_mode_idx = match config.emulation_mode {
ControllersEmulationMode::RiftSTouch => 1,
ControllersEmulationMode::ValveIndex => 3,
ControllersEmulationMode::ViveWand => 5,
ControllersEmulationMode::Quest2Touch => 7,
ControllersEmulationMode::ViveTracker => 9,
};
override_trigger_threshold =
if let Switch::Enabled(value) = config.trigger_threshold_override {
trigger_threshold = value;
true
} else {
false
};
override_grip_threshold = if let Switch::Enabled(value) = config.grip_threshold_override {
grip_threshold = value;
true
} else {
false
};
controller_is_tracker =
matches!(config.emulation_mode, ControllersEmulationMode::ViveTracker);
true
} else {
false
@ -171,11 +150,7 @@ pub fn contruct_openvr_config() -> OpenvrConfig {
.force_software_encoding,
sw_thread_count: settings.video.encoder_config.software.thread_count,
controllers_enabled,
controllers_mode_idx,
override_trigger_threshold,
trigger_threshold,
override_grip_threshold,
grip_threshold,
controller_is_tracker,
enable_foveated_rendering,
foveation_center_size_x,
foveation_center_size_y,
@ -852,6 +827,21 @@ fn try_connect(mut client_ips: HashMap<IpAddr, String>) -> ConResult {
});
let control_receive_thread = thread::spawn({
let mut controller_button_mapping_manager = if let Switch::Enabled(config) =
&SERVER_DATA_MANAGER.read().settings().headset.controllers
{
Some(ButtonMappingManager::new_automatic(
&CONTROLLER_PROFILE_INFO
.get(&alvr_common::hash_string(QUEST_CONTROLLER_PROFILE_PATH))
.unwrap()
.button_set,
&config.button_mapping_config,
))
} else {
None
};
// todo: gestures_button_mapping_manager...
let control_sender = Arc::clone(&control_sender);
let client_hostname = client_hostname.clone();
move || {
@ -897,6 +887,7 @@ fn try_connect(mut client_ips: HashMap<IpAddr, String>) -> ConResult {
unsafe { crate::RequestIDR() }
}
ClientControlPacket::VideoErrorReport => {
// legacy endpoint. todo: remove
if let Some(stats) = &mut *STATISTICS_MANAGER.lock() {
stats.report_packet_loss();
}
@ -940,9 +931,9 @@ fn try_connect(mut client_ips: HashMap<IpAddr, String>) -> ConResult {
entries
.iter()
.map(|e| ButtonEvent {
path: BUTTON_PATH_FROM_ID
path: BUTTON_INFO
.get(&e.path_id)
.cloned()
.map(|info| info.path.to_owned())
.unwrap_or_else(|| {
format!("Unknown (ID: {:#16x})", e.path_id)
}),
@ -953,25 +944,28 @@ fn try_connect(mut client_ips: HashMap<IpAddr, String>) -> ConResult {
}
}
for entry in entries {
let value = match entry.value {
ButtonValue::Binary(value) => FfiButtonValue {
type_: crate::FfiButtonType_BUTTON_TYPE_BINARY,
__bindgen_anon_1: crate::FfiButtonValue__bindgen_ty_1 {
binary: value.into(),
},
},
ButtonValue::Scalar(value) => FfiButtonValue {
type_: crate::FfiButtonType_BUTTON_TYPE_SCALAR,
__bindgen_anon_1: crate::FfiButtonValue__bindgen_ty_1 {
scalar: value,
},
},
if let Some(manager) = &mut controller_button_mapping_manager {
for entry in entries {
manager.report_button(entry.path_id, entry.value);
}
};
}
ClientControlPacket::ActiveInteractionProfile {
device_id: _,
profile_id,
} => {
controller_button_mapping_manager =
if let (Switch::Enabled(config), Some(profile_info)) = (
&SERVER_DATA_MANAGER.read().settings().headset.controllers,
CONTROLLER_PROFILE_INFO.get(&profile_id),
) {
Some(ButtonMappingManager::new_automatic(
&profile_info.button_set,
&config.button_mapping_config,
))
} else {
None
};
unsafe { crate::SetButton(entry.path_id, value) };
}
}
ClientControlPacket::Log { level, message } => {
info!("Client {client_hostname}: [{level:?}] {message}")
@ -1130,7 +1124,7 @@ pub extern "C" fn send_video(timestamp_ns: u64, buffer_ptr: *mut u8, len: i32, i
unsafe { crate::RequestIDR() };
if is_idr {
create_recording_file();
crate::create_recording_file();
*LAST_IDR_INSTANT.lock() = Instant::now();
}
}

View File

@ -0,0 +1,636 @@
use crate::{bindings::FfiButtonValue, SERVER_DATA_MANAGER};
use alvr_common::{once_cell::sync::Lazy, settings_schema::Switch, *};
use alvr_packets::ButtonValue;
use alvr_session::{AutomaticButtonMappingConfig, ControllersEmulationMode, HysteresisThreshold};
use std::{
collections::{HashMap, HashSet},
ops::Range,
};
pub static REGISTERED_BUTTON_SET: Lazy<HashSet<u64>> = Lazy::new(|| {
let data_manager_lock = SERVER_DATA_MANAGER.read();
let Switch::Enabled(controllers_config) = &data_manager_lock.settings().headset.controllers
else {
return HashSet::new();
};
let profile = match &controllers_config.emulation_mode {
ControllersEmulationMode::Quest2Touch => &QUEST_CONTROLLER_PROFILE_ID,
ControllersEmulationMode::ValveIndex => &INDEX_CONTROLLER_PROFILE_ID,
ControllersEmulationMode::ViveWand => &VIVE_CONTROLLER_PROFILE_ID,
ControllersEmulationMode::ViveTracker => return HashSet::new(),
};
CONTROLLER_PROFILE_INFO
.get(profile)
.unwrap()
.button_set
.clone()
});
pub struct BinaryToScalarStates {
off: f32,
on: f32,
}
pub enum MappingType {
Passthrough,
HysteresisThreshold(HysteresisThreshold),
BinaryToScalar(BinaryToScalarStates),
Remap(Range<f32>), // remaps 0..1 to custom range
}
pub struct BindingTarget {
destination: u64,
mapping_type: MappingType,
binary_conditions: Vec<u64>,
}
// Inputs relative to the same physical button
#[derive(Clone, Copy)]
pub struct ButtonInputs {
click: Option<u64>,
touch: Option<u64>,
value: Option<u64>,
force: Option<u64>,
}
fn click(click: u64) -> ButtonInputs {
ButtonInputs {
click: Some(click),
touch: None,
value: None,
force: None,
}
}
fn ct(set: &HashSet<u64>, click: u64, touch: u64) -> ButtonInputs {
ButtonInputs {
click: Some(click),
touch: set.contains(&touch).then_some(touch),
value: None,
force: None,
}
}
fn value(value: u64) -> ButtonInputs {
ButtonInputs {
click: None,
touch: None,
value: Some(value),
force: None,
}
}
fn ctv(set: &HashSet<u64>, click: u64, touch: u64, value: u64) -> ButtonInputs {
ButtonInputs {
click: set.contains(&click).then_some(click),
touch: set.contains(&touch).then_some(touch),
value: set.contains(&value).then_some(value),
force: None,
}
}
fn ctvf(set: &HashSet<u64>, click: u64, touch: u64, value: u64, force: u64) -> ButtonInputs {
ButtonInputs {
click: set.contains(&click).then_some(click),
touch: set.contains(&touch).then_some(touch),
value: set.contains(&value).then_some(value),
force: set.contains(&force).then_some(force),
}
}
fn passthrough(target: u64) -> BindingTarget {
BindingTarget {
destination: target,
mapping_type: MappingType::Passthrough,
binary_conditions: vec![],
}
}
fn binary_to_scalar(target: u64, map: BinaryToScalarStates) -> BindingTarget {
BindingTarget {
destination: target,
mapping_type: MappingType::BinaryToScalar(map),
binary_conditions: vec![],
}
}
fn hysteresis_threshold(target: u64, map: HysteresisThreshold) -> BindingTarget {
BindingTarget {
destination: target,
mapping_type: MappingType::HysteresisThreshold(map),
binary_conditions: vec![],
}
}
fn remap(target: u64, map: Range<f32>) -> BindingTarget {
BindingTarget {
destination: target,
mapping_type: MappingType::Remap(map),
binary_conditions: vec![],
}
}
// Map two buttons with eterogeneous inputs
fn map_button_pair_automatic(
source: ButtonInputs,
destination: ButtonInputs,
config: &AutomaticButtonMappingConfig,
) -> impl Iterator<Item = (u64, Vec<BindingTarget>)> {
let click_to_value = BinaryToScalarStates { off: 0.0, on: 1.0 };
let mut entries = vec![];
if let Some(source_click) = source.click {
let mut targets = vec![];
if let Some(destination_click) = destination.click {
targets.push(passthrough(destination_click));
}
if source.touch.is_none() {
if let Some(destination_touch) = destination.touch {
targets.push(passthrough(destination_touch));
}
}
if source.value.is_none() {
if let Some(destination_value) = destination.value {
targets.push(binary_to_scalar(destination_value, click_to_value));
}
}
entries.push((source_click, targets));
}
if let Some(source_touch) = source.touch {
let mut targets = vec![];
if let Some(destination_touch) = destination.touch {
targets.push(passthrough(destination_touch));
}
entries.push((source_touch, targets));
}
if let Some(source_value) = source.value {
let mut targets = vec![];
let mut remap_for_touch = false;
let mut remap_for_force = false;
if source.click.is_none() {
if let Some(destination_click) = destination.click {
targets.push(hysteresis_threshold(
destination_click,
config.click_threshold,
));
}
}
if source.touch.is_none() {
if let Some(destination_touch) = destination.touch {
targets.push(hysteresis_threshold(
destination_touch,
config.touch_threshold,
));
remap_for_touch = true;
}
}
if source.force.is_none() {
if let Some(destination_force) = destination.force {
targets.push(remap(destination_force, config.force_threshold..1.0));
remap_for_force = true;
}
}
if let Some(destination_value) = destination.value {
if !remap_for_touch && !remap_for_force {
targets.push(passthrough(destination_value));
} else {
let low = if remap_for_touch {
config.touch_threshold.value
} else {
0.0
};
let high = if remap_for_force {
config.force_threshold
} else {
1.0
};
targets.push(remap(destination_value, low..high));
}
}
entries.push((source_value, targets));
}
entries.into_iter()
}
pub fn automatic_bindings(
source_set: &HashSet<u64>,
destination_set: &HashSet<u64>,
config: &AutomaticButtonMappingConfig,
) -> HashMap<u64, Vec<BindingTarget>> {
let s_set = source_set;
let d_set = destination_set;
let mut bindings = HashMap::new();
// Menu buttons
if s_set.contains(&*LEFT_MENU_CLICK_ID) {
let click = click(*LEFT_MENU_CLICK_ID);
if d_set.contains(&*LEFT_MENU_CLICK_ID) {
bindings.extend(map_button_pair_automatic(click, click, config));
} else if d_set.contains(&*LEFT_SYSTEM_CLICK_ID) {
bindings.extend(map_button_pair_automatic(
click,
ct(s_set, *LEFT_SYSTEM_CLICK_ID, *LEFT_SYSTEM_TOUCH_ID),
config,
));
}
}
if s_set.contains(&*RIGHT_MENU_CLICK_ID) {
let click = click(*RIGHT_MENU_CLICK_ID);
if d_set.contains(&*RIGHT_MENU_CLICK_ID) {
bindings.extend(map_button_pair_automatic(click, click, config));
} else if d_set.contains(&*RIGHT_SYSTEM_CLICK_ID) {
bindings.extend(map_button_pair_automatic(
click,
ct(s_set, *RIGHT_SYSTEM_CLICK_ID, *RIGHT_SYSTEM_TOUCH_ID),
config,
));
}
}
// A/X buttons
if s_set.contains(&*LEFT_X_CLICK_ID) {
let source = ct(s_set, *LEFT_X_CLICK_ID, *LEFT_X_TOUCH_ID);
if d_set.contains(&*LEFT_X_CLICK_ID) {
bindings.extend(map_button_pair_automatic(
source,
ct(d_set, *LEFT_X_CLICK_ID, *LEFT_X_TOUCH_ID),
config,
));
} else if d_set.contains(&*LEFT_A_CLICK_ID) {
bindings.extend(map_button_pair_automatic(
source,
ct(d_set, *LEFT_A_CLICK_ID, *LEFT_A_TOUCH_ID),
config,
));
} else if d_set.contains(&*LEFT_TRACKPAD_CLICK_ID) {
bindings.extend(map_button_pair_automatic(
source,
ct(d_set, *LEFT_TRACKPAD_CLICK_ID, *LEFT_TRACKPAD_TOUCH_ID),
config,
));
}
}
if s_set.contains(&*RIGHT_A_CLICK_ID) {
let source = ct(s_set, *RIGHT_A_CLICK_ID, *RIGHT_A_TOUCH_ID);
if d_set.contains(&*RIGHT_A_CLICK_ID) {
bindings.extend(map_button_pair_automatic(
source,
ct(d_set, *RIGHT_A_CLICK_ID, *RIGHT_A_TOUCH_ID),
config,
));
} else if d_set.contains(&*RIGHT_TRACKPAD_CLICK_ID) {
bindings.extend(map_button_pair_automatic(
source,
ct(d_set, *RIGHT_TRACKPAD_CLICK_ID, *RIGHT_TRACKPAD_TOUCH_ID),
config,
));
}
}
// B/Y buttons
if s_set.contains(&*LEFT_Y_CLICK_ID) {
let source = ct(s_set, *LEFT_Y_CLICK_ID, *LEFT_Y_TOUCH_ID);
if d_set.contains(&*LEFT_Y_CLICK_ID) {
bindings.extend(map_button_pair_automatic(
source,
ct(d_set, *LEFT_Y_CLICK_ID, *LEFT_Y_TOUCH_ID),
config,
));
} else if d_set.contains(&*LEFT_B_CLICK_ID) {
bindings.extend(map_button_pair_automatic(
source,
ct(d_set, *LEFT_B_CLICK_ID, *LEFT_B_TOUCH_ID),
config,
));
}
}
if s_set.contains(&*RIGHT_B_CLICK_ID) && d_set.contains(&*RIGHT_B_CLICK_ID) {
bindings.extend(map_button_pair_automatic(
ct(s_set, *RIGHT_B_CLICK_ID, *RIGHT_B_TOUCH_ID),
ct(d_set, *RIGHT_B_CLICK_ID, *RIGHT_B_TOUCH_ID),
config,
));
}
// Squeeze buttons
if (s_set.contains(&*LEFT_SQUEEZE_CLICK_ID) || s_set.contains(&*LEFT_SQUEEZE_VALUE_ID))
&& (d_set.contains(&*LEFT_SQUEEZE_CLICK_ID) || d_set.contains(&*LEFT_SQUEEZE_VALUE_ID))
{
bindings.extend(map_button_pair_automatic(
ctvf(
s_set,
*LEFT_SQUEEZE_CLICK_ID,
*LEFT_SQUEEZE_TOUCH_ID,
*LEFT_SQUEEZE_VALUE_ID,
*LEFT_SQUEEZE_FORCE_ID,
),
ctvf(
d_set,
*LEFT_SQUEEZE_CLICK_ID,
*LEFT_SQUEEZE_TOUCH_ID,
*LEFT_SQUEEZE_VALUE_ID,
*LEFT_SQUEEZE_FORCE_ID,
),
config,
));
}
if (s_set.contains(&*RIGHT_SQUEEZE_CLICK_ID) || s_set.contains(&*RIGHT_SQUEEZE_VALUE_ID))
&& (d_set.contains(&*RIGHT_SQUEEZE_CLICK_ID) || d_set.contains(&*RIGHT_SQUEEZE_VALUE_ID))
{
bindings.extend(map_button_pair_automatic(
ctvf(
s_set,
*RIGHT_SQUEEZE_CLICK_ID,
*RIGHT_SQUEEZE_TOUCH_ID,
*RIGHT_SQUEEZE_VALUE_ID,
*RIGHT_SQUEEZE_FORCE_ID,
),
ctvf(
d_set,
*RIGHT_SQUEEZE_CLICK_ID,
*RIGHT_SQUEEZE_TOUCH_ID,
*RIGHT_SQUEEZE_VALUE_ID,
*RIGHT_SQUEEZE_FORCE_ID,
),
config,
));
}
// Trigger buttons
if (s_set.contains(&*LEFT_TRIGGER_CLICK_ID) || s_set.contains(&*LEFT_TRIGGER_VALUE_ID))
&& (d_set.contains(&*LEFT_TRIGGER_CLICK_ID) || d_set.contains(&*LEFT_TRIGGER_VALUE_ID))
{
bindings.extend(map_button_pair_automatic(
ctv(
s_set,
*LEFT_TRIGGER_CLICK_ID,
*LEFT_TRIGGER_TOUCH_ID,
*LEFT_TRIGGER_VALUE_ID,
),
ctv(
d_set,
*LEFT_TRIGGER_CLICK_ID,
*LEFT_TRIGGER_TOUCH_ID,
*LEFT_TRIGGER_VALUE_ID,
),
config,
));
}
if (s_set.contains(&*RIGHT_TRIGGER_CLICK_ID) || s_set.contains(&*RIGHT_TRIGGER_VALUE_ID))
&& (d_set.contains(&*RIGHT_TRIGGER_CLICK_ID) || d_set.contains(&*RIGHT_TRIGGER_VALUE_ID))
{
bindings.extend(map_button_pair_automatic(
ctv(
s_set,
*RIGHT_TRIGGER_CLICK_ID,
*RIGHT_TRIGGER_TOUCH_ID,
*RIGHT_TRIGGER_VALUE_ID,
),
ctv(
d_set,
*RIGHT_TRIGGER_CLICK_ID,
*RIGHT_TRIGGER_TOUCH_ID,
*RIGHT_TRIGGER_VALUE_ID,
),
config,
));
}
// Thumbsticks
if s_set.contains(&*LEFT_THUMBSTICK_X_ID) {
let x = value(*LEFT_THUMBSTICK_X_ID);
let y = value(*LEFT_THUMBSTICK_Y_ID);
if d_set.contains(&*LEFT_THUMBSTICK_X_ID) {
bindings.extend(map_button_pair_automatic(x, x, config));
bindings.extend(map_button_pair_automatic(y, y, config));
} else if d_set.contains(&*LEFT_TRACKPAD_X_ID) {
bindings.extend(map_button_pair_automatic(
x,
value(*LEFT_TRACKPAD_X_ID),
config,
));
bindings.extend(map_button_pair_automatic(
y,
value(*LEFT_TRACKPAD_Y_ID),
config,
));
}
}
if s_set.contains(&*LEFT_THUMBSTICK_CLICK_ID) {
let source = ct(s_set, *LEFT_THUMBSTICK_CLICK_ID, *LEFT_THUMBSTICK_TOUCH_ID);
if d_set.contains(&*LEFT_THUMBSTICK_CLICK_ID) {
bindings.extend(map_button_pair_automatic(
source,
ct(d_set, *LEFT_THUMBSTICK_CLICK_ID, *LEFT_THUMBSTICK_TOUCH_ID),
config,
));
} else if d_set.contains(&*LEFT_TRACKPAD_CLICK_ID) {
bindings.extend(map_button_pair_automatic(
source,
ct(d_set, *LEFT_TRACKPAD_CLICK_ID, *LEFT_TRACKPAD_TOUCH_ID),
config,
));
}
}
if s_set.contains(&*RIGHT_THUMBSTICK_X_ID) {
let x = value(*RIGHT_THUMBSTICK_X_ID);
let y = value(*RIGHT_THUMBSTICK_Y_ID);
if d_set.contains(&*RIGHT_THUMBSTICK_X_ID) {
bindings.extend(map_button_pair_automatic(x, x, config));
bindings.extend(map_button_pair_automatic(y, y, config));
} else if d_set.contains(&*RIGHT_TRACKPAD_X_ID) {
bindings.extend(map_button_pair_automatic(
x,
value(*RIGHT_TRACKPAD_X_ID),
config,
));
bindings.extend(map_button_pair_automatic(
y,
value(*RIGHT_TRACKPAD_Y_ID),
config,
));
}
}
if s_set.contains(&*RIGHT_THUMBSTICK_CLICK_ID) {
let source = ct(
s_set,
*RIGHT_THUMBSTICK_CLICK_ID,
*RIGHT_THUMBSTICK_TOUCH_ID,
);
if d_set.contains(&*RIGHT_THUMBSTICK_CLICK_ID) {
bindings.extend(map_button_pair_automatic(
source,
ct(
d_set,
*RIGHT_THUMBSTICK_CLICK_ID,
*RIGHT_THUMBSTICK_TOUCH_ID,
),
config,
));
} else if d_set.contains(&*RIGHT_TRACKPAD_CLICK_ID) {
bindings.extend(map_button_pair_automatic(
source,
ct(d_set, *RIGHT_TRACKPAD_CLICK_ID, *RIGHT_TRACKPAD_TOUCH_ID),
config,
));
}
}
// Thumbrests
if s_set.contains(&*LEFT_THUMBREST_TOUCH_ID) {
let source = value(*LEFT_THUMBREST_TOUCH_ID);
if d_set.contains(&*LEFT_THUMBREST_TOUCH_ID) {
bindings.extend(map_button_pair_automatic(source, source, config));
} else if d_set.contains(&*LEFT_TRACKPAD_TOUCH_ID) {
bindings.extend(map_button_pair_automatic(
source,
value(*LEFT_TRACKPAD_TOUCH_ID),
config,
));
}
}
if s_set.contains(&*RIGHT_THUMBREST_TOUCH_ID) {
let source = value(*RIGHT_THUMBREST_TOUCH_ID);
if d_set.contains(&*RIGHT_THUMBREST_TOUCH_ID) {
bindings.extend(map_button_pair_automatic(source, source, config));
} else if d_set.contains(&*RIGHT_TRACKPAD_TOUCH_ID) {
bindings.extend(map_button_pair_automatic(
source,
value(*RIGHT_TRACKPAD_TOUCH_ID),
config,
));
}
}
bindings
}
pub extern "C" fn register_buttons(device_id: u64) {
for id in &*REGISTERED_BUTTON_SET {
if let Some(info) = BUTTON_INFO.get(id) {
if info.device_id == device_id {
unsafe { crate::RegisterButton(*id) };
}
} else {
error!("Cannot register unrecognized button ID {id}");
}
}
}
pub struct ButtonMappingManager {
mappings: HashMap<u64, Vec<BindingTarget>>,
binary_source_states: HashMap<u64, bool>,
hysteresis_states: HashMap<u64, HashMap<u64, bool>>,
}
impl ButtonMappingManager {
pub fn new_automatic(source: &HashSet<u64>, config: &AutomaticButtonMappingConfig) -> Self {
Self {
mappings: automatic_bindings(source, &REGISTERED_BUTTON_SET, config),
binary_source_states: HashMap::new(),
hysteresis_states: HashMap::new(),
}
}
// pub fn new_manual(mappings: HashMap<u64, Vec<BindingTarget>>) -> Self {
// Self {
// mappings,
// binary_source_states: HashMap::new(),
// hysteresis_states: HashMap::new(),
// }
// }
// Apply any button changes that are mapped to this specific button
pub fn report_button(&mut self, source_id: u64, source_value: ButtonValue) {
if let ButtonValue::Binary(value) = source_value {
let val_ref = self.binary_source_states.entry(source_id).or_default();
if value != *val_ref {
*val_ref = value;
} else {
return;
}
}
if let Some(mappings) = self.mappings.get(&source_id) {
for mapping in mappings {
let destination_value = match (&mapping.mapping_type, source_value) {
(MappingType::Passthrough, value) => value,
(MappingType::HysteresisThreshold(threshold), ButtonValue::Scalar(value)) => {
let state = self
.hysteresis_states
.entry(source_id)
.or_default()
.entry(mapping.destination)
.or_default();
if *state && value < threshold.value - threshold.deviation {
*state = false;
} else if !*state && value > threshold.value + threshold.deviation {
*state = true;
} else {
// No change needed
return;
}
ButtonValue::Binary(*state)
}
(MappingType::BinaryToScalar(levels), ButtonValue::Binary(value)) => {
if value {
ButtonValue::Scalar(levels.on)
} else {
ButtonValue::Scalar(levels.off)
}
}
(MappingType::Remap(range), ButtonValue::Scalar(value)) => {
let value = (value - range.start) / (range.end - range.start);
ButtonValue::Scalar(value.clamp(0.0, 1.0))
}
_ => {
error!("Failed to map button!");
return;
}
};
for source_id in &mapping.binary_conditions {
if !self
.binary_source_states
.get(source_id)
.copied()
.unwrap_or(false)
{
return;
}
}
let destination_value = match destination_value {
ButtonValue::Binary(value) => FfiButtonValue {
type_: crate::FfiButtonType_BUTTON_TYPE_BINARY,
__bindgen_anon_1: crate::FfiButtonValue__bindgen_ty_1 {
binary: value.into(),
},
},
ButtonValue::Scalar(value) => FfiButtonValue {
type_: crate::FfiButtonType_BUTTON_TYPE_SCALAR,
__bindgen_anon_1: crate::FfiButtonValue__bindgen_ty_1 { scalar: value },
},
};
unsafe { crate::SetButton(mapping.destination, destination_value) };
}
} else {
let button_name = BUTTON_INFO
.get(&source_id)
.map(|info| info.path)
.unwrap_or("Unknown");
info!("Received button not mapped: {button_name}");
}
}
}

View File

@ -1,8 +1,8 @@
mod bitrate;
mod buttons;
mod connection;
mod face_tracking;
mod haptics;
mod input_mapping;
mod logging_backend;
mod openvr_props;
mod sockets;
@ -442,6 +442,7 @@ pub unsafe extern "C" fn HmdDriverFactory(
ReportComposed = Some(report_composed);
GetSerialNumber = Some(openvr_props::get_serial_number);
SetOpenvrProps = Some(openvr_props::set_device_openvr_props);
RegisterButtons = Some(input_mapping::register_buttons);
GetDynamicEncoderParams = Some(get_dynamic_encoder_params);
WaitForVSync = Some(wait_for_vsync);

View File

@ -70,7 +70,6 @@ fn serial_number(device_id: u64) -> String {
} else if device_id == *LEFT_HAND_ID || device_id == *RIGHT_HAND_ID {
if let Switch::Enabled(controllers) = &settings.headset.controllers {
let serial_number = match &controllers.emulation_mode {
ControllersEmulationMode::RiftSTouch => "1WMGH000XX0000_Controller",
ControllersEmulationMode::ValveIndex => "ALVR Remote Controller",
ControllersEmulationMode::ViveWand => "ALVR Remote Controller",
ControllersEmulationMode::Quest2Touch => "1WMHH000X00000_Controller",
@ -231,22 +230,22 @@ pub extern "C" fn set_device_openvr_props(device_id: u64) {
};
match config.emulation_mode {
ControllersEmulationMode::RiftSTouch => {
ControllersEmulationMode::Quest2Touch => {
set_string(TrackingSystemName, "oculus");
set_string(ManufacturerName, "Oculus");
if device_id == *LEFT_HAND_ID {
set_string(ModelNumber, "Oculus Rift S (Left Controller)");
set_string(RenderModelName, "oculus_rifts_controller_left");
set_string(ModelNumber, "Miramar (Left Controller)");
set_string(RenderModelName, "oculus_quest2_controller_left");
set_string(
RegisteredDeviceType,
"oculus/1WMGH000XX0000_Controller_Left",
"oculus/1WMHH000X00000_Controller_Left",
);
} else if device_id == *RIGHT_HAND_ID {
set_string(ModelNumber, "Oculus Rift S (Right Controller)");
set_string(RenderModelName, "oculus_rifts_controller_right");
set_string(ModelNumber, "Miramar (Right Controller)");
set_string(RenderModelName, "oculus_quest2_controller_right");
set_string(
RegisteredDeviceType,
"oculus/1WMGH000XX0000_Controller_Right",
"oculus/1WMHH000X00000_Controller_Right",
);
}
set_string(ControllerType, "oculus_touch");
@ -348,79 +347,6 @@ pub extern "C" fn set_device_openvr_props(device_id: u64) {
set_string(ControllerType, "vive_controller");
set_string(InputProfilePath, "{oculus}/input/touch_profile.json");
}
ControllersEmulationMode::Quest2Touch => {
set_string(TrackingSystemName, "oculus");
set_string(ManufacturerName, "Oculus");
if device_id == *LEFT_HAND_ID {
set_string(ModelNumber, "Miramar (Left Controller)");
set_string(RenderModelName, "oculus_quest2_controller_left");
set_string(
RegisteredDeviceType,
"oculus/1WMHH000X00000_Controller_Left",
);
} else if device_id == *RIGHT_HAND_ID {
set_string(ModelNumber, "Miramar (Right Controller)");
set_string(RenderModelName, "oculus_quest2_controller_right");
set_string(
RegisteredDeviceType,
"oculus/1WMHH000X00000_Controller_Right",
);
}
set_string(ControllerType, "oculus_touch");
set_string(InputProfilePath, "{oculus}/input/touch_profile.json");
if device_id == *LEFT_HAND_ID {
set_string(
NamedIconPathDeviceOff,
"{oculus}/icons/rifts_left_controller_off.png",
);
set_string(
NamedIconPathDeviceSearching,
"{oculus}/icons/rifts_left_controller_searching.gif",
);
set_string(
NamedIconPathDeviceSearchingAlert,
"{oculus}/icons/rifts_left_controller_searching_alert.gif",
);
set_string(
NamedIconPathDeviceReady,
"{oculus}/icons/rifts_left_controller_ready.png",
);
set_string(
NamedIconPathDeviceReadyAlert,
"{oculus}/icons/rifts_left_controller_ready_alert.png",
);
set_string(
NamedIconPathDeviceAlertLow,
"{oculus}/icons/rifts_left_controller_ready_low.png",
);
} else if device_id == *RIGHT_HAND_ID {
set_string(
NamedIconPathDeviceOff,
"{oculus}/icons/rifts_right_controller_off.png",
);
set_string(
NamedIconPathDeviceSearching,
"{oculus}/icons/rifts_right_controller_searching.gif",
);
set_string(
NamedIconPathDeviceSearchingAlert,
"{oculus}/icons/rifts_right_controller_searching_alert.gif",
);
set_string(
NamedIconPathDeviceReady,
"{oculus}/icons/rifts_right_controller_ready.png",
);
set_string(
NamedIconPathDeviceReadyAlert,
"{oculus}/icons/rifts_right_controller_ready_alert.png",
);
set_string(
NamedIconPathDeviceAlertLow,
"{oculus}/icons/rifts_right_controller_ready_low.png",
);
}
}
ControllersEmulationMode::ViveTracker => {
set_string(TrackingSystemName, "lighthouse");
set_string(RenderModelName, "{htc}vr_tracker_vive_1_0");

View File

@ -58,12 +58,8 @@ pub struct OpenvrConfig {
pub entropy_coding: u32,
pub force_sw_encoding: bool,
pub sw_thread_count: u32,
pub controllers_mode_idx: i32,
pub controller_is_tracker: bool,
pub controllers_enabled: bool,
pub override_trigger_threshold: bool,
pub trigger_threshold: f32,
pub override_grip_threshold: bool,
pub grip_threshold: f32,
pub enable_foveated_rendering: bool,
pub foveation_center_size_x: f32,
pub foveation_center_size_y: f32,

View File

@ -600,16 +600,29 @@ pub struct FaceTrackingConfig {
#[derive(SettingsSchema, Serialize, Deserialize, Clone)]
pub enum ControllersEmulationMode {
#[schema(strings(display_name = "Rift S Touch"))]
RiftSTouch,
#[schema(strings(display_name = "Quest 2 Touch"))]
Quest2Touch,
#[schema(strings(display_name = "Valve Index"))]
ValveIndex,
ViveWand,
#[schema(strings(display_name = "Quest 2 Touch"))]
Quest2Touch,
ViveTracker,
}
#[derive(SettingsSchema, Serialize, Deserialize, Clone, Copy)]
pub struct HysteresisThreshold {
#[schema(gui(slider(min = 0.0, max = 1.0, step = 0.01)))]
pub value: f32,
#[schema(gui(slider(min = 0.0, max = 1.0, step = 0.01)))]
pub deviation: f32,
}
#[derive(SettingsSchema, Serialize, Deserialize, Clone)]
pub struct AutomaticButtonMappingConfig {
pub click_threshold: HysteresisThreshold,
pub touch_threshold: HysteresisThreshold,
pub force_threshold: f32,
}
#[derive(SettingsSchema, Serialize, Deserialize, Clone)]
pub struct HapticsConfig {
#[schema(flag = "real-time")]
@ -639,6 +652,8 @@ pub struct ControllersConfig {
#[schema(flag = "steamvr-restart")]
pub extra_openvr_props: Vec<OpenvrPropEntry>,
pub button_mapping_config: AutomaticButtonMappingConfig,
#[schema(strings(
display_name = "Prediction",
help = r"Higher values make the controllers track smoother.
@ -676,14 +691,6 @@ Currently this cannot be reliably estimated automatically. The correct value sho
#[schema(gui(slider(min = -180.0, max = 180.0, step = 1.0)), suffix = "°")]
pub left_hand_tracking_rotation_offset: [f32; 3],
#[schema(flag = "steamvr-restart")]
#[schema(gui(slider(min = 0.01, max = 1.0, step = 0.01)))]
pub trigger_threshold_override: Switch<f32>,
#[schema(flag = "steamvr-restart")]
#[schema(gui(slider(min = 0.01, max = 1.0, step = 0.01)))]
pub grip_threshold_override: Switch<f32>,
#[schema(flag = "real-time")]
pub haptics: Switch<HapticsConfig>,
}
@ -1228,6 +1235,20 @@ pub fn session_settings_default() -> SettingsDefault {
},
tracked: true,
extra_openvr_props: default_custom_openvr_props,
button_mapping_config: AutomaticButtonMappingConfigDefault {
gui_collapsed: true,
click_threshold: HysteresisThresholdDefault {
gui_collapsed: false,
value: 0.5,
deviation: 0.05,
},
touch_threshold: HysteresisThresholdDefault {
gui_collapsed: false,
value: 0.1,
deviation: 0.05,
},
force_threshold: 0.2,
},
steamvr_pipeline_frames: 3.0,
linear_velocity_cutoff: 0.05,
angular_velocity_cutoff: 10.0,
@ -1235,14 +1256,6 @@ pub fn session_settings_default() -> SettingsDefault {
left_controller_rotation_offset: [-20.0, 0.0, 0.0],
left_hand_tracking_position_offset: [0.04, -0.02, -0.13],
left_hand_tracking_rotation_offset: [0.0, -45.0, -90.0],
trigger_threshold_override: SwitchDefault {
enabled: false,
content: 0.1,
},
grip_threshold_override: SwitchDefault {
enabled: false,
content: 0.1,
},
haptics: SwitchDefault {
enabled: true,
content: HapticsConfigDefault {