Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Analog Stick Deadzone Settings #348

Merged
merged 2 commits into from
Dec 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ set(BUILD_SHARED_CORE_LIBS OFF)

if (TARGET_WEBOS)
set(CMAKE_INSTALL_LIBDIR lib/backports)
set(SDL2_BACKPORT_REVISION "e4a02636b3aee0edd5fb71318e226d7628cd7d39")
set(SDL2_BACKPORT_REVISION "c8cc2923342f82c55baef6185862badfe0af1ee3")
include(ExternalSDL2BackportForWebOS)
unset(CMAKE_INSTALL_LIBDIR)
else ()
Expand Down Expand Up @@ -337,4 +337,4 @@ elseif (TARGET_STEAMLINK)
elseif (OS_LINUX)
include(PackageDebian)
elseif (OS_WINDOWS)
endif ()
endif ()
9 changes: 9 additions & 0 deletions src/app/app_settings.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ void settings_initialize(app_settings_t *config, char *conf_dir) {
config->hdr = false;
config->hevc = true;
config->av1 = false;
config->stick_deadzone = 7;

config->conf_dir = conf_dir;
config->ini_path = path_join(conf_dir, CONF_NAME_MOONLIGHT);
Expand Down Expand Up @@ -114,6 +115,7 @@ bool settings_save(app_settings_t *config) {
ini_write_bool(fp, "hardware_mouse", config->hardware_mouse);
#endif
ini_write_bool(fp, "swap_abxy", config->swap_abxy);
ini_write_int(fp, "stick_deadzone", config->stick_deadzone);

ini_write_section(fp, "video");
ini_write_string(fp, "decoder", config->decoder);
Expand Down Expand Up @@ -254,6 +256,13 @@ static int settings_parse(app_settings_t *config, const char *section, const cha
#if FEATURE_INPUT_EVMOUSE
config->hardware_mouse = INI_IS_TRUE(value);
#endif
} else if (INI_NAME_MATCH("stick_deadzone")) {
set_int(&config->stick_deadzone, value);
if (config->stick_deadzone < 0) {
config->stick_deadzone = 0;
} else if (config->stick_deadzone > 100) {
config->stick_deadzone = 100;
}
} else if (INI_NAME_MATCH("swap_abxy")) {
config->swap_abxy = INI_IS_TRUE(value);
} else if (INI_FULL_MATCH("video", "decoder")) {
Expand Down
1 change: 1 addition & 0 deletions src/app/app_settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ typedef struct app_settings_t {
bool hdr;
bool hevc;
bool av1;
int stick_deadzone;

char *conf_dir;
char *ini_path;
Expand Down
57 changes: 36 additions & 21 deletions src/app/stream/input/session_gamepad.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ static bool gamepad_combo_check(int buttons, short combo);
static bool sensor_state_needs_update(const app_gamepad_sensor_state_t *state, uint32_t timestamp,
const float data[3]);

static bool vmouse_intercepted(stream_input_t *input, const app_gamepad_state_t *gamepad);

static bool filter_deadzone_2axis(stream_input_t *input, short *x, short *y);

void stream_input_handle_cbutton(stream_input_t *input, const SDL_ControllerButtonEvent *event) {
app_gamepad_state_t *gamepad = app_input_gamepad_state_by_instance_id(input->input, event->which);
if (gamepad == NULL) {
Expand Down Expand Up @@ -138,57 +142,49 @@ void stream_input_handle_caxis(stream_input_t *input, const SDL_ControllerAxisEv
if (gamepad == NULL) {
return;
}
bool vmouse_intercepted = false;
bool vmouse = session_input_is_vmouse_active(&input->vmouse);
switch (event->axis) {
case SDL_CONTROLLER_AXIS_LEFTX:
case SDL_CONTROLLER_AXIS_LEFTX: {
gamepad->leftStickX = SDL_max(event->value, -32767);
break;
case SDL_CONTROLLER_AXIS_LEFTY:
}
case SDL_CONTROLLER_AXIS_LEFTY: {
// Signed values have one more negative value than
// positive value, so inverting the sign on -32768
// could actually cause the value to overflow and
// wrap around to be negative again. Avoid that by
// capping the value at 32767.
gamepad->leftStickY = (short) -SDL_max(event->value, (short) -32767);
break;
}
case SDL_CONTROLLER_AXIS_RIGHTX: {
if (vmouse) {
vmouse_intercepted = true;
}
gamepad->rightStickX = SDL_max(event->value, -32767);
break;
}
case SDL_CONTROLLER_AXIS_RIGHTY: {
if (vmouse) {
vmouse_intercepted = true;
}
gamepad->rightStickY = (short) -SDL_max(event->value, (short) -32767);
break;
}
case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
if (vmouse) {
vmouse_intercepted = true;
}
case SDL_CONTROLLER_AXIS_TRIGGERLEFT: {
gamepad->leftTrigger = (char) (event->value * 255UL / 32767);
break;
case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
if (vmouse) {
vmouse_intercepted = true;
}
}
case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: {
gamepad->rightTrigger = (char) (event->value * 255UL / 32767);
break;
}
default:
return;
}
if (input->view_only) {
return;
}
if (vmouse_intercepted) {

filter_deadzone_2axis(input, &gamepad->leftStickX, &gamepad->leftStickY);
filter_deadzone_2axis(input, &gamepad->rightStickX, &gamepad->rightStickY);

if (vmouse_intercepted(input, gamepad)) {
vmouse_set_vector(&input->vmouse, gamepad->rightStickX, gamepad->rightStickY);
vmouse_set_trigger(&input->vmouse, gamepad->leftTrigger, gamepad->rightTrigger);
}
if (vmouse) {
LiSendMultiControllerEvent(gamepad->gs_id, input->input->activeGamepadMask, gamepad->buttons, 0, 0,
gamepad->leftStickX, gamepad->leftStickY, 0, 0);
} else {
Expand Down Expand Up @@ -370,4 +366,23 @@ static bool sensor_state_needs_update(const app_gamepad_sensor_state_t *state, u
}
}
return false;
}

static bool vmouse_intercepted(stream_input_t *input, const app_gamepad_state_t *gamepad) {
if (!session_input_is_vmouse_active(&input->vmouse)) {
return false;
}
return gamepad->rightStickX != 0 || gamepad->rightStickY != 0 || gamepad->leftTrigger != 0 ||
gamepad->rightTrigger != 0;
}

static bool filter_deadzone_2axis(stream_input_t *input, short *x, short *y) {
uint32_t magnitude_pow2 = (uint32_t) (*x) * (*x) + (uint32_t) (*y) * (*y);
uint32_t threshold_sqrt = 32768 * input->stick_deadzone / 100;
if (magnitude_pow2 < threshold_sqrt * threshold_sqrt) {
*x = 0;
*y = 0;
return true;
}
return false;
}
1 change: 1 addition & 0 deletions src/app/stream/input/session_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ void session_input_init(stream_input_t *input, session_t *session, app_input_t *
input->session = session;
input->input = app_input;
input->view_only = config->view_only;
input->stick_deadzone = config->stick_deadzone;
input->no_sdl_mouse = config->hardware_mouse;
#if FEATURE_INPUT_EVMOUSE
if (!config->view_only && config->hardware_mouse) {
Expand Down
2 changes: 1 addition & 1 deletion src/app/stream/input/session_input.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ typedef struct stream_input_t {
app_input_t *input;
bool started;
bool view_only, no_sdl_mouse;
bool virtual_mouse;
uint8_t stick_deadzone;
session_input_vmouse_t vmouse;
#if FEATURE_INPUT_EVMOUSE
session_evmouse_t evmouse;
Expand Down
7 changes: 7 additions & 0 deletions src/app/stream/session.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,13 @@ void session_config_init(app_t *app, session_config_t *config, const SERVER_DATA
config->local_audio = app_config->localaudio;
config->view_only = app_config->viewonly;
config->sops = app_config->sops;
if (app_config->stick_deadzone < 0) {
config->stick_deadzone = 0;
} else if (app_config->stick_deadzone > 100) {
config->stick_deadzone = 100;
} else {
config->stick_deadzone = (uint8_t) app_config->stick_deadzone;
}

SS4S_VideoCapabilities video_cap = app->ss4s.video_cap;
SS4S_AudioCapabilities audio_cap = app->ss4s.audio_cap;
Expand Down
1 change: 1 addition & 0 deletions src/app/stream/session.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ typedef struct session_config_t {
bool local_audio;
bool hardware_mouse;
bool vmouse;
uint8_t stick_deadzone;
} session_config_t;

extern int streaming_errno;
Expand Down
28 changes: 27 additions & 1 deletion src/app/ui/settings/panes/input.pane.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,22 @@ typedef struct input_pane_t {

lv_obj_t *absmouse_toggle;
lv_obj_t *absmouse_hint;
lv_obj_t *deadzone_label;
} input_pane_t;

static lv_obj_t *create_obj(lv_fragment_t *self, lv_obj_t *view);

static void pane_ctor(lv_fragment_t *self, void *args);

#if FEATURE_INPUT_EVMOUSE
static void hwmouse_state_update_cb(lv_event_t *e);

static void hwmouse_state_update(input_pane_t *pane);
#endif

static void update_deadzone_label(input_pane_t *pane);

static void on_deadzone_changed(lv_event_t *e);

const lv_fragment_class_t settings_pane_input_cls = {
.constructor_cb = pane_ctor,
Expand Down Expand Up @@ -57,6 +64,13 @@ static lv_obj_t *create_obj(lv_fragment_t *self, lv_obj_t *container) {

pref_header(view, locstr("Gamepad"));

pane->deadzone_label = pref_title_label(view, locstr("Analog stick deadzone"));
lv_obj_t *deadzone_slider = pref_slider(view, &app_configuration->stick_deadzone, 0, 20, 1);
lv_obj_set_width(deadzone_slider, LV_PCT(100));
lv_obj_add_event_cb(deadzone_slider, on_deadzone_changed, LV_EVENT_VALUE_CHANGED, pane);
pref_desc_label(view, locstr("Note: Some games can enforce a larger deadzone "
"than what Moonlight is configured to use."), false);

pref_checkbox(view, locstr("Virtual mouse"), &app_configuration->virtual_mouse, false);
pref_desc_label(view, locstr("Press LB + RT to move mouse cursor with sticks. "
"LT/RT for left/right mouse buttons."), false);
Expand All @@ -68,9 +82,11 @@ static lv_obj_t *create_obj(lv_fragment_t *self, lv_obj_t *container) {
#if FEATURE_INPUT_EVMOUSE
hwmouse_state_update(pane);
#endif
update_deadzone_label(pane);
return view;
}

#if FEATURE_INPUT_EVMOUSE
static void hwmouse_state_update_cb(lv_event_t *e) {
hwmouse_state_update((input_pane_t *) lv_event_get_user_data(e));
}
Expand All @@ -85,4 +101,14 @@ static void hwmouse_state_update(input_pane_t *pane) {
lv_label_set_text(pane->absmouse_hint, locstr("Better for remote desktop. "
"For some games, mouse will not work properly."));
}
}
}
#endif

static void update_deadzone_label(input_pane_t *pane) {
lv_label_set_text_fmt(pane->deadzone_label, locstr("Gamepad deadzone - %d%%"), app_configuration->stick_deadzone);
}

static void on_deadzone_changed(lv_event_t *e) {
input_pane_t *pane = (input_pane_t *) lv_event_get_user_data(e);
update_deadzone_label(pane);
}