From 7356286fe0412dca904fbc9cbf45312c2fbfe114 Mon Sep 17 00:00:00 2001 From: Dominic Masters Date: Wed, 11 Mar 2026 13:00:11 -0500 Subject: [PATCH] Adjust how deadzones work --- assets/init.lua | 4 +- assets/scene/minesweeper.lua | 17 +------- src/dusk/input/input.c | 9 +++-- src/dusk/input/input.h | 17 +++++--- src/dusk/script/module/input/moduleinput.c | 25 ++++++++++++ src/dusk/script/module/input/moduleinput.h | 10 ++++- src/dusk/util/string.c | 7 ++++ src/dusk/util/string.h | 11 +++++- src/duskdolphin/input/inputdolphin.c | 46 +++++++++------------- src/duskdolphin/input/inputdolphin.h | 10 ++++- src/dusklinux/input/inputlinux.c | 6 ++- src/duskpsp/input/inputpsp.c | 14 ++++--- src/dusksdl2/input/inputsdl2.c | 5 +-- src/dusksdl2/input/inputsdl2.h | 9 +++++ 14 files changed, 126 insertions(+), 64 deletions(-) diff --git a/assets/init.lua b/assets/init.lua index beee571..033f11e 100644 --- a/assets/init.lua +++ b/assets/init.lua @@ -30,7 +30,7 @@ elseif DOLPHIN then inputBind("lstick_left", INPUT_ACTION_LEFT) inputBind("lstick_right", INPUT_ACTION_RIGHT) -else +elseif LINUX then if INPUT_KEYBOARD then inputBind("w", INPUT_ACTION_UP) inputBind("s", INPUT_ACTION_DOWN) @@ -70,6 +70,8 @@ else inputBind("mouse_x", INPUT_ACTION_POINTERX) inputBind("mouse_y", INPUT_ACTION_POINTERY) end +else + print("Unknown platform, no default input bindings set.") end sceneSet('scene/minesweeper.lua') \ No newline at end of file diff --git a/assets/scene/minesweeper.lua b/assets/scene/minesweeper.lua index bcafd1e..993693e 100644 --- a/assets/scene/minesweeper.lua +++ b/assets/scene/minesweeper.lua @@ -178,21 +178,8 @@ function sceneDispose() end function sceneUpdate() - if inputIsDown(INPUT_ACTION_RIGHT) then - x = x + 1 - end - - if inputIsDown(INPUT_ACTION_LEFT) then - x = x - 1 - end - - if inputIsDown(INPUT_ACTION_DOWN) then - y = y + 1 - end - - if inputIsDown(INPUT_ACTION_UP) then - y = y - 1 - end + x = x + inputAxis(INPUT_ACTION_LEFT, INPUT_ACTION_RIGHT) + y = y + inputAxis(INPUT_ACTION_UP, INPUT_ACTION_DOWN) end diff --git a/src/dusk/input/input.c b/src/dusk/input/input.c index b128608..1dd1351 100644 --- a/src/dusk/input/input.c +++ b/src/dusk/input/input.c @@ -23,10 +23,6 @@ errorret_t inputInit(void) { INPUT.actions[i].currentValue = 0.0f; } - #ifdef DUSK_INPUT_GAMEPAD - INPUT.deadzone = 0.2f; - #endif - #ifdef inputInitPlatform errorChain(inputInitPlatform()); #endif @@ -194,4 +190,9 @@ void inputBind(const inputbutton_t button, const inputaction_t act) { // Bind the action. data->action = act; +} + +float_t inputDeadzone(const float_t rawValue, const float_t deadzone) { + if(rawValue < deadzone) return 0.0f; + return (rawValue - deadzone) / (1.0f - deadzone); } \ No newline at end of file diff --git a/src/dusk/input/input.h b/src/dusk/input/input.h index b5281f9..c597321 100644 --- a/src/dusk/input/input.h +++ b/src/dusk/input/input.h @@ -27,10 +27,6 @@ typedef struct { event_t eventReleased; inputplatform_t platform; - - #ifdef DUSK_INPUT_GAMEPAD - float_t deadzone; - #endif } input_t; extern input_t INPUT; @@ -130,4 +126,15 @@ float_t inputAxis(const inputaction_t neg, const inputaction_t pos); * @param button The input button to bind. * @param action The input action to bind the button to. */ -void inputBind(const inputbutton_t button, const inputaction_t act); \ No newline at end of file +void inputBind(const inputbutton_t button, const inputaction_t act); + +/** + * Applies deadzone formula to a raw input value. This will; + * return 0 if input is less than the deadzone. + * re-map the range between 0 and 1 in deadzone-space. + * + * @param rawValue The raw input value to apply the deadzone to. + * @param deadzone The deadzone threshold (0.0f to 1.0f). + * @return The input value after applying the deadzone. + */ +float_t inputDeadzone(const float_t rawValue, const float_t deadzone); \ No newline at end of file diff --git a/src/dusk/script/module/input/moduleinput.c b/src/dusk/script/module/input/moduleinput.c index 48056e7..d9293a5 100644 --- a/src/dusk/script/module/input/moduleinput.c +++ b/src/dusk/script/module/input/moduleinput.c @@ -53,6 +53,7 @@ void moduleInput(scriptcontext_t *context) { lua_register(context->luaState, "inputPressed", moduleInputPressed); lua_register(context->luaState, "inputReleased", moduleInputReleased); lua_register(context->luaState, "inputGetValue", moduleInputGetValue); + lua_register(context->luaState, "inputAxis", moduleInputAxis); } int moduleInputIndex(lua_State *l) { @@ -189,4 +190,28 @@ int moduleInputGetValue(lua_State *L) { lua_pushnumber(L, inputGetCurrentValue(action)); return 1; +} + +int moduleInputAxis(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + + if(!lua_isnumber(L, 1) || !lua_isnumber(L, 2)) { + luaL_error(L, "inputAxis: Expected two action IDs as arguments (neg, pos)"); + return 0; + } + + const inputaction_t neg = (inputaction_t)lua_tonumber(L, 1); + const inputaction_t pos = (inputaction_t)lua_tonumber(L, 2); + + if(neg < INPUT_ACTION_NULL || neg >= INPUT_ACTION_COUNT) { + luaL_error(L, "inputAxis: Invalid negative action ID %d", neg); + return 0; + } + if(pos < INPUT_ACTION_NULL || pos >= INPUT_ACTION_COUNT) { + luaL_error(L, "inputAxis: Invalid positive action ID %d", pos); + return 0; + } + + lua_pushnumber(L, inputAxis(neg, pos)); + return 1; } \ No newline at end of file diff --git a/src/dusk/script/module/input/moduleinput.h b/src/dusk/script/module/input/moduleinput.h index 1ff6391..ff3e905 100644 --- a/src/dusk/script/module/input/moduleinput.h +++ b/src/dusk/script/module/input/moduleinput.h @@ -60,4 +60,12 @@ int moduleInputReleased(lua_State *L); * @param L The Lua state. * @return Number of return values on the Lua stack. */ -int moduleInputGetValue(lua_State *L); \ No newline at end of file +int moduleInputGetValue(lua_State *L); + +/** + * Script binding for inputAxis. + * + * @param L The Lua state. + * @return Number of return values on the Lua stack. + */ +int moduleInputAxis(lua_State *L); \ No newline at end of file diff --git a/src/dusk/util/string.c b/src/dusk/util/string.c index 918962f..4e00cdb 100644 --- a/src/dusk/util/string.c +++ b/src/dusk/util/string.c @@ -228,4 +228,11 @@ bool_t stringEndsWithCaseInsensitive( size_t suffixLen = strlen(suffix); if(suffixLen > strLen) return false; return strcasecmp(str + strLen - suffixLen, suffix) == 0; +} + +bool_t stringIncludesString(const char_t *haystack, const char_t *needle) { + assertNotNull(haystack, "haystack must not be NULL"); + assertNotNull(needle, "needle must not be NULL"); + + return strstr(haystack, needle) != NULL; } \ No newline at end of file diff --git a/src/dusk/util/string.h b/src/dusk/util/string.h index c6e2887..8b21ae2 100644 --- a/src/dusk/util/string.h +++ b/src/dusk/util/string.h @@ -160,4 +160,13 @@ bool_t stringEndsWith(const char_t *str, const char_t *suffix); * @param suffix The suffix to check for. * @return TRUE if the string ends with the suffix, FALSE otherwise. */ -bool_t stringEndsWithCaseInsensitive(const char_t *str, const char_t *suffix); \ No newline at end of file +bool_t stringEndsWithCaseInsensitive(const char_t *str, const char_t *suffix); + +/** + * Determines if a string includes a specified substring. + * + * @param haystack The string to check. + * @param needle The substring to check for. + * @return TRUE if the string includes the substring, FALSE otherwise. + */ +bool_t stringIncludesString(const char_t *haystack, const char_t *needle); \ No newline at end of file diff --git a/src/duskdolphin/input/inputdolphin.c b/src/duskdolphin/input/inputdolphin.c index e8270a5..6779017 100644 --- a/src/duskdolphin/input/inputdolphin.c +++ b/src/duskdolphin/input/inputdolphin.c @@ -7,6 +7,8 @@ #include "input/input.h" #include "assert/assert.h" +#include "log/log.h" +#include "util/string.h" inputbuttondata_t INPUT_BUTTON_DATA[] = { #ifdef DUSK_INPUT_GAMEPAD @@ -26,13 +28,14 @@ inputbuttondata_t INPUT_BUTTON_DATA[] = { { .name = "lstick_up", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_LEFT_X, .positive = true } } }, { .name = "lstick_down", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_LEFT_X, .positive = false } } }, { .name = "lstick_left", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_LEFT_Y, .positive = true } } }, - { .name = "lstick_right", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_LEFT_Y, .positive = false } } }, { .name = "rstick_up", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_C_X, .positive = true } } }, { .name = "rstick_down", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_C_X, .positive = false } } }, { .name = "rstick_left", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_C_Y, .positive = true } } }, { .name = "rstick_right", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_C_Y, .positive = false } } }, + { .name = "lstick_right", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_LEFT_Y, .positive = false } } }, { .name = "ltrigger", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_TRIGGER_LEFT, .positive = true } } }, { .name = "rtrigger", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_TRIGGER_RIGHT, .positive = true } } }, + #endif { .name = NULL } @@ -51,29 +54,13 @@ void inputUpdateDolphin(void) { for(uint8_t i = 0; i < INPUT_DOLPHIN_PAD_COUNT; i++) { INPUT.platform.padState[i] = PAD_ButtonsHeld(i); - INPUT.platform.pads[i][INPUT_GAMEPAD_AXIS_LEFT_X] = ( - INPUT_DOLPHIN_AXIS(PAD_StickX(i)) - ); - - INPUT.platform.pads[i][INPUT_GAMEPAD_AXIS_LEFT_Y] = ( - INPUT_DOLPHIN_AXIS(PAD_StickY(i)) - ); - - INPUT.platform.pads[i][INPUT_GAMEPAD_AXIS_C_X] = ( - INPUT_DOLPHIN_AXIS(PAD_SubStickX(i)) - ); - - INPUT.platform.pads[i][INPUT_GAMEPAD_AXIS_C_Y] = ( - INPUT_DOLPHIN_AXIS(PAD_SubStickY(i)) - ); - - INPUT.platform.pads[i][INPUT_GAMEPAD_AXIS_TRIGGER_LEFT] = ( - INPUT_DOLPHIN_AXIS(PAD_TriggerL(i)) - ); - - INPUT.platform.pads[i][INPUT_GAMEPAD_AXIS_TRIGGER_RIGHT] = ( - INPUT_DOLPHIN_AXIS(PAD_TriggerR(i)) - ); + INPUT.platform.pads[i][INPUT_GAMEPAD_AXIS_LEFT_X] = PAD_StickX(i); + INPUT.platform.pads[i][INPUT_GAMEPAD_AXIS_LEFT_Y] = PAD_StickY(i); + INPUT.platform.pads[i][INPUT_GAMEPAD_AXIS_C_X] = PAD_SubStickX(i); + INPUT.platform.pads[i][INPUT_GAMEPAD_AXIS_C_Y] = PAD_SubStickY(i); + INPUT.platform.pads[i][INPUT_GAMEPAD_AXIS_TRIGGER_LEFT]=PAD_TriggerL(i); + INPUT.platform.pads[i][INPUT_GAMEPAD_AXIS_TRIGGER_RIGHT]=PAD_TriggerR(i); + // Because gamecube sticks are hexagons this is going to be weird. } #endif } @@ -87,10 +74,11 @@ float_t inputButtonGetValueDolphin(const inputbutton_t button) { } case INPUT_BUTTON_TYPE_GAMEPAD_AXIS: { - float_t value = INPUT.platform.pads[0][button.gpAxis.axis]; + float_t axis = INPUT.platform.pads[0][button.gpAxis.axis]; + float_t value = axis / 128.0f; if(!button.gpAxis.positive) value = -value; - if(value >= INPUT.deadzone) return value; - return 0.0f; + value = inputDeadzone(value, inputGetDeadzoneDolphin(button)); + return value; } #endif @@ -99,4 +87,8 @@ float_t inputButtonGetValueDolphin(const inputbutton_t button) { return 0.0f; } } +} + +float_t inputGetDeadzoneDolphin(const inputbutton_t button) { + return 0.2f; } \ No newline at end of file diff --git a/src/duskdolphin/input/inputdolphin.h b/src/duskdolphin/input/inputdolphin.h index 7884d01..2f13005 100644 --- a/src/duskdolphin/input/inputdolphin.h +++ b/src/duskdolphin/input/inputdolphin.h @@ -63,4 +63,12 @@ void inputUpdateDolphin(void); * @param button The button to get the value of. * @return The value of the button, between 0 and 1. */ -float_t inputButtonGetValueDolphin(const inputbutton_t button); \ No newline at end of file +float_t inputButtonGetValueDolphin(const inputbutton_t button); + +/** + * Returns the deadzone for the given button. + * + * @param button The button to get the deadzone of. + * @return The deadzone for the button, between 0 and 1. + */ +float_t inputGetDeadzoneDolphin(const inputbutton_t button); \ No newline at end of file diff --git a/src/dusklinux/input/inputlinux.c b/src/dusklinux/input/inputlinux.c index 350672e..1eb10ca 100644 --- a/src/dusklinux/input/inputlinux.c +++ b/src/dusklinux/input/inputlinux.c @@ -182,4 +182,8 @@ inputbuttondata_t INPUT_BUTTON_DATA[] = { #endif { .name = NULL }, -}; \ No newline at end of file +}; + +float_t inputGetDeadzoneSDL2(const inputbutton_t button) { + return 0.17f; +} \ No newline at end of file diff --git a/src/duskpsp/input/inputpsp.c b/src/duskpsp/input/inputpsp.c index 3d14b85..7b1d70c 100644 --- a/src/duskpsp/input/inputpsp.c +++ b/src/duskpsp/input/inputpsp.c @@ -21,10 +21,14 @@ inputbuttondata_t INPUT_BUTTON_DATA[] = { { .name = "l", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = SDL_CONTROLLER_BUTTON_LEFTSHOULDER } }, { .name = "r", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER } }, - { .name = "lstick_down", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = SDL_CONTROLLER_AXIS_LEFTX, .positive = true } } }, - { .name = "lstick_up", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = SDL_CONTROLLER_AXIS_LEFTX, .positive = false } } }, - { .name = "lstick_right", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = SDL_CONTROLLER_AXIS_LEFTY, .positive = true } } }, - { .name = "lstick_left", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = SDL_CONTROLLER_AXIS_LEFTY, .positive = false } } }, + { .name = "lstick_down", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = SDL_CONTROLLER_AXIS_LEFTY, .positive = true } } }, + { .name = "lstick_up", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = SDL_CONTROLLER_AXIS_LEFTY, .positive = false } } }, + { .name = "lstick_right", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = SDL_CONTROLLER_AXIS_LEFTX, .positive = true } } }, + { .name = "lstick_left", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = SDL_CONTROLLER_AXIS_LEFTX, .positive = false } } }, { .name = NULL } -}; \ No newline at end of file +}; + +float_t inputGetDeadzoneSDL2(const inputbutton_t button) { + return 0.17f; +} \ No newline at end of file diff --git a/src/dusksdl2/input/inputsdl2.c b/src/dusksdl2/input/inputsdl2.c index 79ef30e..e1ac5b7 100644 --- a/src/dusksdl2/input/inputsdl2.c +++ b/src/dusksdl2/input/inputsdl2.c @@ -88,10 +88,9 @@ float_t inputButtonGetValueSDL2(const inputbutton_t button) { INPUT.platform.controller, button.gpAxis.axis ); value = (float_t)axis / 32767.0f; - if(!button.gpAxis.positive) value = -value; - if(value >= INPUT.deadzone) return value; - return 0.0f; + value = inputDeadzone(value, inputGetDeadzoneSDL2(button)); + return value; } #endif diff --git a/src/dusksdl2/input/inputsdl2.h b/src/dusksdl2/input/inputsdl2.h index ffec370..9b3af5c 100644 --- a/src/dusksdl2/input/inputsdl2.h +++ b/src/dusksdl2/input/inputsdl2.h @@ -49,6 +49,15 @@ typedef struct { */ void inputUpdateSDL2(void); +/** + * Returns the deadzone for the given gamepad axis. Requires implementation by + * the host platform. + * + * @param button The button to get the deadzone of. + * @return The deadzone for the given gamepad axis. + */ +float_t inputGetDeadzoneSDL2(const inputbutton_t button); + /** * Returns the input value (between 0 and 1) of the given button. *