add deadzone option (#554)

* add deadzone option

* add deadzone calc

* more
This commit is contained in:
Logan McNaughton 2025-08-23 15:36:03 +02:00 committed by GitHub
parent 90be2130c1
commit 8799650245
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 101 additions and 23 deletions

View File

@ -22,15 +22,22 @@ struct Args {
short,
long,
value_name = "PROFILE_NAME",
help = "Create a new input profile (keyboard/gamepad mappings)."
help = "Create a new input profile (keyboard/gamepad mappings)"
)]
configure_input_profile: Option<String>,
#[arg(
short,
long,
help = "Use DirectInput when configuring a new input profile."
help = "Use DirectInput when configuring a new input profile"
)]
use_dinput: bool,
#[arg(
short,
long,
value_name = "DEADZONE_PERCENTAGE",
help = "Used along with --configure-input-profile to set the deadzone for analog sticks"
)]
deadzone: Option<i32>,
#[arg(
short,
long,
@ -112,6 +119,7 @@ async fn main() {
&mut ui,
args.configure_input_profile.unwrap(),
args.use_dinput,
args.deadzone.unwrap_or(ui::input::DEADZONE_DEFAULT),
);
return;
}

View File

@ -29,6 +29,7 @@ pub struct InputProfile {
pub joystick_hat: [InputJoystickHat; ui::input::PROFILE_SIZE],
pub joystick_axis: [InputControllerAxis; ui::input::PROFILE_SIZE],
pub dinput: bool,
pub deadzone: i32,
}
#[derive(serde::Serialize, serde::Deserialize)]

View File

@ -211,6 +211,7 @@ fn controller_window(
let weak_app = app.as_weak();
app.on_input_profile_button_clicked(move || {
let dialog = InputProfileDialog::new().unwrap();
dialog.set_deadzone(ui::input::DEADZONE_DEFAULT);
let weak_dialog = dialog.as_weak();
let weak_app = weak_app.clone();
dialog.on_profile_creation_button_clicked(move || {
@ -220,10 +221,16 @@ fn controller_window(
handle.hide().unwrap();
let profile_name = handle.get_profile_name().into();
let dinput = handle.get_dinput();
let deadzone = handle.get_deadzone();
tokio::spawn(async move {
let mut game_ui = ui::Ui::new();
ui::input::configure_input_profile(&mut game_ui, profile_name, dinput);
ui::input::configure_input_profile(
&mut game_ui,
profile_name,
dinput,
deadzone,
);
update_input_profiles(&weak_app, &game_ui.config);
});
})

View File

@ -1,8 +1,9 @@
import { StandardButton, HorizontalBox, VerticalBox, Button, LineEdit, CheckBox } from "std-widgets.slint";
import { StandardButton, HorizontalBox, VerticalBox, Button, LineEdit, CheckBox, Slider } from "std-widgets.slint";
export global InputProfileData {
in-out property <bool> dinput;
in-out property <string> profile_name;
in-out property <int> deadzone;
}
export component InputProfileDialog inherits Window {
@ -10,6 +11,7 @@ export component InputProfileDialog inherits Window {
callback profile_creation_button_clicked;
in-out property dinput <=> InputProfileData.dinput;
in-out property profile_name <=> InputProfileData.profile_name;
in-out property deadzone <=> InputProfileData.deadzone;
VerticalBox {
HorizontalBox {
LineEdit {
@ -21,6 +23,27 @@ export component InputProfileDialog inherits Window {
}
}
HorizontalBox {
alignment: center;
Text {
text: @tr("Deadzone Percentage");
vertical-alignment: center;
}
Slider {
min-width: 160px;
value: InputProfileData.deadzone;
changed(value) => {
InputProfileData.deadzone = value;
}
}
Text {
text: InputProfileData.deadzone + "%";
vertical-alignment: center;
}
}
HorizontalBox {
alignment: center;
CheckBox {

View File

@ -28,6 +28,8 @@ const Y_AXIS_SHIFT: usize = 24;
const MAX_AXIS_VALUE: f64 = 85.0;
pub const DEADZONE_DEFAULT: i32 = 5;
pub struct Controllers {
pub rumble: bool,
pub game_controller: *mut sdl3_sys::gamepad::SDL_Gamepad,
@ -56,6 +58,7 @@ fn bound_axis(x: &mut f64, y: &mut f64) {
fn set_axis_from_joystick(
profile: &ui::config::InputProfile,
joystick: *mut sdl3_sys::joystick::SDL_Joystick,
deadzone: u16,
) -> (f64, f64) {
let mut x = 0.0;
let mut y = 0.0;
@ -63,32 +66,48 @@ fn set_axis_from_joystick(
let axis_position = unsafe {
sdl3_sys::joystick::SDL_GetJoystickAxis(joystick, profile.joystick_axis[AXIS_LEFT].id)
};
if axis_position as isize * profile.joystick_axis[AXIS_LEFT].axis as isize > 0 {
x = axis_position as f64 * MAX_AXIS_VALUE / i16::MAX as f64;
if axis_position.unsigned_abs() > deadzone
&& axis_position as isize * profile.joystick_axis[AXIS_LEFT].axis as isize > 0
{
x = (axis_position.unsigned_abs() - deadzone) as f64 * MAX_AXIS_VALUE
/ (i16::MAX as u16 - deadzone) as f64;
x *= profile.joystick_axis[AXIS_LEFT].axis as f64;
}
}
if profile.joystick_axis[AXIS_RIGHT].enabled {
let axis_position = unsafe {
sdl3_sys::joystick::SDL_GetJoystickAxis(joystick, profile.joystick_axis[AXIS_RIGHT].id)
};
if axis_position as isize * profile.joystick_axis[AXIS_RIGHT].axis as isize > 0 {
x = axis_position as f64 * MAX_AXIS_VALUE / i16::MAX as f64;
if axis_position.unsigned_abs() > deadzone
&& axis_position as isize * profile.joystick_axis[AXIS_RIGHT].axis as isize > 0
{
x = (axis_position.unsigned_abs() - deadzone) as f64 * MAX_AXIS_VALUE
/ (i16::MAX as u16 - deadzone) as f64;
x *= profile.joystick_axis[AXIS_RIGHT].axis as f64;
}
}
if profile.joystick_axis[AXIS_DOWN].enabled {
let axis_position = unsafe {
sdl3_sys::joystick::SDL_GetJoystickAxis(joystick, profile.joystick_axis[AXIS_DOWN].id)
};
if axis_position as isize * profile.joystick_axis[AXIS_DOWN].axis as isize > 0 {
y = (axis_position as f64 * MAX_AXIS_VALUE / i16::MAX as f64).neg();
if axis_position.unsigned_abs() > deadzone
&& axis_position as isize * profile.joystick_axis[AXIS_DOWN].axis as isize > 0
{
y = (axis_position.unsigned_abs() - deadzone) as f64 * MAX_AXIS_VALUE
/ (i16::MAX as u16 - deadzone) as f64;
y *= (profile.joystick_axis[AXIS_DOWN].axis as f64).neg();
}
}
if profile.joystick_axis[AXIS_UP].enabled {
let axis_position = unsafe {
sdl3_sys::joystick::SDL_GetJoystickAxis(joystick, profile.joystick_axis[AXIS_UP].id)
};
if axis_position as isize * profile.joystick_axis[AXIS_UP].axis as isize > 0 {
y = (axis_position as f64 * MAX_AXIS_VALUE / i16::MAX as f64).neg();
if axis_position.unsigned_abs() > deadzone
&& axis_position as isize * profile.joystick_axis[AXIS_UP].axis as isize > 0
{
y = (axis_position.unsigned_abs() - deadzone) as f64 * MAX_AXIS_VALUE
/ (i16::MAX as u16 - deadzone) as f64;
y *= (profile.joystick_axis[AXIS_UP].axis as f64).neg();
}
}
(x, y)
@ -130,6 +149,7 @@ fn get_button_from_i32(button: i32) -> sdl3_sys::gamepad::SDL_GamepadButton {
fn set_axis_from_controller(
profile: &ui::config::InputProfile,
controller: *mut sdl3_sys::gamepad::SDL_Gamepad,
deadzone: u16,
) -> (f64, f64) {
let mut x = 0.0;
let mut y = 0.0;
@ -140,8 +160,12 @@ fn set_axis_from_controller(
get_axis_from_i32(profile.controller_axis[AXIS_LEFT].id),
)
};
if axis_position as isize * profile.controller_axis[AXIS_LEFT].axis as isize > 0 {
x = axis_position as f64 * MAX_AXIS_VALUE / i16::MAX as f64;
if axis_position.unsigned_abs() > deadzone
&& axis_position as isize * profile.controller_axis[AXIS_LEFT].axis as isize > 0
{
x = (axis_position.unsigned_abs() - deadzone) as f64 * MAX_AXIS_VALUE
/ (i16::MAX as u16 - deadzone) as f64;
x *= profile.controller_axis[AXIS_LEFT].axis as f64;
}
}
if profile.controller_axis[AXIS_RIGHT].enabled {
@ -151,8 +175,12 @@ fn set_axis_from_controller(
get_axis_from_i32(profile.controller_axis[AXIS_RIGHT].id),
)
};
if axis_position as isize * profile.controller_axis[AXIS_RIGHT].axis as isize > 0 {
x = axis_position as f64 * MAX_AXIS_VALUE / i16::MAX as f64;
if axis_position.unsigned_abs() > deadzone
&& axis_position as isize * profile.controller_axis[AXIS_RIGHT].axis as isize > 0
{
x = (axis_position.unsigned_abs() - deadzone) as f64 * MAX_AXIS_VALUE
/ (i16::MAX as u16 - deadzone) as f64;
x *= profile.controller_axis[AXIS_RIGHT].axis as f64;
}
}
if profile.controller_axis[AXIS_DOWN].enabled {
@ -162,8 +190,12 @@ fn set_axis_from_controller(
get_axis_from_i32(profile.controller_axis[AXIS_DOWN].id),
)
};
if axis_position as isize * profile.controller_axis[AXIS_DOWN].axis as isize > 0 {
y = (axis_position as f64 * MAX_AXIS_VALUE / i16::MAX as f64).neg();
if axis_position.unsigned_abs() > deadzone
&& axis_position as isize * profile.controller_axis[AXIS_DOWN].axis as isize > 0
{
y = (axis_position.unsigned_abs() - deadzone) as f64 * MAX_AXIS_VALUE
/ (i16::MAX as u16 - deadzone) as f64;
y *= (profile.controller_axis[AXIS_DOWN].axis as f64).neg();
}
}
if profile.controller_axis[AXIS_UP].enabled {
@ -173,8 +205,12 @@ fn set_axis_from_controller(
get_axis_from_i32(profile.controller_axis[AXIS_UP].id),
)
};
if axis_position as isize * profile.controller_axis[AXIS_UP].axis as isize > 0 {
y = (axis_position as f64 * MAX_AXIS_VALUE / i16::MAX as f64).neg();
if axis_position.unsigned_abs() > deadzone
&& axis_position as isize * profile.controller_axis[AXIS_UP].axis as isize > 0
{
y = (axis_position.unsigned_abs() - deadzone) as f64 * MAX_AXIS_VALUE
/ (i16::MAX as u16 - deadzone) as f64;
y *= (profile.controller_axis[AXIS_UP].axis as f64).neg();
}
}
(x, y)
@ -408,10 +444,11 @@ pub fn get(ui: &ui::Ui, channel: usize) -> InputData {
(x, y) = set_axis_from_keys(profile, ui.input.keyboard_state);
}
let deadzone = (i16::MAX as i32 * profile.deadzone / 100) as u16;
if !controller.is_null() {
(x, y) = set_axis_from_controller(profile, controller)
(x, y) = set_axis_from_controller(profile, controller, deadzone)
} else if !joystick.is_null() {
(x, y) = set_axis_from_joystick(profile, joystick)
(x, y) = set_axis_from_joystick(profile, joystick, deadzone)
}
bound_axis(&mut x, &mut y);
@ -466,7 +503,7 @@ fn close_controllers(
}
}
pub fn configure_input_profile(ui: &mut ui::Ui, profile: String, dinput: bool) {
pub fn configure_input_profile(ui: &mut ui::Ui, profile: String, dinput: bool, deadzone: i32) {
ui::sdl_init(sdl3_sys::init::SDL_INIT_VIDEO);
ui::ttf_init();
@ -699,6 +736,7 @@ pub fn configure_input_profile(ui: &mut ui::Ui, profile: String, dinput: bool) {
joystick_hat: new_joystick_hat,
joystick_axis: new_joystick_axis,
dinput,
deadzone,
};
ui.config.input.input_profiles.insert(profile, new_profile);
}
@ -899,6 +937,7 @@ pub fn get_default_profile() -> ui::config::InputProfile {
axis: 0,
}; PROFILE_SIZE],
dinput: false,
deadzone: DEADZONE_DEFAULT,
}
}