diff options
author | comex <comexk@gmail.com> | 2023-07-02 00:01:11 +0200 |
---|---|---|
committer | comex <comexk@gmail.com> | 2023-07-02 00:01:11 +0200 |
commit | 98685d48e3cb9f25f6919f004ec62cadf33afad2 (patch) | |
tree | 9df2ce7f57370641589bfae7196c77b090bcbe0f /src/input_common/drivers | |
parent | PR feedback + constification (diff) | |
parent | Update translations (2023-07-01) (#10972) (diff) | |
download | yuzu-98685d48e3cb9f25f6919f004ec62cadf33afad2.tar yuzu-98685d48e3cb9f25f6919f004ec62cadf33afad2.tar.gz yuzu-98685d48e3cb9f25f6919f004ec62cadf33afad2.tar.bz2 yuzu-98685d48e3cb9f25f6919f004ec62cadf33afad2.tar.lz yuzu-98685d48e3cb9f25f6919f004ec62cadf33afad2.tar.xz yuzu-98685d48e3cb9f25f6919f004ec62cadf33afad2.tar.zst yuzu-98685d48e3cb9f25f6919f004ec62cadf33afad2.zip |
Diffstat (limited to '')
-rw-r--r-- | src/input_common/drivers/joycon.cpp | 158 | ||||
-rw-r--r-- | src/input_common/drivers/joycon.h | 19 | ||||
-rw-r--r-- | src/input_common/drivers/mouse.cpp | 99 | ||||
-rw-r--r-- | src/input_common/drivers/mouse.h | 2 | ||||
-rw-r--r-- | src/input_common/drivers/sdl_driver.cpp | 32 | ||||
-rw-r--r-- | src/input_common/drivers/virtual_amiibo.cpp | 130 | ||||
-rw-r--r-- | src/input_common/drivers/virtual_amiibo.h | 16 |
7 files changed, 356 insertions, 100 deletions
diff --git a/src/input_common/drivers/joycon.cpp b/src/input_common/drivers/joycon.cpp index b2b5677c8..0aca5a3a3 100644 --- a/src/input_common/drivers/joycon.cpp +++ b/src/input_common/drivers/joycon.cpp @@ -102,12 +102,12 @@ bool Joycons::IsDeviceNew(SDL_hid_device_info* device_info) const { Joycon::SerialNumber serial_number{}; const auto result = Joycon::JoyconDriver::GetDeviceType(device_info, type); - if (result != Joycon::DriverResult::Success) { + if (result != Common::Input::DriverResult::Success) { return false; } const auto result2 = Joycon::JoyconDriver::GetSerialNumber(device_info, serial_number); - if (result2 != Joycon::DriverResult::Success) { + if (result2 != Common::Input::DriverResult::Success) { return false; } @@ -171,10 +171,10 @@ void Joycons::RegisterNewDevice(SDL_hid_device_info* device_info) { LOG_WARNING(Input, "No free handles available"); return; } - if (result == Joycon::DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = handle->RequestDeviceAccess(device_info); } - if (result == Joycon::DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { LOG_WARNING(Input, "Initialize device"); const std::size_t port = handle->GetDevicePort(); @@ -195,8 +195,8 @@ void Joycons::RegisterNewDevice(SDL_hid_device_info* device_info) { OnMotionUpdate(port, type, id, value); }}, .on_ring_data = {[this](f32 ring_data) { OnRingConUpdate(ring_data); }}, - .on_amiibo_data = {[this, port, type](const std::vector<u8>& amiibo_data) { - OnAmiiboUpdate(port, type, amiibo_data); + .on_amiibo_data = {[this, port, type](const Joycon::TagInfo& tag_info) { + OnAmiiboUpdate(port, type, tag_info); }}, .on_camera_data = {[this, port](const std::vector<u8>& camera_data, Joycon::IrsResolution format) { @@ -273,8 +273,7 @@ Common::Input::DriverResult Joycons::SetLeds(const PadIdentifier& identifier, led_config += led_status.led_3 ? 4 : 0; led_config += led_status.led_4 ? 8 : 0; - return static_cast<Common::Input::DriverResult>( - handle->SetLedConfig(static_cast<u8>(led_config))); + return handle->SetLedConfig(static_cast<u8>(led_config)); } Common::Input::DriverResult Joycons::SetCameraFormat(const PadIdentifier& identifier, @@ -283,21 +282,113 @@ Common::Input::DriverResult Joycons::SetCameraFormat(const PadIdentifier& identi if (handle == nullptr) { return Common::Input::DriverResult::InvalidHandle; } - return static_cast<Common::Input::DriverResult>(handle->SetIrsConfig( - Joycon::IrsMode::ImageTransfer, static_cast<Joycon::IrsResolution>(camera_format))); + return handle->SetIrsConfig(Joycon::IrsMode::ImageTransfer, + static_cast<Joycon::IrsResolution>(camera_format)); }; Common::Input::NfcState Joycons::SupportsNfc(const PadIdentifier& identifier_) const { return Common::Input::NfcState::Success; }; +Common::Input::NfcState Joycons::StartNfcPolling(const PadIdentifier& identifier) { + auto handle = GetHandle(identifier); + if (handle == nullptr) { + return Common::Input::NfcState::Unknown; + } + return TranslateDriverResult(handle->StartNfcPolling()); +}; + +Common::Input::NfcState Joycons::StopNfcPolling(const PadIdentifier& identifier) { + auto handle = GetHandle(identifier); + if (handle == nullptr) { + return Common::Input::NfcState::Unknown; + } + return TranslateDriverResult(handle->StopNfcPolling()); +}; + +Common::Input::NfcState Joycons::ReadAmiiboData(const PadIdentifier& identifier, + std::vector<u8>& out_data) { + auto handle = GetHandle(identifier); + if (handle == nullptr) { + return Common::Input::NfcState::Unknown; + } + return TranslateDriverResult(handle->ReadAmiiboData(out_data)); +} + Common::Input::NfcState Joycons::WriteNfcData(const PadIdentifier& identifier, const std::vector<u8>& data) { auto handle = GetHandle(identifier); - if (handle->WriteNfcData(data) != Joycon::DriverResult::Success) { - return Common::Input::NfcState::WriteFailed; + if (handle == nullptr) { + return Common::Input::NfcState::Unknown; } - return Common::Input::NfcState::Success; + return TranslateDriverResult(handle->WriteNfcData(data)); +}; + +Common::Input::NfcState Joycons::ReadMifareData(const PadIdentifier& identifier, + const Common::Input::MifareRequest& request, + Common::Input::MifareRequest& data) { + auto handle = GetHandle(identifier); + if (handle == nullptr) { + return Common::Input::NfcState::Unknown; + } + + const auto command = static_cast<Joycon::MifareCmd>(request.data[0].command); + std::vector<Joycon::MifareReadChunk> read_request{}; + for (const auto& request_data : request.data) { + if (request_data.command == 0) { + continue; + } + Joycon::MifareReadChunk chunk = { + .command = command, + .sector_key = {}, + .sector = request_data.sector, + }; + memcpy(chunk.sector_key.data(), request_data.key.data(), + sizeof(Joycon::MifareReadChunk::sector_key)); + read_request.emplace_back(chunk); + } + + std::vector<Joycon::MifareReadData> read_data(read_request.size()); + const auto result = handle->ReadMifareData(read_request, read_data); + if (result == Common::Input::DriverResult::Success) { + for (std::size_t i = 0; i < read_request.size(); i++) { + data.data[i] = { + .command = static_cast<u8>(command), + .sector = read_data[i].sector, + .key = {}, + .data = read_data[i].data, + }; + } + } + return TranslateDriverResult(result); +}; + +Common::Input::NfcState Joycons::WriteMifareData(const PadIdentifier& identifier, + const Common::Input::MifareRequest& request) { + auto handle = GetHandle(identifier); + if (handle == nullptr) { + return Common::Input::NfcState::Unknown; + } + + const auto command = static_cast<Joycon::MifareCmd>(request.data[0].command); + std::vector<Joycon::MifareWriteChunk> write_request{}; + for (const auto& request_data : request.data) { + if (request_data.command == 0) { + continue; + } + Joycon::MifareWriteChunk chunk = { + .command = command, + .sector_key = {}, + .sector = request_data.sector, + .data = {}, + }; + memcpy(chunk.sector_key.data(), request_data.key.data(), + sizeof(Joycon::MifareReadChunk::sector_key)); + memcpy(chunk.data.data(), request_data.data.data(), sizeof(Joycon::MifareWriteChunk::data)); + write_request.emplace_back(chunk); + } + + return TranslateDriverResult(handle->WriteMifareData(write_request)); }; Common::Input::DriverResult Joycons::SetPollingMode(const PadIdentifier& identifier, @@ -310,15 +401,15 @@ Common::Input::DriverResult Joycons::SetPollingMode(const PadIdentifier& identif switch (polling_mode) { case Common::Input::PollingMode::Active: - return static_cast<Common::Input::DriverResult>(handle->SetActiveMode()); + return handle->SetActiveMode(); case Common::Input::PollingMode::Passive: - return static_cast<Common::Input::DriverResult>(handle->SetPassiveMode()); + return handle->SetPassiveMode(); case Common::Input::PollingMode::IR: - return static_cast<Common::Input::DriverResult>(handle->SetIrMode()); + return handle->SetIrMode(); case Common::Input::PollingMode::NFC: - return static_cast<Common::Input::DriverResult>(handle->SetNfcMode()); + return handle->SetNfcMode(); case Common::Input::PollingMode::Ring: - return static_cast<Common::Input::DriverResult>(handle->SetRingConMode()); + return handle->SetRingConMode(); default: return Common::Input::DriverResult::NotSupported; } @@ -403,11 +494,20 @@ void Joycons::OnRingConUpdate(f32 ring_data) { } void Joycons::OnAmiiboUpdate(std::size_t port, Joycon::ControllerType type, - const std::vector<u8>& amiibo_data) { + const Joycon::TagInfo& tag_info) { const auto identifier = GetIdentifier(port, type); - const auto nfc_state = amiibo_data.empty() ? Common::Input::NfcState::AmiiboRemoved - : Common::Input::NfcState::NewAmiibo; - SetNfc(identifier, {nfc_state, amiibo_data}); + const auto nfc_state = tag_info.uuid_length == 0 ? Common::Input::NfcState::AmiiboRemoved + : Common::Input::NfcState::NewAmiibo; + + const Common::Input::NfcStatus nfc_status{ + .state = nfc_state, + .uuid_length = tag_info.uuid_length, + .protocol = tag_info.protocol, + .tag_type = tag_info.tag_type, + .uuid = tag_info.uuid, + }; + + SetNfc(identifier, nfc_status); } void Joycons::OnCameraUpdate(std::size_t port, const std::vector<u8>& camera_data, @@ -726,4 +826,18 @@ std::string Joycons::JoyconName(Joycon::ControllerType type) const { return "Unknown Switch Controller"; } } + +Common::Input::NfcState Joycons::TranslateDriverResult(Common::Input::DriverResult result) const { + switch (result) { + case Common::Input::DriverResult::Success: + return Common::Input::NfcState::Success; + case Common::Input::DriverResult::Disabled: + return Common::Input::NfcState::WrongDeviceState; + case Common::Input::DriverResult::NotSupported: + return Common::Input::NfcState::NotSupported; + default: + return Common::Input::NfcState::Unknown; + } +} + } // namespace InputCommon diff --git a/src/input_common/drivers/joycon.h b/src/input_common/drivers/joycon.h index e3f0ad78f..112e970e1 100644 --- a/src/input_common/drivers/joycon.h +++ b/src/input_common/drivers/joycon.h @@ -15,8 +15,8 @@ using SerialNumber = std::array<u8, 15>; struct Battery; struct Color; struct MotionData; +struct TagInfo; enum class ControllerType : u8; -enum class DriverResult; enum class IrsResolution; class JoyconDriver; } // namespace InputCommon::Joycon @@ -39,9 +39,18 @@ public: Common::Input::DriverResult SetCameraFormat(const PadIdentifier& identifier, Common::Input::CameraFormat camera_format) override; - Common::Input::NfcState SupportsNfc(const PadIdentifier& identifier_) const override; - Common::Input::NfcState WriteNfcData(const PadIdentifier& identifier_, + Common::Input::NfcState SupportsNfc(const PadIdentifier& identifier) const override; + Common::Input::NfcState StartNfcPolling(const PadIdentifier& identifier) override; + Common::Input::NfcState StopNfcPolling(const PadIdentifier& identifier) override; + Common::Input::NfcState ReadAmiiboData(const PadIdentifier& identifier, + std::vector<u8>& out_data) override; + Common::Input::NfcState WriteNfcData(const PadIdentifier& identifier, const std::vector<u8>& data) override; + Common::Input::NfcState ReadMifareData(const PadIdentifier& identifier, + const Common::Input::MifareRequest& request, + Common::Input::MifareRequest& out_data) override; + Common::Input::NfcState WriteMifareData(const PadIdentifier& identifier, + const Common::Input::MifareRequest& request) override; Common::Input::DriverResult SetPollingMode( const PadIdentifier& identifier, const Common::Input::PollingMode polling_mode) override; @@ -82,7 +91,7 @@ private: const Joycon::MotionData& value); void OnRingConUpdate(f32 ring_data); void OnAmiiboUpdate(std::size_t port, Joycon::ControllerType type, - const std::vector<u8>& amiibo_data); + const Joycon::TagInfo& amiibo_data); void OnCameraUpdate(std::size_t port, const std::vector<u8>& camera_data, Joycon::IrsResolution format); @@ -102,6 +111,8 @@ private: /// Returns the name of the device in text format std::string JoyconName(Joycon::ControllerType type) const; + Common::Input::NfcState TranslateDriverResult(Common::Input::DriverResult result) const; + std::jthread scan_thread; // Joycon types are split by type to ease supporting dualjoycon configurations diff --git a/src/input_common/drivers/mouse.cpp b/src/input_common/drivers/mouse.cpp index 0c9f642bb..f07cf8a0e 100644 --- a/src/input_common/drivers/mouse.cpp +++ b/src/input_common/drivers/mouse.cpp @@ -76,9 +76,6 @@ void Mouse::UpdateThread(std::stop_token stop_token) { UpdateStickInput(); UpdateMotionInput(); - if (mouse_panning_timeout++ > 20) { - StopPanning(); - } std::this_thread::sleep_for(std::chrono::milliseconds(update_time)); } } @@ -88,18 +85,45 @@ void Mouse::UpdateStickInput() { return; } - const float sensitivity = - Settings::values.mouse_panning_sensitivity.GetValue() * default_stick_sensitivity; + const float length = last_mouse_change.Length(); - // Slow movement by 4% - last_mouse_change *= 0.96f; - SetAxis(identifier, mouse_axis_x, last_mouse_change.x * sensitivity); - SetAxis(identifier, mouse_axis_y, -last_mouse_change.y * sensitivity); + // Prevent input from exceeding the max range (1.0f) too much, + // but allow some room to make it easier to sustain + if (length > 1.2f) { + last_mouse_change /= length; + last_mouse_change *= 1.2f; + } + + auto mouse_change = last_mouse_change; + + // Bind the mouse change to [0 <= deadzone_counterweight <= 1,1] + if (length < 1.0f) { + const float deadzone_h_counterweight = + Settings::values.mouse_panning_deadzone_x_counterweight.GetValue(); + const float deadzone_v_counterweight = + Settings::values.mouse_panning_deadzone_y_counterweight.GetValue(); + mouse_change /= length; + mouse_change.x *= length + (1 - length) * deadzone_h_counterweight * 0.01f; + mouse_change.y *= length + (1 - length) * deadzone_v_counterweight * 0.01f; + } + + SetAxis(identifier, mouse_axis_x, mouse_change.x); + SetAxis(identifier, mouse_axis_y, -mouse_change.y); + + // Decay input over time + const float clamped_length = std::min(1.0f, length); + const float decay_strength = Settings::values.mouse_panning_decay_strength.GetValue(); + const float decay = 1 - clamped_length * clamped_length * decay_strength * 0.01f; + const float min_decay = Settings::values.mouse_panning_min_decay.GetValue(); + const float clamped_decay = std::min(1 - min_decay / 100.0f, decay); + last_mouse_change *= clamped_decay; } void Mouse::UpdateMotionInput() { - const float sensitivity = - Settings::values.mouse_panning_sensitivity.GetValue() * default_motion_sensitivity; + // This may need its own sensitivity instead of using the average + const float sensitivity = (Settings::values.mouse_panning_x_sensitivity.GetValue() + + Settings::values.mouse_panning_y_sensitivity.GetValue()) / + 2.0f * default_motion_sensitivity; const float rotation_velocity = std::sqrt(last_motion_change.x * last_motion_change.x + last_motion_change.y * last_motion_change.y); @@ -131,49 +155,28 @@ void Mouse::UpdateMotionInput() { void Mouse::Move(int x, int y, int center_x, int center_y) { if (Settings::values.mouse_panning) { - mouse_panning_timeout = 0; - - auto mouse_change = + const auto mouse_change = (Common::MakeVec(x, y) - Common::MakeVec(center_x, center_y)).Cast<float>(); - last_motion_change += {-mouse_change.y, -mouse_change.x, 0}; - - const auto move_distance = mouse_change.Length(); - if (move_distance == 0) { - return; - } + const float x_sensitivity = + Settings::values.mouse_panning_x_sensitivity.GetValue() * default_stick_sensitivity; + const float y_sensitivity = + Settings::values.mouse_panning_y_sensitivity.GetValue() * default_stick_sensitivity; - // Make slow movements at least 3 units on length - if (move_distance < 3.0f) { - // Normalize value - mouse_change /= move_distance; - mouse_change *= 3.0f; - } - - // Average mouse movements - last_mouse_change = (last_mouse_change * 0.91f) + (mouse_change * 0.09f); - - const auto last_move_distance = last_mouse_change.Length(); - - // Make fast movements clamp to 8 units on length - if (last_move_distance > 8.0f) { - // Normalize value - last_mouse_change /= last_move_distance; - last_mouse_change *= 8.0f; - } - - // Ignore average if it's less than 1 unit and use current movement value - if (last_move_distance < 1.0f) { - last_mouse_change = mouse_change / mouse_change.Length(); - } + last_motion_change += {-mouse_change.y, -mouse_change.x, 0}; + last_mouse_change.x += mouse_change.x * x_sensitivity * 0.09f; + last_mouse_change.y += mouse_change.y * y_sensitivity * 0.09f; return; } if (button_pressed) { const auto mouse_move = Common::MakeVec<int>(x, y) - mouse_origin; - const float sensitivity = Settings::values.mouse_panning_sensitivity.GetValue() * 0.0012f; - SetAxis(identifier, mouse_axis_x, static_cast<float>(mouse_move.x) * sensitivity); - SetAxis(identifier, mouse_axis_y, static_cast<float>(-mouse_move.y) * sensitivity); + const float x_sensitivity = Settings::values.mouse_panning_x_sensitivity.GetValue(); + const float y_sensitivity = Settings::values.mouse_panning_y_sensitivity.GetValue(); + SetAxis(identifier, mouse_axis_x, + static_cast<float>(mouse_move.x) * x_sensitivity * 0.0012f); + SetAxis(identifier, mouse_axis_y, + static_cast<float>(-mouse_move.y) * y_sensitivity * 0.0012f); last_motion_change = { static_cast<float>(-mouse_move.y) / 50.0f, @@ -241,10 +244,6 @@ void Mouse::ReleaseAllButtons() { button_pressed = false; } -void Mouse::StopPanning() { - last_mouse_change = {}; -} - std::vector<Common::ParamPackage> Mouse::GetInputDevices() const { std::vector<Common::ParamPackage> devices; devices.emplace_back(Common::ParamPackage{ diff --git a/src/input_common/drivers/mouse.h b/src/input_common/drivers/mouse.h index b872c7a0f..0e8edcce1 100644 --- a/src/input_common/drivers/mouse.h +++ b/src/input_common/drivers/mouse.h @@ -98,7 +98,6 @@ private: void UpdateThread(std::stop_token stop_token); void UpdateStickInput(); void UpdateMotionInput(); - void StopPanning(); Common::Input::ButtonNames GetUIButtonName(const Common::ParamPackage& params) const; @@ -108,7 +107,6 @@ private: Common::Vec3<float> last_motion_change; Common::Vec2<int> wheel_position; bool button_pressed; - int mouse_panning_timeout{}; std::jthread update_thread; }; diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index 9a0439bb5..9f26392b1 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -150,6 +150,8 @@ public: if (sdl_controller) { const auto type = SDL_GameControllerGetType(sdl_controller.get()); return (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) || + (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT) || + (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT) || (type == SDL_CONTROLLER_TYPE_PS5); } return false; @@ -228,9 +230,8 @@ public: return false; } - Common::Input::BatteryLevel GetBatteryLevel() { - const auto level = SDL_JoystickCurrentPowerLevel(sdl_joystick.get()); - switch (level) { + Common::Input::BatteryLevel GetBatteryLevel(SDL_JoystickPowerLevel battery_level) { + switch (battery_level) { case SDL_JOYSTICK_POWER_EMPTY: return Common::Input::BatteryLevel::Empty; case SDL_JOYSTICK_POWER_LOW: @@ -378,7 +379,6 @@ void SDLDriver::InitJoystick(int joystick_index) { if (joystick_map.find(guid) == joystick_map.end()) { auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_gamecontroller); PreSetController(joystick->GetPadIdentifier()); - SetBattery(joystick->GetPadIdentifier(), joystick->GetBatteryLevel()); joystick->EnableMotion(); joystick_map[guid].emplace_back(std::move(joystick)); return; @@ -398,7 +398,6 @@ void SDLDriver::InitJoystick(int joystick_index) { const int port = static_cast<int>(joystick_guid_list.size()); auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_gamecontroller); PreSetController(joystick->GetPadIdentifier()); - SetBattery(joystick->GetPadIdentifier(), joystick->GetBatteryLevel()); joystick->EnableMotion(); joystick_guid_list.emplace_back(std::move(joystick)); } @@ -438,8 +437,6 @@ void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) { if (const auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) { const PadIdentifier identifier = joystick->GetPadIdentifier(); SetButton(identifier, event.jbutton.button, true); - // Battery doesn't trigger an event so just update every button press - SetBattery(identifier, joystick->GetBatteryLevel()); } break; } @@ -466,6 +463,13 @@ void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) { } break; } + case SDL_JOYBATTERYUPDATED: { + if (auto joystick = GetSDLJoystickBySDLID(event.jbattery.which)) { + const PadIdentifier identifier = joystick->GetPadIdentifier(); + SetBattery(identifier, joystick->GetBatteryLevel(event.jbattery.level)); + } + break; + } case SDL_JOYDEVICEREMOVED: LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which); CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which)); @@ -483,6 +487,10 @@ void SDLDriver::CloseJoysticks() { } SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_engine_)) { + // Set our application name. Currently passed to DBus by SDL and visible to the user through + // their desktop environment. + SDL_SetHint(SDL_HINT_APP_NAME, "yuzu"); + if (!Settings::values.enable_raw_input) { // Disable raw input. When enabled this setting causes SDL to die when a web applet opens SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "0"); @@ -501,6 +509,9 @@ SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_en SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "0"); } else { SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1"); + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOYCON_HOME_LED, "0"); + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS, "0"); + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_VERTICAL_JOY_CONS, "1"); } // Disable hidapi drivers for pro controllers when the custom joycon driver is enabled @@ -508,8 +519,11 @@ SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_en SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, "0"); } else { SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, "1"); + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_HOME_LED, "0"); } + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_PLAYER_LED, "1"); + // Disable hidapi driver for xbox. Already default on Windows, this causes conflict with native // driver on Linux. SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_XBOX, "0"); @@ -789,7 +803,9 @@ ButtonMapping SDLDriver::GetButtonMappingForDevice(const Common::ParamPackage& p // This list also excludes Screenshot since there's not really a mapping for that ButtonBindings switch_to_sdl_button; - if (SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) { + if (SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO || + SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT || + SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT) { switch_to_sdl_button = GetNintendoButtonBinding(joystick); } else { switch_to_sdl_button = GetDefaultButtonBinding(); diff --git a/src/input_common/drivers/virtual_amiibo.cpp b/src/input_common/drivers/virtual_amiibo.cpp index 6435b8af8..180eb53ef 100644 --- a/src/input_common/drivers/virtual_amiibo.cpp +++ b/src/input_common/drivers/virtual_amiibo.cpp @@ -29,14 +29,13 @@ Common::Input::DriverResult VirtualAmiibo::SetPollingMode( switch (polling_mode) { case Common::Input::PollingMode::NFC: - if (state == State::Initialized) { - state = State::WaitingForAmiibo; - } + state = State::Initialized; return Common::Input::DriverResult::Success; default: - if (state == State::AmiiboIsOpen) { + if (state == State::TagNearby) { CloseAmiibo(); } + state = State::Disabled; return Common::Input::DriverResult::NotSupported; } } @@ -45,6 +44,39 @@ Common::Input::NfcState VirtualAmiibo::SupportsNfc( [[maybe_unused]] const PadIdentifier& identifier_) const { return Common::Input::NfcState::Success; } +Common::Input::NfcState VirtualAmiibo::StartNfcPolling(const PadIdentifier& identifier_) { + if (state != State::Initialized) { + return Common::Input::NfcState::WrongDeviceState; + } + state = State::WaitingForAmiibo; + return Common::Input::NfcState::Success; +} + +Common::Input::NfcState VirtualAmiibo::StopNfcPolling(const PadIdentifier& identifier_) { + if (state == State::Disabled) { + return Common::Input::NfcState::WrongDeviceState; + } + if (state == State::TagNearby) { + CloseAmiibo(); + } + state = State::Initialized; + return Common::Input::NfcState::Success; +} + +Common::Input::NfcState VirtualAmiibo::ReadAmiiboData(const PadIdentifier& identifier_, + std::vector<u8>& out_data) { + if (state != State::TagNearby) { + return Common::Input::NfcState::WrongDeviceState; + } + + if (status.tag_type != 1U << 1) { + return Common::Input::NfcState::InvalidTagType; + } + + out_data.resize(nfc_data.size()); + memcpy(out_data.data(), nfc_data.data(), nfc_data.size()); + return Common::Input::NfcState::Success; +} Common::Input::NfcState VirtualAmiibo::WriteNfcData( [[maybe_unused]] const PadIdentifier& identifier_, const std::vector<u8>& data) { @@ -66,6 +98,69 @@ Common::Input::NfcState VirtualAmiibo::WriteNfcData( return Common::Input::NfcState::Success; } +Common::Input::NfcState VirtualAmiibo::ReadMifareData(const PadIdentifier& identifier_, + const Common::Input::MifareRequest& request, + Common::Input::MifareRequest& out_data) { + if (state != State::TagNearby) { + return Common::Input::NfcState::WrongDeviceState; + } + + if (status.tag_type != 1U << 6) { + return Common::Input::NfcState::InvalidTagType; + } + + for (std::size_t i = 0; i < request.data.size(); i++) { + if (request.data[i].command == 0) { + continue; + } + out_data.data[i].command = request.data[i].command; + out_data.data[i].sector = request.data[i].sector; + + const std::size_t sector_index = + request.data[i].sector * sizeof(Common::Input::MifareData::data); + + if (nfc_data.size() < sector_index + sizeof(Common::Input::MifareData::data)) { + return Common::Input::NfcState::WriteFailed; + } + + // Ignore the sector key as we don't support it + memcpy(out_data.data[i].data.data(), nfc_data.data() + sector_index, + sizeof(Common::Input::MifareData::data)); + } + + return Common::Input::NfcState::Success; +} + +Common::Input::NfcState VirtualAmiibo::WriteMifareData( + const PadIdentifier& identifier_, const Common::Input::MifareRequest& request) { + if (state != State::TagNearby) { + return Common::Input::NfcState::WrongDeviceState; + } + + if (status.tag_type != 1U << 6) { + return Common::Input::NfcState::InvalidTagType; + } + + for (std::size_t i = 0; i < request.data.size(); i++) { + if (request.data[i].command == 0) { + continue; + } + + const std::size_t sector_index = + request.data[i].sector * sizeof(Common::Input::MifareData::data); + + if (nfc_data.size() < sector_index + sizeof(Common::Input::MifareData::data)) { + return Common::Input::NfcState::WriteFailed; + } + + // Ignore the sector key as we don't support it + memcpy(nfc_data.data() + sector_index, request.data[i].data.data(), + sizeof(Common::Input::MifareData::data)); + } + + return Common::Input::NfcState::Success; +} + VirtualAmiibo::State VirtualAmiibo::GetCurrentState() const { return state; } @@ -112,23 +207,31 @@ VirtualAmiibo::Info VirtualAmiibo::LoadAmiibo(std::span<u8> data) { case AmiiboSizeWithoutPassword: case AmiiboSizeWithSignature: nfc_data.resize(AmiiboSize); + status.tag_type = 1U << 1; + status.uuid_length = 7; break; case MifareSize: nfc_data.resize(MifareSize); + status.tag_type = 1U << 6; + status.uuid_length = 4; break; default: return Info::NotAnAmiibo; } - state = State::AmiiboIsOpen; + status.uuid = {}; + status.protocol = 1; + state = State::TagNearby; + status.state = Common::Input::NfcState::NewAmiibo, memcpy(nfc_data.data(), data.data(), data.size_bytes()); - SetNfc(identifier, {Common::Input::NfcState::NewAmiibo, nfc_data}); + memcpy(status.uuid.data(), nfc_data.data(), status.uuid_length); + SetNfc(identifier, status); return Info::Success; } VirtualAmiibo::Info VirtualAmiibo::ReloadAmiibo() { - if (state == State::AmiiboIsOpen) { - SetNfc(identifier, {Common::Input::NfcState::NewAmiibo, nfc_data}); + if (state == State::TagNearby) { + SetNfc(identifier, status); return Info::Success; } @@ -136,9 +239,14 @@ VirtualAmiibo::Info VirtualAmiibo::ReloadAmiibo() { } VirtualAmiibo::Info VirtualAmiibo::CloseAmiibo() { - state = polling_mode == Common::Input::PollingMode::NFC ? State::WaitingForAmiibo - : State::Initialized; - SetNfc(identifier, {Common::Input::NfcState::AmiiboRemoved, {}}); + if (state != State::TagNearby) { + return Info::Success; + } + + state = State::WaitingForAmiibo; + status.state = Common::Input::NfcState::AmiiboRemoved; + SetNfc(identifier, status); + status.tag_type = 0; return Info::Success; } diff --git a/src/input_common/drivers/virtual_amiibo.h b/src/input_common/drivers/virtual_amiibo.h index 09ca09e68..490f38e05 100644 --- a/src/input_common/drivers/virtual_amiibo.h +++ b/src/input_common/drivers/virtual_amiibo.h @@ -20,9 +20,10 @@ namespace InputCommon { class VirtualAmiibo final : public InputEngine { public: enum class State { + Disabled, Initialized, WaitingForAmiibo, - AmiiboIsOpen, + TagNearby, }; enum class Info { @@ -41,9 +42,17 @@ public: const PadIdentifier& identifier_, const Common::Input::PollingMode polling_mode_) override; Common::Input::NfcState SupportsNfc(const PadIdentifier& identifier_) const override; - + Common::Input::NfcState StartNfcPolling(const PadIdentifier& identifier_) override; + Common::Input::NfcState StopNfcPolling(const PadIdentifier& identifier_) override; + Common::Input::NfcState ReadAmiiboData(const PadIdentifier& identifier_, + std::vector<u8>& out_data) override; Common::Input::NfcState WriteNfcData(const PadIdentifier& identifier_, const std::vector<u8>& data) override; + Common::Input::NfcState ReadMifareData(const PadIdentifier& identifier_, + const Common::Input::MifareRequest& data, + Common::Input::MifareRequest& out_data) override; + Common::Input::NfcState WriteMifareData(const PadIdentifier& identifier_, + const Common::Input::MifareRequest& data) override; State GetCurrentState() const; @@ -61,8 +70,9 @@ private: static constexpr std::size_t MifareSize = 0x400; std::string file_path{}; - State state{State::Initialized}; + State state{State::Disabled}; std::vector<u8> nfc_data; + Common::Input::NfcStatus status; Common::Input::PollingMode polling_mode{Common::Input::PollingMode::Passive}; }; } // namespace InputCommon |