input_common: Reimplement SDL

This commit is contained in:
Narr the Reg 2022-12-07 18:57:14 -06:00
parent ea4cf3cc6b
commit 4904ef8001
2 changed files with 108 additions and 39 deletions

View File

@ -46,6 +46,7 @@ SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_en
// not a generic one
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1");
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, "1");
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_HOME_LED, "0");
// Disable hidapi driver for xbox. Already default on Windows, this causes conflict with native
// driver on Linux.
@ -84,36 +85,37 @@ SDLDriver::~SDLDriver() {
CloseJoysticks();
SDL_DelEventWatch(&SDLEventWatcher, this);
if (initialized) {
if (vibration_thread.joinable()) {
vibration_thread.join();
}
if (initialized) {
SDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER);
}
initialized = false;
}
void SDLDriver::InitJoystick(int joystick_index) {
SDL_Joystick* sdl_joystick = SDL_JoystickOpen(joystick_index);
SDL_GameController* sdl_gamecontroller = nullptr;
if (SDL_IsGameController(joystick_index)) {
sdl_gamecontroller = SDL_GameControllerOpen(joystick_index);
}
if (!sdl_joystick) {
LOG_ERROR(Input, "Failed to open joystick {}", joystick_index);
return;
}
std::shared_ptr<SDLDriver::JoystickID> SDLDriver::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) {
auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id);
const auto guid = GetGUID(sdl_joystick);
}
void SDLDriver::CloseJoystick(SDL_Joystick* sdl_joystick) {
const auto guid = GetGUID(sdl_joystick);
}
void SDLDriver::CloseJoysticks() {
std::scoped_lock lock{joystick_map_mutex};
const auto map_it = joystick_map.find(guid);
if (map_it == joystick_map.end()) {
return nullptr;
}
const auto vec_it =
std::find_if(map_it->second.begin(), map_it->second.end(),
[sdl_id](const auto& joystick) { return joystick->sdl_index == sdl_id; });
if (vec_it == map_it->second.end()) {
return nullptr;
}
return *vec_it;
}
void SDLDriver::PumpEvents() const {
@ -124,32 +126,87 @@ void SDLDriver::PumpEvents() const {
void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) {
switch (event.type) {
case SDL_JOYBUTTONUP: {
case SDL_JOYBUTTONUP:
case SDL_JOYBUTTONDOWN:
case SDL_JOYHATMOTION:
case SDL_JOYAXISMOTION:
case SDL_CONTROLLERSENSORUPDATE:
UpdateControllerStatus(event.type, event.jdevice.which);
break;
}
case SDL_JOYBUTTONDOWN: {
break;
}
case SDL_JOYHATMOTION: {
break;
}
case SDL_JOYAXISMOTION: {
break;
}
case SDL_CONTROLLERSENSORUPDATE: {
break;
}
case SDL_JOYDEVICEREMOVED:
LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which);
CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which));
CloseJoystick(event.jdevice.which);
break;
case SDL_JOYDEVICEADDED:
LOG_DEBUG(Input, "Controller connected with device index {}", event.jdevice.which);
InitJoystick(event.jdevice.which);
break;
}
}
void SDLDriver::InitJoystick(int joystick_index) {
LOG_DEBUG(Input, "Controller connected with device index {}", joystick_index);
SDL_Joystick* sdl_joystick = SDL_JoystickOpen(joystick_index);
SDL_GameController* sdl_gamecontroller = nullptr;
if (!sdl_joystick) {
LOG_ERROR(Input, "Failed to open joystick {}", joystick_index);
return;
}
const auto guid = GetGUID(sdl_joystick);
const auto joystick = GetSDLJoystickBySDLID(joystick_index);
PreSetController(joystick->identifier);
if (SDL_IsGameController(joystick_index)) {
sdl_gamecontroller = SDL_GameControllerOpen(joystick_index);
}
if (sdl_gamecontroller) {
SetBattery(joystick->identifier, GetBatteryLevel(joystick_index));
if (SDL_GameControllerHasSensor(sdl_gamecontroller, SDL_SENSOR_ACCEL) == SDL_TRUE) {
SDL_GameControllerSetSensorEnabled(sdl_gamecontroller, SDL_SENSOR_ACCEL, SDL_TRUE);
}
if (SDL_GameControllerHasSensor(sdl_gamecontroller, SDL_SENSOR_GYRO) == SDL_TRUE) {
SDL_GameControllerSetSensorEnabled(sdl_gamecontroller, SDL_SENSOR_GYRO, SDL_TRUE);
}
}
}
void SDLDriver::CloseJoystick(int joystick_index) {
LOG_DEBUG(Input, "Controller removed with device index {}", joystick_index);
std::scoped_lock lock{joystick_map_mutex};
}
void SDLDriver::CloseJoysticks() {
std::scoped_lock lock{joystick_map_mutex};
joystick_map.clear();
}
void SDLDriver::UpdateControllerStatus(u32 event, int joystick_index, int index, int value) {
const auto joystick = GetSDLJoystickBySDLID(joystick_index);
switch (event) {
case SDL_JOYBATTERYUPDATED:
SetBattery(joystick->identifier, GetBatteryLevel(value));
case SDL_JOYBUTTONUP:
SetButton(joystick->identifier, index, false);
break;
case SDL_JOYBUTTONDOWN:
SetButton(joystick->identifier, index, true);
break;
case SDL_JOYHATMOTION:
SetHatButton(joystick->identifier, index, value);
break;
case SDL_JOYAXISMOTION:
SetAxis(joystick->identifier, index, value / 32767.0f);
break;
case SDL_CONTROLLERSENSORUPDATE:
SetMotion(joystick->identifier, 0, GetMotion(joystick_index));
break;
default:
break;
}
}
bool SDLDriver::IsStickInverted(const Common::ParamPackage& params) {
if (!params.Has("guid") || !params.Has("port")) {
return false;
@ -166,7 +223,6 @@ Common::Input::VibrationError SDLDriver::SetVibration(
return Common::Input::VibrationError::None;
}
void SDLDriver::SendVibrations() {
std::vector<VibrationRequest> filtered_vibrations{};
while (!vibration_queue.Empty()) {

View File

@ -57,16 +57,29 @@ private:
Common::Input::VibrationStatus vibration;
};
struct JoystickID {
int sdl_index;
bool has_rumble;
PadIdentifier identifier;
};
std::shared_ptr<JoystickID> GetSDLJoystickBySDLID(SDL_JoystickID sdl_id);
void InitJoystick(int joystick_index);
void CloseJoystick(SDL_Joystick* sdl_joystick);
void CloseJoystick(int joystick_index);
/// Needs to be called before SDL_QuitSubSystem.
void CloseJoysticks();
void UpdateControllerStatus(u32 event, int joystick_index, int index, int value);
Common::Input::BatteryLevel GetBatteryLevel(int value);
/// Takes all vibrations from the queue and sends the command to the controller
void SendVibrations();
/// Map of GUID of a list of corresponding virtual Joysticks
std::unordered_map<Common::UUID, std::vector<std::shared_ptr<JoystickID>>> joystick_map;
std::mutex joystick_map_mutex;
std::atomic<bool> initialized = false;