mirror of
https://github.com/moonlight-stream/moonlight-embedded.git
synced 2025-07-02 07:45:48 +00:00
Implement controller hotplugging for SDL
This commit is contained in:
parent
634a0eee15
commit
bbdd7e5b24
109
src/input/sdl.c
109
src/input/sdl.c
@ -33,6 +33,7 @@ typedef struct _GAMEPAD_STATE {
|
|||||||
short rightStickX, rightStickY;
|
short rightStickX, rightStickY;
|
||||||
int buttons;
|
int buttons;
|
||||||
SDL_JoystickID sdl_id;
|
SDL_JoystickID sdl_id;
|
||||||
|
SDL_GameController* controller;
|
||||||
SDL_Haptic* haptic;
|
SDL_Haptic* haptic;
|
||||||
int haptic_effect_id;
|
int haptic_effect_id;
|
||||||
short id;
|
short id;
|
||||||
@ -46,40 +47,84 @@ static int activeGamepadMask = 0;
|
|||||||
|
|
||||||
int sdl_gamepads = 0;
|
int sdl_gamepads = 0;
|
||||||
|
|
||||||
static PGAMEPAD_STATE get_gamepad(SDL_JoystickID sdl_id) {
|
static PGAMEPAD_STATE get_gamepad(SDL_JoystickID sdl_id, bool add) {
|
||||||
|
// See if a gamepad already exists
|
||||||
|
for (int i = 0;i<4;i++) {
|
||||||
|
if (gamepads[i].initialized && gamepads[i].sdl_id == sdl_id)
|
||||||
|
return &gamepads[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!add)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
for (int i = 0;i<4;i++) {
|
for (int i = 0;i<4;i++) {
|
||||||
if (!gamepads[i].initialized) {
|
if (!gamepads[i].initialized) {
|
||||||
gamepads[i].sdl_id = sdl_id;
|
gamepads[i].sdl_id = sdl_id;
|
||||||
gamepads[i].id = i;
|
gamepads[i].id = i;
|
||||||
gamepads[i].initialized = true;
|
gamepads[i].initialized = true;
|
||||||
|
|
||||||
|
// This will cause connection of the virtual controller on the host PC
|
||||||
activeGamepadMask |= (1 << i);
|
activeGamepadMask |= (1 << i);
|
||||||
|
LiSendMultiControllerEvent(i, activeGamepadMask, 0, 0, 0, 0, 0, 0, 0);
|
||||||
|
|
||||||
return &gamepads[i];
|
return &gamepads[i];
|
||||||
} else if (gamepads[i].sdl_id == sdl_id)
|
}
|
||||||
return &gamepads[i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return &gamepads[0];
|
return &gamepads[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_gamepad(int joystick_index) {
|
static void add_gamepad(int joystick_index) {
|
||||||
if (SDL_IsGameController(joystick_index)) {
|
SDL_GameController* controller = SDL_GameControllerOpen(joystick_index);
|
||||||
sdl_gamepads++;
|
if (!controller) {
|
||||||
SDL_GameController* controller = SDL_GameControllerOpen(joystick_index);
|
fprintf(stderr, "Could not open gamecontroller %i: %s\n", joystick_index, SDL_GetError());
|
||||||
if (!controller) {
|
return;
|
||||||
fprintf(stderr, "Could not open gamecontroller %i: %s\n", joystick_index, SDL_GetError());
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_Joystick* joystick = SDL_GameControllerGetJoystick(controller);
|
SDL_Joystick* joystick = SDL_GameControllerGetJoystick(controller);
|
||||||
SDL_Haptic* haptic = SDL_HapticOpenFromJoystick(joystick);
|
SDL_JoystickID joystick_id = SDL_JoystickInstanceID(joystick);
|
||||||
if (haptic && (SDL_HapticQuery(haptic) & SDL_HAPTIC_LEFTRIGHT) == 0) {
|
|
||||||
SDL_HapticClose(haptic);
|
|
||||||
haptic = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_JoystickID sdl_id = SDL_JoystickInstanceID(joystick);
|
if (get_gamepad(joystick_id, false)) {
|
||||||
PGAMEPAD_STATE state = get_gamepad(joystick_index);
|
// Already added
|
||||||
state->haptic = haptic;
|
SDL_GameControllerClose(controller);
|
||||||
state->haptic_effect_id = -1;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Haptic* haptic = SDL_HapticOpenFromJoystick(joystick);
|
||||||
|
if (haptic && (SDL_HapticQuery(haptic) & SDL_HAPTIC_LEFTRIGHT) == 0) {
|
||||||
|
SDL_HapticClose(haptic);
|
||||||
|
haptic = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
PGAMEPAD_STATE state = get_gamepad(joystick_id, true);
|
||||||
|
state->controller = controller;
|
||||||
|
state->haptic = haptic;
|
||||||
|
state->haptic_effect_id = -1;
|
||||||
|
|
||||||
|
sdl_gamepads++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void remove_gamepad(SDL_JoystickID sdl_id) {
|
||||||
|
for (int i = 0;i<4;i++) {
|
||||||
|
if (gamepads[i].initialized && gamepads[i].sdl_id == sdl_id) {
|
||||||
|
if (gamepads[i].haptic_effect_id >= 0) {
|
||||||
|
SDL_HapticDestroyEffect(gamepads[i].haptic, gamepads[i].haptic_effect_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gamepads[i].haptic) {
|
||||||
|
SDL_HapticClose(gamepads[i].haptic);
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_GameControllerClose(gamepads[i].controller);
|
||||||
|
|
||||||
|
// This will cause disconnection of the virtual controller on the host PC
|
||||||
|
activeGamepadMask &= ~(1 << i);
|
||||||
|
LiSendMultiControllerEvent(i, activeGamepadMask, 0, 0, 0, 0, 0, 0, 0);
|
||||||
|
|
||||||
|
memset(&gamepads[i], 0, sizeof(*gamepads));
|
||||||
|
sdl_gamepads--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,8 +135,12 @@ void sdlinput_init(char* mappings) {
|
|||||||
SDL_InitSubSystem(SDL_INIT_HAPTIC);
|
SDL_InitSubSystem(SDL_INIT_HAPTIC);
|
||||||
SDL_GameControllerAddMappingsFromFile(mappings);
|
SDL_GameControllerAddMappingsFromFile(mappings);
|
||||||
|
|
||||||
for (int i = 0; i < SDL_NumJoysticks(); ++i)
|
// Add game controllers here to ensure an accurate count
|
||||||
init_gamepad(i);
|
// goes to the host when starting a new session.
|
||||||
|
for (int i = 0; i < SDL_NumJoysticks(); ++i) {
|
||||||
|
if (SDL_IsGameController(i))
|
||||||
|
add_gamepad(i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int sdlinput_handle_event(SDL_Event* event) {
|
int sdlinput_handle_event(SDL_Event* event) {
|
||||||
@ -184,7 +233,9 @@ int sdlinput_handle_event(SDL_Event* event) {
|
|||||||
LiSendKeyboardEvent(0x80 << 8 | button, event->type==SDL_KEYDOWN?KEY_ACTION_DOWN:KEY_ACTION_UP, keyboard_modifiers);
|
LiSendKeyboardEvent(0x80 << 8 | button, event->type==SDL_KEYDOWN?KEY_ACTION_DOWN:KEY_ACTION_UP, keyboard_modifiers);
|
||||||
break;
|
break;
|
||||||
case SDL_CONTROLLERAXISMOTION:
|
case SDL_CONTROLLERAXISMOTION:
|
||||||
gamepad = get_gamepad(event->caxis.which);
|
gamepad = get_gamepad(event->caxis.which, false);
|
||||||
|
if (!gamepad)
|
||||||
|
return SDL_NOTHING;
|
||||||
switch (event->caxis.axis) {
|
switch (event->caxis.axis) {
|
||||||
case SDL_CONTROLLER_AXIS_LEFTX:
|
case SDL_CONTROLLER_AXIS_LEFTX:
|
||||||
gamepad->leftStickX = event->caxis.value;
|
gamepad->leftStickX = event->caxis.value;
|
||||||
@ -211,7 +262,9 @@ int sdlinput_handle_event(SDL_Event* event) {
|
|||||||
break;
|
break;
|
||||||
case SDL_CONTROLLERBUTTONDOWN:
|
case SDL_CONTROLLERBUTTONDOWN:
|
||||||
case SDL_CONTROLLERBUTTONUP:
|
case SDL_CONTROLLERBUTTONUP:
|
||||||
gamepad = get_gamepad(event->cbutton.which);
|
gamepad = get_gamepad(event->cbutton.which, false);
|
||||||
|
if (!gamepad)
|
||||||
|
return SDL_NOTHING;
|
||||||
switch (event->cbutton.button) {
|
switch (event->cbutton.button) {
|
||||||
case SDL_CONTROLLER_BUTTON_A:
|
case SDL_CONTROLLER_BUTTON_A:
|
||||||
button = A_FLAG;
|
button = A_FLAG;
|
||||||
@ -271,6 +324,12 @@ int sdlinput_handle_event(SDL_Event* event) {
|
|||||||
|
|
||||||
LiSendMultiControllerEvent(gamepad->id, activeGamepadMask, gamepad->buttons, gamepad->leftTrigger, gamepad->rightTrigger, gamepad->leftStickX, gamepad->leftStickY, gamepad->rightStickX, gamepad->rightStickY);
|
LiSendMultiControllerEvent(gamepad->id, activeGamepadMask, gamepad->buttons, gamepad->leftTrigger, gamepad->rightTrigger, gamepad->leftStickX, gamepad->leftStickY, gamepad->rightStickX, gamepad->rightStickY);
|
||||||
break;
|
break;
|
||||||
|
case SDL_CONTROLLERDEVICEADDED:
|
||||||
|
add_gamepad(event->cdevice.which);
|
||||||
|
break;
|
||||||
|
case SDL_CONTROLLERDEVICEREMOVED:
|
||||||
|
remove_gamepad(event->cdevice.which);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return SDL_NOTHING;
|
return SDL_NOTHING;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user