feat(server): ✨ Expose button remapping settings
This commit is contained in:
parent
ce7328568f
commit
254d06c197
|
@ -84,7 +84,14 @@ pub fn contruct_openvr_config() -> OpenvrConfig {
|
|||
let controllers_enabled = if let Switch::Enabled(config) = settings.headset.controllers {
|
||||
controller_is_tracker =
|
||||
matches!(config.emulation_mode, ControllersEmulationMode::ViveTracker);
|
||||
_controller_profile = config.emulation_mode as i32;
|
||||
_controller_profile = match config.emulation_mode {
|
||||
ControllersEmulationMode::RiftSTouch => 0,
|
||||
ControllersEmulationMode::Quest2Touch => 1,
|
||||
ControllersEmulationMode::ValveIndex => 2,
|
||||
ControllersEmulationMode::ViveWand => 3,
|
||||
ControllersEmulationMode::ViveTracker => 4,
|
||||
ControllersEmulationMode::Custom { .. } => 5,
|
||||
};
|
||||
|
||||
true
|
||||
} else {
|
||||
|
@ -892,20 +899,25 @@ 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 mut controller_button_mapping_manager = SERVER_DATA_MANAGER
|
||||
.read()
|
||||
.settings()
|
||||
.headset
|
||||
.controllers
|
||||
.as_option()
|
||||
.map(|config| {
|
||||
if let Some(mappings) = &config.button_mappings {
|
||||
ButtonMappingManager::new_manual(mappings)
|
||||
} else {
|
||||
ButtonMappingManager::new_automatic(
|
||||
&CONTROLLER_PROFILE_INFO
|
||||
.get(&alvr_common::hash_string(QUEST_CONTROLLER_PROFILE_PATH))
|
||||
.unwrap()
|
||||
.button_set,
|
||||
&config.button_mapping_config,
|
||||
)
|
||||
}
|
||||
});
|
||||
|
||||
let control_sender = Arc::clone(&control_sender);
|
||||
let client_hostname = client_hostname.clone();
|
||||
|
@ -1024,10 +1036,14 @@ fn try_connect(mut client_ips: HashMap<IpAddr, String>) -> ConResult {
|
|||
&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,
|
||||
))
|
||||
if let Some(mappings) = &config.button_mappings {
|
||||
Some(ButtonMappingManager::new_manual(mappings))
|
||||
} else {
|
||||
Some(ButtonMappingManager::new_automatic(
|
||||
&profile_info.button_set,
|
||||
&config.button_mapping_config,
|
||||
))
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
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,
|
||||
use alvr_session::{
|
||||
AutomaticButtonMappingConfig, BinaryToScalarStates, ButtonBindingTarget, ButtonMappingType,
|
||||
ControllersEmulationMode, HysteresisThreshold, Range,
|
||||
};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
pub static REGISTERED_BUTTON_SET: Lazy<HashSet<u64>> = Lazy::new(|| {
|
||||
let data_manager_lock = SERVER_DATA_MANAGER.read();
|
||||
|
@ -14,36 +14,35 @@ pub static REGISTERED_BUTTON_SET: Lazy<HashSet<u64>> = Lazy::new(|| {
|
|||
return HashSet::new();
|
||||
};
|
||||
|
||||
let profile = match &controllers_config.emulation_mode {
|
||||
match &controllers_config.emulation_mode {
|
||||
ControllersEmulationMode::RiftSTouch | ControllersEmulationMode::Quest2Touch => {
|
||||
&QUEST_CONTROLLER_PROFILE_ID
|
||||
CONTROLLER_PROFILE_INFO
|
||||
.get(&QUEST_CONTROLLER_PROFILE_ID)
|
||||
.unwrap()
|
||||
.button_set
|
||||
.clone()
|
||||
}
|
||||
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()
|
||||
ControllersEmulationMode::ValveIndex => CONTROLLER_PROFILE_INFO
|
||||
.get(&INDEX_CONTROLLER_PROFILE_ID)
|
||||
.unwrap()
|
||||
.button_set
|
||||
.clone(),
|
||||
ControllersEmulationMode::ViveWand => CONTROLLER_PROFILE_INFO
|
||||
.get(&VIVE_CONTROLLER_PROFILE_ID)
|
||||
.unwrap()
|
||||
.button_set
|
||||
.clone(),
|
||||
ControllersEmulationMode::ViveTracker => HashSet::new(),
|
||||
ControllersEmulationMode::Custom { button_set, .. } => button_set
|
||||
.iter()
|
||||
.map(|b| alvr_common::hash_string(b))
|
||||
.collect(),
|
||||
}
|
||||
});
|
||||
|
||||
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,
|
||||
mapping_type: ButtonMappingType,
|
||||
binary_conditions: Vec<u64>,
|
||||
}
|
||||
|
||||
|
@ -104,7 +103,7 @@ fn ctvf(set: &HashSet<u64>, click: u64, touch: u64, value: u64, force: u64) -> B
|
|||
fn passthrough(target: u64) -> BindingTarget {
|
||||
BindingTarget {
|
||||
destination: target,
|
||||
mapping_type: MappingType::Passthrough,
|
||||
mapping_type: ButtonMappingType::Passthrough,
|
||||
binary_conditions: vec![],
|
||||
}
|
||||
}
|
||||
|
@ -112,7 +111,7 @@ fn passthrough(target: u64) -> BindingTarget {
|
|||
fn binary_to_scalar(target: u64, map: BinaryToScalarStates) -> BindingTarget {
|
||||
BindingTarget {
|
||||
destination: target,
|
||||
mapping_type: MappingType::BinaryToScalar(map),
|
||||
mapping_type: ButtonMappingType::BinaryToScalar(map),
|
||||
binary_conditions: vec![],
|
||||
}
|
||||
}
|
||||
|
@ -120,15 +119,15 @@ fn binary_to_scalar(target: u64, map: BinaryToScalarStates) -> BindingTarget {
|
|||
fn hysteresis_threshold(target: u64, map: HysteresisThreshold) -> BindingTarget {
|
||||
BindingTarget {
|
||||
destination: target,
|
||||
mapping_type: MappingType::HysteresisThreshold(map),
|
||||
mapping_type: ButtonMappingType::HysteresisThreshold(map),
|
||||
binary_conditions: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
fn remap(target: u64, map: Range<f32>) -> BindingTarget {
|
||||
fn remap(target: u64, map: Range) -> BindingTarget {
|
||||
BindingTarget {
|
||||
destination: target,
|
||||
mapping_type: MappingType::Remap(map),
|
||||
mapping_type: ButtonMappingType::Remap(map),
|
||||
binary_conditions: vec![],
|
||||
}
|
||||
}
|
||||
|
@ -192,7 +191,13 @@ fn map_button_pair_automatic(
|
|||
}
|
||||
if source.force.is_none() {
|
||||
if let Some(destination_force) = destination.force {
|
||||
targets.push(remap(destination_force, config.force_threshold..1.0));
|
||||
targets.push(remap(
|
||||
destination_force,
|
||||
Range {
|
||||
min: config.force_threshold,
|
||||
max: 1.0,
|
||||
},
|
||||
));
|
||||
remap_for_force = true;
|
||||
}
|
||||
}
|
||||
|
@ -210,7 +215,13 @@ fn map_button_pair_automatic(
|
|||
} else {
|
||||
1.0
|
||||
};
|
||||
targets.push(remap(destination_value, low..high));
|
||||
targets.push(remap(
|
||||
destination_value,
|
||||
Range {
|
||||
min: low,
|
||||
max: high,
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -541,13 +552,34 @@ impl ButtonMappingManager {
|
|||
}
|
||||
}
|
||||
|
||||
// pub fn new_manual(mappings: HashMap<u64, Vec<BindingTarget>>) -> Self {
|
||||
// Self {
|
||||
// mappings,
|
||||
// binary_source_states: HashMap::new(),
|
||||
// hysteresis_states: HashMap::new(),
|
||||
// }
|
||||
// }
|
||||
pub fn new_manual(mappings: &[(String, Vec<ButtonBindingTarget>)]) -> Self {
|
||||
let mappings = mappings
|
||||
.iter()
|
||||
.map(|(key, value)| {
|
||||
(
|
||||
alvr_common::hash_string(key),
|
||||
value
|
||||
.iter()
|
||||
.map(|b| BindingTarget {
|
||||
destination: alvr_common::hash_string(&b.destination),
|
||||
mapping_type: b.mapping_type.clone(),
|
||||
binary_conditions: b
|
||||
.binary_conditions
|
||||
.iter()
|
||||
.map(|c| alvr_common::hash_string(c))
|
||||
.collect(),
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
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) {
|
||||
|
@ -564,8 +596,11 @@ impl ButtonMappingManager {
|
|||
if let Some(mappings) = self.mappings.get(&source_id) {
|
||||
'mapping: for mapping in mappings {
|
||||
let destination_value = match (&mapping.mapping_type, source_value) {
|
||||
(MappingType::Passthrough, value) => value,
|
||||
(MappingType::HysteresisThreshold(threshold), ButtonValue::Scalar(value)) => {
|
||||
(ButtonMappingType::Passthrough, value) => value,
|
||||
(
|
||||
ButtonMappingType::HysteresisThreshold(threshold),
|
||||
ButtonValue::Scalar(value),
|
||||
) => {
|
||||
let state = self
|
||||
.hysteresis_states
|
||||
.entry(source_id)
|
||||
|
@ -584,15 +619,15 @@ impl ButtonMappingManager {
|
|||
|
||||
ButtonValue::Binary(*state)
|
||||
}
|
||||
(MappingType::BinaryToScalar(levels), ButtonValue::Binary(value)) => {
|
||||
(ButtonMappingType::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);
|
||||
(ButtonMappingType::Remap(range), ButtonValue::Scalar(value)) => {
|
||||
let value = (value - range.min) / (range.max - range.min);
|
||||
ButtonValue::Scalar(value.clamp(0.0, 1.0))
|
||||
}
|
||||
_ => {
|
||||
|
|
|
@ -72,6 +72,7 @@ fn serial_number(device_id: u64) -> String {
|
|||
ControllersEmulationMode::ValveIndex => "ALVR Remote Controller",
|
||||
ControllersEmulationMode::ViveWand => "ALVR Remote Controller",
|
||||
ControllersEmulationMode::ViveTracker => "ALVR Remote Controller",
|
||||
ControllersEmulationMode::Custom { serial_number, .. } => serial_number,
|
||||
};
|
||||
|
||||
if device_id == *LEFT_HAND_ID {
|
||||
|
@ -142,11 +143,7 @@ pub extern "C" fn set_device_openvr_props(device_id: u64) {
|
|||
set_prop(RegisteredDeviceType("vive".into()));
|
||||
set_prop(DriverVersion("".into()));
|
||||
}
|
||||
HeadsetEmulationMode::Custom { props, .. } => {
|
||||
for prop in props {
|
||||
set_prop(prop.clone());
|
||||
}
|
||||
}
|
||||
HeadsetEmulationMode::Custom { .. } => (),
|
||||
}
|
||||
|
||||
set_prop(UserIpdMeters(0.063));
|
||||
|
@ -454,6 +451,7 @@ pub extern "C" fn set_device_openvr_props(device_id: u64) {
|
|||
"{htc}/icons/tracker_status_ready_low.png".into(),
|
||||
));
|
||||
}
|
||||
ControllersEmulationMode::Custom { .. } => todo!(),
|
||||
}
|
||||
|
||||
set_prop(SerialNumber(serial_number(device_id)));
|
||||
|
|
|
@ -571,7 +571,6 @@ pub enum HeadsetEmulationMode {
|
|||
Vive,
|
||||
Custom {
|
||||
serial_number: String,
|
||||
props: Vec<OpenvrProperty>,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -608,6 +607,10 @@ pub enum ControllersEmulationMode {
|
|||
ValveIndex,
|
||||
ViveWand,
|
||||
ViveTracker,
|
||||
Custom {
|
||||
serial_number: String,
|
||||
button_set: Vec<String>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(SettingsSchema, Serialize, Deserialize, Clone, Copy)]
|
||||
|
@ -618,6 +621,38 @@ pub struct HysteresisThreshold {
|
|||
pub deviation: f32,
|
||||
}
|
||||
|
||||
#[derive(SettingsSchema, Serialize, Deserialize, Clone, Copy)]
|
||||
pub struct BinaryToScalarStates {
|
||||
#[schema(gui(slider(min = 0.0, max = 1.0, step = 0.01)))]
|
||||
pub off: f32,
|
||||
#[schema(gui(slider(min = 0.0, max = 1.0, step = 0.01)))]
|
||||
pub on: f32,
|
||||
}
|
||||
|
||||
// Remaps 0..1 to custom range
|
||||
#[derive(SettingsSchema, Serialize, Deserialize, Clone, Copy)]
|
||||
pub struct Range {
|
||||
#[schema(gui(slider(min = 0.0, max = 1.0, step = 0.01)))]
|
||||
pub min: f32,
|
||||
#[schema(gui(slider(min = 0.0, max = 1.0, step = 0.01)))]
|
||||
pub max: f32,
|
||||
}
|
||||
|
||||
#[derive(SettingsSchema, Serialize, Deserialize, Clone)]
|
||||
pub enum ButtonMappingType {
|
||||
Passthrough,
|
||||
HysteresisThreshold(HysteresisThreshold),
|
||||
BinaryToScalar(BinaryToScalarStates),
|
||||
Remap(Range),
|
||||
}
|
||||
|
||||
#[derive(SettingsSchema, Serialize, Deserialize, Clone)]
|
||||
pub struct ButtonBindingTarget {
|
||||
pub destination: String,
|
||||
pub mapping_type: ButtonMappingType,
|
||||
pub binary_conditions: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(SettingsSchema, Serialize, Deserialize, Clone)]
|
||||
#[schema(collapsible)]
|
||||
pub struct AutomaticButtonMappingConfig {
|
||||
|
@ -626,81 +661,6 @@ pub struct AutomaticButtonMappingConfig {
|
|||
pub force_threshold: f32,
|
||||
}
|
||||
|
||||
#[derive(SettingsSchema, Serialize, Deserialize, Clone)]
|
||||
#[schema(collapsible)]
|
||||
pub struct HapticsConfig {
|
||||
#[schema(flag = "real-time")]
|
||||
#[schema(gui(slider(min = 0.0, max = 5.0, step = 0.1)))]
|
||||
pub intensity_multiplier: f32,
|
||||
|
||||
#[schema(flag = "real-time")]
|
||||
#[schema(gui(slider(min = 0.0, max = 1.0, step = 0.01)))]
|
||||
pub amplitude_curve: f32,
|
||||
|
||||
#[schema(strings(display_name = "Minimum duration"))]
|
||||
#[schema(flag = "real-time")]
|
||||
#[schema(gui(slider(min = 0.0, max = 0.1, step = 0.001)), suffix = "s")]
|
||||
pub min_duration_s: f32,
|
||||
}
|
||||
|
||||
#[derive(SettingsSchema, Serialize, Deserialize, Clone)]
|
||||
#[schema(collapsible)]
|
||||
pub struct ControllersConfig {
|
||||
#[schema(strings(help = "Turning this off will make the controllers appear powered off."))]
|
||||
#[schema(flag = "real-time")]
|
||||
pub tracked: bool,
|
||||
|
||||
#[schema(flag = "steamvr-restart")]
|
||||
pub emulation_mode: ControllersEmulationMode,
|
||||
|
||||
#[schema(flag = "steamvr-restart")]
|
||||
pub extra_openvr_props: Vec<OpenvrProperty>,
|
||||
|
||||
pub button_mapping_config: AutomaticButtonMappingConfig,
|
||||
|
||||
pub hand_tracking: HandTrackingConfig,
|
||||
|
||||
#[schema(strings(
|
||||
display_name = "Prediction",
|
||||
help = r"Higher values make the controllers track smoother.
|
||||
Technically, this is the time (counted in frames) between pose submitted to SteamVR and the corresponding virtual vsync happens.
|
||||
Currently this cannot be reliably estimated automatically. The correct value should be 2 but 3 is default for smoother tracking at the cost of slight lag."
|
||||
))]
|
||||
#[schema(gui(slider(min = 1.0, max = 10.0, logarithmic)), suffix = "frames")]
|
||||
pub steamvr_pipeline_frames: f32,
|
||||
|
||||
#[schema(flag = "real-time")]
|
||||
// note: logarithmic scale seems to be glitchy for this control
|
||||
#[schema(gui(slider(min = 0.0, max = 1.0, step = 0.01)), suffix = "m/s")]
|
||||
pub linear_velocity_cutoff: f32,
|
||||
|
||||
#[schema(flag = "real-time")]
|
||||
// note: logarithmic scale seems to be glitchy for this control
|
||||
#[schema(gui(slider(min = 0.0, max = 100.0, step = 1.0)), suffix = "°/s")]
|
||||
pub angular_velocity_cutoff: f32,
|
||||
|
||||
#[schema(flag = "real-time")]
|
||||
// note: logarithmic scale seems to be glitchy for this control
|
||||
#[schema(gui(slider(min = -0.5, max = 0.5, step = 0.001)), suffix = "m")]
|
||||
pub left_controller_position_offset: [f32; 3],
|
||||
|
||||
#[schema(flag = "real-time")]
|
||||
#[schema(gui(slider(min = -180.0, max = 180.0, step = 1.0)), suffix = "°")]
|
||||
pub left_controller_rotation_offset: [f32; 3],
|
||||
|
||||
#[schema(flag = "real-time")]
|
||||
// note: logarithmic scale seems to be glitchy for this control
|
||||
#[schema(gui(slider(min = -0.5, max = 0.5, step = 0.001)), suffix = "m")]
|
||||
pub left_hand_tracking_position_offset: [f32; 3],
|
||||
|
||||
#[schema(flag = "real-time")]
|
||||
#[schema(gui(slider(min = -180.0, max = 180.0, step = 1.0)), suffix = "°")]
|
||||
pub left_hand_tracking_rotation_offset: [f32; 3],
|
||||
|
||||
#[schema(flag = "real-time")]
|
||||
pub haptics: Switch<HapticsConfig>,
|
||||
}
|
||||
|
||||
#[derive(SettingsSchema, Serialize, Deserialize, Clone)]
|
||||
#[schema(collapsible)]
|
||||
pub struct HandTrackingConfig {
|
||||
|
@ -788,6 +748,84 @@ pub struct HandGestureConfig {
|
|||
pub repeat_delay: u32,
|
||||
}
|
||||
|
||||
#[derive(SettingsSchema, Serialize, Deserialize, Clone)]
|
||||
#[schema(collapsible)]
|
||||
pub struct HapticsConfig {
|
||||
#[schema(flag = "real-time")]
|
||||
#[schema(gui(slider(min = 0.0, max = 5.0, step = 0.1)))]
|
||||
pub intensity_multiplier: f32,
|
||||
|
||||
#[schema(flag = "real-time")]
|
||||
#[schema(gui(slider(min = 0.0, max = 1.0, step = 0.01)))]
|
||||
pub amplitude_curve: f32,
|
||||
|
||||
#[schema(strings(display_name = "Minimum duration"))]
|
||||
#[schema(flag = "real-time")]
|
||||
#[schema(gui(slider(min = 0.0, max = 0.1, step = 0.001)), suffix = "s")]
|
||||
pub min_duration_s: f32,
|
||||
}
|
||||
|
||||
#[derive(SettingsSchema, Serialize, Deserialize, Clone)]
|
||||
#[schema(collapsible)]
|
||||
pub struct ControllersConfig {
|
||||
#[schema(strings(help = "Turning this off will make the controllers appear powered off."))]
|
||||
#[schema(flag = "real-time")]
|
||||
pub tracked: bool,
|
||||
|
||||
#[schema(flag = "steamvr-restart")]
|
||||
pub emulation_mode: ControllersEmulationMode,
|
||||
|
||||
#[schema(flag = "steamvr-restart")]
|
||||
pub extra_openvr_props: Vec<OpenvrProperty>,
|
||||
|
||||
#[schema(strings(help = "List of OpenXR-syle paths"))]
|
||||
pub button_mappings: Option<Vec<(String, Vec<ButtonBindingTarget>)>>,
|
||||
|
||||
pub button_mapping_config: AutomaticButtonMappingConfig,
|
||||
|
||||
pub hand_tracking: HandTrackingConfig,
|
||||
|
||||
#[schema(strings(
|
||||
display_name = "Prediction",
|
||||
help = r"Higher values make the controllers track smoother.
|
||||
Technically, this is the time (counted in frames) between pose submitted to SteamVR and the corresponding virtual vsync happens.
|
||||
Currently this cannot be reliably estimated automatically. The correct value should be 2 but 3 is default for smoother tracking at the cost of slight lag."
|
||||
))]
|
||||
#[schema(gui(slider(min = 1.0, max = 10.0, logarithmic)), suffix = "frames")]
|
||||
pub steamvr_pipeline_frames: f32,
|
||||
|
||||
#[schema(flag = "real-time")]
|
||||
// note: logarithmic scale seems to be glitchy for this control
|
||||
#[schema(gui(slider(min = 0.0, max = 1.0, step = 0.01)), suffix = "m/s")]
|
||||
pub linear_velocity_cutoff: f32,
|
||||
|
||||
#[schema(flag = "real-time")]
|
||||
// note: logarithmic scale seems to be glitchy for this control
|
||||
#[schema(gui(slider(min = 0.0, max = 100.0, step = 1.0)), suffix = "°/s")]
|
||||
pub angular_velocity_cutoff: f32,
|
||||
|
||||
#[schema(flag = "real-time")]
|
||||
// note: logarithmic scale seems to be glitchy for this control
|
||||
#[schema(gui(slider(min = -0.5, max = 0.5, step = 0.001)), suffix = "m")]
|
||||
pub left_controller_position_offset: [f32; 3],
|
||||
|
||||
#[schema(flag = "real-time")]
|
||||
#[schema(gui(slider(min = -180.0, max = 180.0, step = 1.0)), suffix = "°")]
|
||||
pub left_controller_rotation_offset: [f32; 3],
|
||||
|
||||
#[schema(flag = "real-time")]
|
||||
// note: logarithmic scale seems to be glitchy for this control
|
||||
#[schema(gui(slider(min = -0.5, max = 0.5, step = 0.001)), suffix = "m")]
|
||||
pub left_hand_tracking_position_offset: [f32; 3],
|
||||
|
||||
#[schema(flag = "real-time")]
|
||||
#[schema(gui(slider(min = -180.0, max = 180.0, step = 1.0)), suffix = "°")]
|
||||
pub left_hand_tracking_rotation_offset: [f32; 3],
|
||||
|
||||
#[schema(flag = "real-time")]
|
||||
pub haptics: Switch<HapticsConfig>,
|
||||
}
|
||||
|
||||
#[derive(SettingsSchema, Serialize, Deserialize, Clone, Copy)]
|
||||
pub enum PositionRecenteringMode {
|
||||
Disabled,
|
||||
|
@ -1276,7 +1314,6 @@ pub fn session_settings_default() -> SettingsDefault {
|
|||
emulation_mode: HeadsetEmulationModeDefault {
|
||||
Custom: HeadsetEmulationModeCustomDefault {
|
||||
serial_number: "Unknown".into(),
|
||||
props: default_custom_openvr_props.clone(),
|
||||
},
|
||||
variant: HeadsetEmulationModeDefaultVariant::Quest2,
|
||||
},
|
||||
|
@ -1303,11 +1340,51 @@ pub fn session_settings_default() -> SettingsDefault {
|
|||
enabled: true,
|
||||
content: ControllersConfigDefault {
|
||||
gui_collapsed: false,
|
||||
tracked: true,
|
||||
emulation_mode: ControllersEmulationModeDefault {
|
||||
Custom: ControllersEmulationModeCustomDefault {
|
||||
serial_number: "ALVR Controller".into(),
|
||||
button_set: VectorDefault {
|
||||
gui_collapsed: false,
|
||||
element: "/user/hand/left/input/a/click".into(),
|
||||
content: vec![],
|
||||
},
|
||||
},
|
||||
variant: ControllersEmulationModeDefaultVariant::Quest2Touch,
|
||||
},
|
||||
tracked: true,
|
||||
extra_openvr_props: default_custom_openvr_props,
|
||||
button_mappings: OptionalDefault {
|
||||
set: false,
|
||||
content: DictionaryDefault {
|
||||
gui_collapsed: false,
|
||||
key: "/user/hand/left/input/a/click".into(),
|
||||
value: VectorDefault {
|
||||
gui_collapsed: false,
|
||||
element: ButtonBindingTargetDefault {
|
||||
destination: "/user/hand/left/input/a/click".into(),
|
||||
mapping_type: ButtonMappingTypeDefault {
|
||||
HysteresisThreshold: HysteresisThresholdDefault {
|
||||
value: 0.5,
|
||||
deviation: 0.05,
|
||||
},
|
||||
BinaryToScalar: BinaryToScalarStatesDefault {
|
||||
off: 0.0,
|
||||
on: 1.0,
|
||||
},
|
||||
Remap: RangeDefault { min: 0.0, max: 1.0 },
|
||||
variant: ButtonMappingTypeDefaultVariant::Passthrough,
|
||||
},
|
||||
binary_conditions: VectorDefault {
|
||||
gui_collapsed: true,
|
||||
element: "/user/hand/left/input/trigger/touch".into(),
|
||||
content: vec![],
|
||||
},
|
||||
},
|
||||
content: vec![],
|
||||
},
|
||||
content: vec![],
|
||||
},
|
||||
},
|
||||
button_mapping_config: AutomaticButtonMappingConfigDefault {
|
||||
gui_collapsed: true,
|
||||
click_threshold: HysteresisThresholdDefault {
|
||||
|
|
Loading…
Reference in New Issue