2
0
mirror of https://github.com/Genymobile/scrcpy synced 2025-08-31 14:25:56 +00:00

Handle SDL gamepad events

Introduce a gamepad processor trait, similar to the keyboard processor
and mouse processor traits.

Handle gamepad events received from SDL, convert them to scrcpy-specific
gamepad events, and forward them to the gamepad processor.

Further commits will provide AOA and UHID implementations of the gamepad
processor trait.

PR #5270 <https://github.com/Genymobile/scrcpy/pull/5270>

Co-authored-by: Luiz Henrique Laurini <luizhenriquelaurini@gmail.com>
This commit is contained in:
Romain Vimont
2024-09-06 23:08:08 +02:00
parent c8479fe8bf
commit 4565f36ee6
7 changed files with 255 additions and 1 deletions

View File

@@ -56,16 +56,18 @@ void
sc_input_manager_init(struct sc_input_manager *im,
const struct sc_input_manager_params *params) {
// A key/mouse processor may not be present if there is no controller
assert((!params->kp && !params->mp) || params->controller);
assert((!params->kp && !params->mp && !params->gp) || params->controller);
// A processor must have ops initialized
assert(!params->kp || params->kp->ops);
assert(!params->mp || params->mp->ops);
assert(!params->gp || params->gp->ops);
im->controller = params->controller;
im->fp = params->fp;
im->screen = params->screen;
im->kp = params->kp;
im->mp = params->mp;
im->gp = params->gp;
im->mouse_bindings = params->mouse_bindings;
im->legacy_paste = params->legacy_paste;
@@ -920,6 +922,78 @@ sc_input_manager_process_mouse_wheel(struct sc_input_manager *im,
im->mp->ops->process_mouse_scroll(im->mp, &evt);
}
static void
sc_input_manager_process_gamepad_device(struct sc_input_manager *im,
const SDL_ControllerDeviceEvent *event) {
SDL_JoystickID id;
if (event->type == SDL_CONTROLLERDEVICEADDED) {
SDL_GameController *gc = SDL_GameControllerOpen(event->which);
if (!gc) {
LOGW("Could not open game controller");
return;
}
SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gc);
if (!joystick) {
LOGW("Could not get controller joystick");
SDL_GameControllerClose(gc);
return;
}
id = SDL_JoystickInstanceID(joystick);
} else if (event->type == SDL_CONTROLLERDEVICEREMOVED) {
id = event->which;
SDL_GameController *gc = SDL_GameControllerFromInstanceID(id);
if (gc) {
SDL_GameControllerClose(gc);
} else {
LOGW("Unknown gamepad device removed");
}
} else {
// Nothing to do
return;
}
struct sc_gamepad_device_event evt = {
.type = sc_gamepad_device_event_type_from_sdl_type(event->type),
.gamepad_id = id,
};
im->gp->ops->process_gamepad_device(im->gp, &evt);
}
static void
sc_input_manager_process_gamepad_axis(struct sc_input_manager *im,
const SDL_ControllerAxisEvent *event) {
enum sc_gamepad_axis axis = sc_gamepad_axis_from_sdl(event->axis);
if (axis == SC_GAMEPAD_AXIS_UNKNOWN) {
return;
}
struct sc_gamepad_axis_event evt = {
.gamepad_id = event->which,
.axis = axis,
.value = event->value,
};
im->gp->ops->process_gamepad_axis(im->gp, &evt);
}
static void
sc_input_manager_process_gamepad_button(struct sc_input_manager *im,
const SDL_ControllerButtonEvent *event) {
enum sc_gamepad_button button = sc_gamepad_button_from_sdl(event->button);
if (button == SC_GAMEPAD_BUTTON_UNKNOWN) {
return;
}
struct sc_gamepad_button_event evt = {
.gamepad_id = event->which,
.action = sc_action_from_sdl_controllerbutton_type(event->type),
.button = button,
};
im->gp->ops->process_gamepad_button(im->gp, &evt);
}
static bool
is_apk(const char *file) {
const char *ext = strrchr(file, '.');
@@ -992,6 +1066,27 @@ sc_input_manager_handle_event(struct sc_input_manager *im,
}
sc_input_manager_process_touch(im, &event->tfinger);
break;
case SDL_CONTROLLERDEVICEADDED:
case SDL_CONTROLLERDEVICEREMOVED:
// Handle device added or removed even if paused
if (!im->gp) {
break;
}
sc_input_manager_process_gamepad_device(im, &event->cdevice);
break;
case SDL_CONTROLLERAXISMOTION:
if (!im->gp || paused) {
break;
}
sc_input_manager_process_gamepad_axis(im, &event->caxis);
break;
case SDL_CONTROLLERBUTTONDOWN:
case SDL_CONTROLLERBUTTONUP:
if (!im->gp || paused) {
break;
}
sc_input_manager_process_gamepad_button(im, &event->cbutton);
break;
case SDL_DROPFILE: {
if (!control) {
break;