Merge pull request #55 from Schmarni-Dev/action_updates
Small Changes to make Creating Crates that interact with the action system easier
This commit is contained in:
@@ -8,17 +8,14 @@ use bevy::{
|
|||||||
prelude::*,
|
prelude::*,
|
||||||
render::{
|
render::{
|
||||||
extract_resource::{ExtractResource, ExtractResourcePlugin},
|
extract_resource::{ExtractResource, ExtractResourcePlugin},
|
||||||
renderer::{
|
renderer::{self, RenderAdapter, RenderAdapterInfo, RenderDevice, RenderQueue},
|
||||||
self, RenderAdapter, RenderAdapterInfo, RenderDevice, RenderInstance, RenderQueue,
|
|
||||||
},
|
|
||||||
settings::WgpuSettings,
|
settings::WgpuSettings,
|
||||||
},
|
},
|
||||||
window::{PrimaryWindow, RawHandleWrapper},
|
window::RawHandleWrapper,
|
||||||
};
|
};
|
||||||
use wgpu::Instance;
|
use wgpu::Instance;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
graphics,
|
|
||||||
input::XrInput,
|
input::XrInput,
|
||||||
resources::{
|
resources::{
|
||||||
XrEnvironmentBlendMode, XrFormat, XrFrameState, XrFrameWaiter, XrInstance, XrResolution,
|
XrEnvironmentBlendMode, XrFormat, XrFrameState, XrFrameWaiter, XrInstance, XrResolution,
|
||||||
@@ -107,9 +104,7 @@ impl Plugin for RenderRestartPlugin {
|
|||||||
.insert_resource(ForceMain)
|
.insert_resource(ForceMain)
|
||||||
.add_event::<XrEnableRequest>()
|
.add_event::<XrEnableRequest>()
|
||||||
.add_event::<XrEnableStatus>()
|
.add_event::<XrEnableStatus>()
|
||||||
.add_systems(PreStartup, xr_presetup.run_if(xr_only()))
|
.add_systems(PostStartup, setup_xr.run_if(xr_only()))
|
||||||
.add_systems(Startup, xr_setup.run_if(xr_only()))
|
|
||||||
.add_systems(PostStartup, xr_postsetup.run_if(xr_only()))
|
|
||||||
.add_systems(
|
.add_systems(
|
||||||
PostUpdate,
|
PostUpdate,
|
||||||
update_xr_stuff.run_if(on_event::<XrEnableRequest>()),
|
update_xr_stuff.run_if(on_event::<XrEnableRequest>()),
|
||||||
@@ -154,17 +149,6 @@ fn add_schedules(app: &mut App) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn xr_presetup(world: &mut World) {
|
|
||||||
world.run_schedule(XrPreSetup);
|
|
||||||
}
|
|
||||||
fn xr_setup(world: &mut World) {
|
|
||||||
world.run_schedule(XrSetup);
|
|
||||||
}
|
|
||||||
fn xr_postsetup(world: &mut World) {
|
|
||||||
world.run_schedule(XrPrePostSetup);
|
|
||||||
world.run_schedule(XrPostSetup);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setup_xr(world: &mut World) {
|
fn setup_xr(world: &mut World) {
|
||||||
world.run_schedule(XrPreSetup);
|
world.run_schedule(XrPreSetup);
|
||||||
world.run_schedule(XrSetup);
|
world.run_schedule(XrSetup);
|
||||||
|
|||||||
@@ -35,40 +35,40 @@ pub fn setup_oxr_actions(world: &mut World) {
|
|||||||
while let Some((set_name, set)) = a_iter.next() {
|
while let Some((set_name, set)) = a_iter.next() {
|
||||||
let mut actions: HashMap<&'static str, TypedAction> = default();
|
let mut actions: HashMap<&'static str, TypedAction> = default();
|
||||||
let oxr_action_set = instance
|
let oxr_action_set = instance
|
||||||
.create_action_set(set_name, set.pretty_name, set.priority)
|
.create_action_set(set_name, &set.pretty_name, set.priority)
|
||||||
.expect("Unable to create action set");
|
.expect("Unable to create action set");
|
||||||
for (action_name, action) in set.actions.into_iter() {
|
for (action_name, action) in set.actions.into_iter() {
|
||||||
let typed_action = match action.action_type {
|
let typed_action = match action.action_type {
|
||||||
ActionType::F32 => TypedAction::F32(match action.handednes {
|
ActionType::F32 => TypedAction::F32(match action.handednes {
|
||||||
ActionHandednes::Single => oxr_action_set
|
ActionHandednes::Single => oxr_action_set
|
||||||
.create_action(action_name, action.pretty_name, &[])
|
.create_action(action_name, &action.pretty_name, &[])
|
||||||
.expect(&format!("Unable to create action: {}", action_name)),
|
.expect(&format!("Unable to create action: {}", action_name)),
|
||||||
ActionHandednes::Double => oxr_action_set
|
ActionHandednes::Double => oxr_action_set
|
||||||
.create_action(action_name, action.pretty_name, &hands)
|
.create_action(action_name, &action.pretty_name, &hands)
|
||||||
.expect(&format!("Unable to create action: {}", action_name)),
|
.expect(&format!("Unable to create action: {}", action_name)),
|
||||||
}),
|
}),
|
||||||
ActionType::Bool => TypedAction::Bool(match action.handednes {
|
ActionType::Bool => TypedAction::Bool(match action.handednes {
|
||||||
ActionHandednes::Single => oxr_action_set
|
ActionHandednes::Single => oxr_action_set
|
||||||
.create_action(action_name, action.pretty_name, &[])
|
.create_action(action_name, &action.pretty_name, &[])
|
||||||
.expect(&format!("Unable to create action: {}", action_name)),
|
.expect(&format!("Unable to create action: {}", action_name)),
|
||||||
ActionHandednes::Double => oxr_action_set
|
ActionHandednes::Double => oxr_action_set
|
||||||
.create_action(action_name, action.pretty_name, &hands)
|
.create_action(action_name, &action.pretty_name, &hands)
|
||||||
.expect(&format!("Unable to create action: {}", action_name)),
|
.expect(&format!("Unable to create action: {}", action_name)),
|
||||||
}),
|
}),
|
||||||
ActionType::PoseF => TypedAction::PoseF(match action.handednes {
|
ActionType::PoseF => TypedAction::PoseF(match action.handednes {
|
||||||
ActionHandednes::Single => oxr_action_set
|
ActionHandednes::Single => oxr_action_set
|
||||||
.create_action(action_name, action.pretty_name, &[])
|
.create_action(action_name, &action.pretty_name, &[])
|
||||||
.expect(&format!("Unable to create action: {}", action_name)),
|
.expect(&format!("Unable to create action: {}", action_name)),
|
||||||
ActionHandednes::Double => oxr_action_set
|
ActionHandednes::Double => oxr_action_set
|
||||||
.create_action(action_name, action.pretty_name, &hands)
|
.create_action(action_name, &action.pretty_name, &hands)
|
||||||
.expect(&format!("Unable to create action: {}", action_name)),
|
.expect(&format!("Unable to create action: {}", action_name)),
|
||||||
}),
|
}),
|
||||||
ActionType::Haptic => TypedAction::Haptic(match action.handednes {
|
ActionType::Haptic => TypedAction::Haptic(match action.handednes {
|
||||||
ActionHandednes::Single => oxr_action_set
|
ActionHandednes::Single => oxr_action_set
|
||||||
.create_action(action_name, action.pretty_name, &[])
|
.create_action(action_name, &action.pretty_name, &[])
|
||||||
.expect(&format!("Unable to create action: {}", action_name)),
|
.expect(&format!("Unable to create action: {}", action_name)),
|
||||||
ActionHandednes::Double => oxr_action_set
|
ActionHandednes::Double => oxr_action_set
|
||||||
.create_action(action_name, action.pretty_name, &hands)
|
.create_action(action_name, &action.pretty_name, &hands)
|
||||||
.expect(&format!("Unable to create action: {}", action_name)),
|
.expect(&format!("Unable to create action: {}", action_name)),
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
@@ -149,6 +149,7 @@ pub enum ActionHandednes {
|
|||||||
Double,
|
Double,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
pub enum ActionType {
|
pub enum ActionType {
|
||||||
F32,
|
F32,
|
||||||
Bool,
|
Bool,
|
||||||
@@ -164,14 +165,14 @@ pub enum TypedAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct SetupAction {
|
pub struct SetupAction {
|
||||||
pretty_name: &'static str,
|
pretty_name: String,
|
||||||
action_type: ActionType,
|
action_type: ActionType,
|
||||||
handednes: ActionHandednes,
|
handednes: ActionHandednes,
|
||||||
bindings: HashMap<&'static str, Vec<&'static str>>,
|
bindings: HashMap<&'static str, Vec<&'static str>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SetupActionSet {
|
pub struct SetupActionSet {
|
||||||
pretty_name: &'static str,
|
pretty_name: String,
|
||||||
priority: u32,
|
priority: u32,
|
||||||
actions: HashMap<&'static str, SetupAction>,
|
actions: HashMap<&'static str, SetupAction>,
|
||||||
}
|
}
|
||||||
@@ -180,7 +181,7 @@ impl SetupActionSet {
|
|||||||
pub fn new_action(
|
pub fn new_action(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
pretty_name: &'static str,
|
pretty_name: String,
|
||||||
action_type: ActionType,
|
action_type: ActionType,
|
||||||
handednes: ActionHandednes,
|
handednes: ActionHandednes,
|
||||||
) {
|
) {
|
||||||
@@ -230,7 +231,7 @@ impl SetupActionSets {
|
|||||||
pub fn add_action_set(
|
pub fn add_action_set(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
pretty_name: &'static str,
|
pretty_name: String,
|
||||||
priority: u32,
|
priority: u32,
|
||||||
) -> &mut SetupActionSet {
|
) -> &mut SetupActionSet {
|
||||||
self.sets.insert(
|
self.sets.insert(
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ use openxr::{ActionTy, HandJoint};
|
|||||||
|
|
||||||
use super::common::{get_bone_gizmo_style, HandBoneRadius};
|
use super::common::{get_bone_gizmo_style, HandBoneRadius};
|
||||||
use crate::{
|
use crate::{
|
||||||
xr_init::{xr_only, XrSetup},
|
|
||||||
resources::{XrInstance, XrSession},
|
resources::{XrInstance, XrSession},
|
||||||
|
xr_init::{xr_only, XrSetup},
|
||||||
xr_input::{
|
xr_input::{
|
||||||
actions::{
|
actions::{
|
||||||
ActionHandednes, ActionType, SetupActionSet, SetupActionSets, XrActionSets, XrBinding,
|
ActionHandednes, ActionType, SetupActionSet, SetupActionSets, XrActionSets, XrBinding,
|
||||||
@@ -28,10 +28,7 @@ pub struct HandEmulationPlugin;
|
|||||||
|
|
||||||
impl Plugin for HandEmulationPlugin {
|
impl Plugin for HandEmulationPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.add_systems(
|
app.add_systems(Update, update_hand_skeleton_from_emulated.run_if(xr_only()));
|
||||||
Update,
|
|
||||||
update_hand_skeleton_from_emulated.run_if(xr_only()),
|
|
||||||
);
|
|
||||||
app.add_systems(XrSetup, setup_hand_emulation_action_set);
|
app.add_systems(XrSetup, setup_hand_emulation_action_set);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -39,54 +36,55 @@ impl Plugin for HandEmulationPlugin {
|
|||||||
const HAND_ACTION_SET: &str = "hand_pose_approx";
|
const HAND_ACTION_SET: &str = "hand_pose_approx";
|
||||||
|
|
||||||
fn setup_hand_emulation_action_set(mut action_sets: ResMut<SetupActionSets>) {
|
fn setup_hand_emulation_action_set(mut action_sets: ResMut<SetupActionSets>) {
|
||||||
let mut action_set = action_sets.add_action_set(HAND_ACTION_SET, "Hand Pose Approximaiton", 0);
|
let action_set =
|
||||||
|
action_sets.add_action_set(HAND_ACTION_SET, "Hand Pose Approximaiton".into(), 0);
|
||||||
action_set.new_action(
|
action_set.new_action(
|
||||||
"thumb_touch",
|
"thumb_touch",
|
||||||
"Thumb Touched",
|
"Thumb Touched".into(),
|
||||||
ActionType::Bool,
|
ActionType::Bool,
|
||||||
ActionHandednes::Double,
|
ActionHandednes::Double,
|
||||||
);
|
);
|
||||||
action_set.new_action(
|
action_set.new_action(
|
||||||
"thumb_x",
|
"thumb_x",
|
||||||
"Thumb X",
|
"Thumb X".into(),
|
||||||
ActionType::F32,
|
ActionType::F32,
|
||||||
ActionHandednes::Double,
|
ActionHandednes::Double,
|
||||||
);
|
);
|
||||||
action_set.new_action(
|
action_set.new_action(
|
||||||
"thumb_y",
|
"thumb_y",
|
||||||
"Thumb Y",
|
"Thumb Y".into(),
|
||||||
ActionType::F32,
|
ActionType::F32,
|
||||||
ActionHandednes::Double,
|
ActionHandednes::Double,
|
||||||
);
|
);
|
||||||
|
|
||||||
action_set.new_action(
|
action_set.new_action(
|
||||||
"index_touch",
|
"index_touch",
|
||||||
"Index Finger Touched",
|
"Index Finger Touched".into(),
|
||||||
ActionType::Bool,
|
ActionType::Bool,
|
||||||
ActionHandednes::Double,
|
ActionHandednes::Double,
|
||||||
);
|
);
|
||||||
action_set.new_action(
|
action_set.new_action(
|
||||||
"index_value",
|
"index_value",
|
||||||
"Index Finger Pull",
|
"Index Finger Pull".into(),
|
||||||
ActionType::F32,
|
ActionType::F32,
|
||||||
ActionHandednes::Double,
|
ActionHandednes::Double,
|
||||||
);
|
);
|
||||||
|
|
||||||
action_set.new_action(
|
action_set.new_action(
|
||||||
"middle_value",
|
"middle_value",
|
||||||
"Middle Finger Pull",
|
"Middle Finger Pull".into(),
|
||||||
ActionType::F32,
|
ActionType::F32,
|
||||||
ActionHandednes::Double,
|
ActionHandednes::Double,
|
||||||
);
|
);
|
||||||
action_set.new_action(
|
action_set.new_action(
|
||||||
"ring_value",
|
"ring_value",
|
||||||
"Ring Finger Pull",
|
"Ring Finger Pull".into(),
|
||||||
ActionType::F32,
|
ActionType::F32,
|
||||||
ActionHandednes::Double,
|
ActionHandednes::Double,
|
||||||
);
|
);
|
||||||
action_set.new_action(
|
action_set.new_action(
|
||||||
"little_value",
|
"little_value",
|
||||||
"Little Finger Pull",
|
"Little Finger Pull".into(),
|
||||||
ActionType::F32,
|
ActionType::F32,
|
||||||
ActionHandednes::Double,
|
ActionHandednes::Double,
|
||||||
);
|
);
|
||||||
@@ -126,6 +124,7 @@ fn suggest_oculus_touch_profile(action_set: &mut SetupActionSet) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
pub(crate) fn update_hand_skeleton_from_emulated(
|
pub(crate) fn update_hand_skeleton_from_emulated(
|
||||||
session: Res<XrSession>,
|
session: Res<XrSession>,
|
||||||
instance: Res<XrInstance>,
|
instance: Res<XrInstance>,
|
||||||
@@ -546,5 +545,6 @@ fn get_bone_curl_angle(bone: HandJoint, curl: f32) -> f32 {
|
|||||||
_ => 1.0,
|
_ => 1.0,
|
||||||
};
|
};
|
||||||
let curl_angle = -((mul * curl * 80.0) + 5.0);
|
let curl_angle = -((mul * curl * 80.0) + 5.0);
|
||||||
|
#[allow(clippy::needless_return)]
|
||||||
return curl_angle;
|
return curl_angle;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -305,124 +305,124 @@ pub struct OculusController {
|
|||||||
impl OculusController {
|
impl OculusController {
|
||||||
pub fn new(mut action_sets: ResMut<SetupActionSets>) -> anyhow::Result<Self> {
|
pub fn new(mut action_sets: ResMut<SetupActionSets>) -> anyhow::Result<Self> {
|
||||||
let action_set =
|
let action_set =
|
||||||
action_sets.add_action_set("oculus_input", "Oculus Touch Controller Input", 0);
|
action_sets.add_action_set("oculus_input", "Oculus Touch Controller Input".into(), 0);
|
||||||
action_set.new_action(
|
action_set.new_action(
|
||||||
"hand_pose",
|
"hand_pose",
|
||||||
"Hand Pose",
|
"Hand Pose".into(),
|
||||||
ActionType::PoseF,
|
ActionType::PoseF,
|
||||||
ActionHandednes::Double,
|
ActionHandednes::Double,
|
||||||
);
|
);
|
||||||
action_set.new_action(
|
action_set.new_action(
|
||||||
"pointer_pose",
|
"pointer_pose",
|
||||||
"Pointer Pose",
|
"Pointer Pose".into(),
|
||||||
ActionType::PoseF,
|
ActionType::PoseF,
|
||||||
ActionHandednes::Double,
|
ActionHandednes::Double,
|
||||||
);
|
);
|
||||||
action_set.new_action(
|
action_set.new_action(
|
||||||
"squeeze",
|
"squeeze",
|
||||||
"Grip Pull",
|
"Grip Pull".into(),
|
||||||
ActionType::F32,
|
ActionType::F32,
|
||||||
ActionHandednes::Double,
|
ActionHandednes::Double,
|
||||||
);
|
);
|
||||||
action_set.new_action(
|
action_set.new_action(
|
||||||
"trigger",
|
"trigger",
|
||||||
"Trigger Pull",
|
"Trigger Pull".into(),
|
||||||
ActionType::F32,
|
ActionType::F32,
|
||||||
ActionHandednes::Double,
|
ActionHandednes::Double,
|
||||||
);
|
);
|
||||||
action_set.new_action(
|
action_set.new_action(
|
||||||
"trigger_touched",
|
"trigger_touched",
|
||||||
"Trigger Touch",
|
"Trigger Touch".into(),
|
||||||
ActionType::Bool,
|
ActionType::Bool,
|
||||||
ActionHandednes::Double,
|
ActionHandednes::Double,
|
||||||
);
|
);
|
||||||
action_set.new_action(
|
action_set.new_action(
|
||||||
"haptic_feedback",
|
"haptic_feedback",
|
||||||
"Haptic Feedback",
|
"Haptic Feedback".into(),
|
||||||
ActionType::Haptic,
|
ActionType::Haptic,
|
||||||
ActionHandednes::Double,
|
ActionHandednes::Double,
|
||||||
);
|
);
|
||||||
action_set.new_action(
|
action_set.new_action(
|
||||||
"x_button",
|
"x_button",
|
||||||
"X Button",
|
"X Button".into(),
|
||||||
ActionType::Bool,
|
ActionType::Bool,
|
||||||
ActionHandednes::Single,
|
ActionHandednes::Single,
|
||||||
);
|
);
|
||||||
action_set.new_action(
|
action_set.new_action(
|
||||||
"x_button_touch",
|
"x_button_touch",
|
||||||
"X Button Touch",
|
"X Button Touch".into(),
|
||||||
ActionType::Bool,
|
ActionType::Bool,
|
||||||
ActionHandednes::Single,
|
ActionHandednes::Single,
|
||||||
);
|
);
|
||||||
action_set.new_action(
|
action_set.new_action(
|
||||||
"y_button",
|
"y_button",
|
||||||
"Y Button",
|
"Y Button".into(),
|
||||||
ActionType::Bool,
|
ActionType::Bool,
|
||||||
ActionHandednes::Single,
|
ActionHandednes::Single,
|
||||||
);
|
);
|
||||||
action_set.new_action(
|
action_set.new_action(
|
||||||
"y_button_touch",
|
"y_button_touch",
|
||||||
"Y Button Touch",
|
"Y Button Touch".into(),
|
||||||
ActionType::Bool,
|
ActionType::Bool,
|
||||||
ActionHandednes::Single,
|
ActionHandednes::Single,
|
||||||
);
|
);
|
||||||
action_set.new_action(
|
action_set.new_action(
|
||||||
"a_button",
|
"a_button",
|
||||||
"A Button",
|
"A Button".into(),
|
||||||
ActionType::Bool,
|
ActionType::Bool,
|
||||||
ActionHandednes::Single,
|
ActionHandednes::Single,
|
||||||
);
|
);
|
||||||
action_set.new_action(
|
action_set.new_action(
|
||||||
"a_button_touch",
|
"a_button_touch",
|
||||||
"A Button Touch",
|
"A Button Touch".into(),
|
||||||
ActionType::Bool,
|
ActionType::Bool,
|
||||||
ActionHandednes::Single,
|
ActionHandednes::Single,
|
||||||
);
|
);
|
||||||
action_set.new_action(
|
action_set.new_action(
|
||||||
"b_button",
|
"b_button",
|
||||||
"B Button",
|
"B Button".into(),
|
||||||
ActionType::Bool,
|
ActionType::Bool,
|
||||||
ActionHandednes::Single,
|
ActionHandednes::Single,
|
||||||
);
|
);
|
||||||
action_set.new_action(
|
action_set.new_action(
|
||||||
"b_button_touch",
|
"b_button_touch",
|
||||||
"B Button Touch",
|
"B Button Touch".into(),
|
||||||
ActionType::Bool,
|
ActionType::Bool,
|
||||||
ActionHandednes::Single,
|
ActionHandednes::Single,
|
||||||
);
|
);
|
||||||
action_set.new_action(
|
action_set.new_action(
|
||||||
"menu_button",
|
"menu_button",
|
||||||
"Menu Button",
|
"Menu Button".into(),
|
||||||
ActionType::Bool,
|
ActionType::Bool,
|
||||||
ActionHandednes::Single,
|
ActionHandednes::Single,
|
||||||
);
|
);
|
||||||
action_set.new_action(
|
action_set.new_action(
|
||||||
"thumbstick_x",
|
"thumbstick_x",
|
||||||
"Thumbstick X",
|
"Thumbstick X".into(),
|
||||||
ActionType::F32,
|
ActionType::F32,
|
||||||
ActionHandednes::Double,
|
ActionHandednes::Double,
|
||||||
);
|
);
|
||||||
action_set.new_action(
|
action_set.new_action(
|
||||||
"thumbstick_y",
|
"thumbstick_y",
|
||||||
"Thumbstick y",
|
"Thumbstick y".into(),
|
||||||
ActionType::F32,
|
ActionType::F32,
|
||||||
ActionHandednes::Double,
|
ActionHandednes::Double,
|
||||||
);
|
);
|
||||||
action_set.new_action(
|
action_set.new_action(
|
||||||
"thumbstick_touch",
|
"thumbstick_touch",
|
||||||
"Thumbstick Touch",
|
"Thumbstick Touch".into(),
|
||||||
ActionType::Bool,
|
ActionType::Bool,
|
||||||
ActionHandednes::Double,
|
ActionHandednes::Double,
|
||||||
);
|
);
|
||||||
action_set.new_action(
|
action_set.new_action(
|
||||||
"thumbstick_click",
|
"thumbstick_click",
|
||||||
"Thumbstick Click",
|
"Thumbstick Click".into(),
|
||||||
ActionType::Bool,
|
ActionType::Bool,
|
||||||
ActionHandednes::Double,
|
ActionHandednes::Double,
|
||||||
);
|
);
|
||||||
action_set.new_action(
|
action_set.new_action(
|
||||||
"thumbrest_touch",
|
"thumbrest_touch",
|
||||||
"Thumbrest Touch",
|
"Thumbrest Touch".into(),
|
||||||
ActionType::Bool,
|
ActionType::Bool,
|
||||||
ActionHandednes::Double,
|
ActionHandednes::Double,
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user