// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include #include "common/param_package.h" #include "common/polyfill_ranges.h" #include "common/polyfill_thread.h" #include "common/settings.h" #include "common/thread.h" #include "input_common/drivers/joycon.h" #include "input_common/helpers/joycon_driver.h" #include "input_common/helpers/joycon_protocol/joycon_types.h" namespace InputCommon { Joycons::Joycons(const std::string& input_engine_) : InputEngine(input_engine_) { // Avoid conflicting with SDL driver if (!Settings::values.enable_joycon_driver && !Settings::values.enable_procon_driver) { return; } LOG_INFO(Input, "Joycon driver Initialization started"); const int init_res = SDL_hid_init(); if (init_res == 0) { Setup(); } else { LOG_ERROR(Input, "Hidapi could not be initialized. failed with error = {}", init_res); } } Joycons::~Joycons() { Reset(); } void Joycons::Reset() { scan_thread = {}; for (const auto& device : left_joycons) { if (!device) { continue; } device->Stop(); } for (const auto& device : right_joycons) { if (!device) { continue; } device->Stop(); } for (const auto& device : pro_controller) { if (!device) { continue; } device->Stop(); } SDL_hid_exit(); } void Joycons::Setup() { u32 port = 0; PreSetController(GetIdentifier(0, Joycon::ControllerType::None)); for (auto& device : left_joycons) { PreSetController(GetIdentifier(port, Joycon::ControllerType::Left)); device = std::make_shared(port++); } port = 0; for (auto& device : right_joycons) { PreSetController(GetIdentifier(port, Joycon::ControllerType::Right)); device = std::make_shared(port++); } port = 0; for (auto& device : pro_controller) { PreSetController(GetIdentifier(port, Joycon::ControllerType::Pro)); device = std::make_shared(port++); } scan_thread = std::jthread([this](std::stop_token stop_token) { ScanThread(stop_token); }); } void Joycons::ScanThread(std::stop_token stop_token) { constexpr u16 nintendo_vendor_id = 0x057e; Common::SetCurrentThreadName("JoyconScanThread"); do { SDL_hid_device_info* devs = SDL_hid_enumerate(nintendo_vendor_id, 0x0); SDL_hid_device_info* cur_dev = devs; while (cur_dev) { if (IsDeviceNew(cur_dev)) { LOG_DEBUG(Input, "Device Found,type : {:04X} {:04X}", cur_dev->vendor_id, cur_dev->product_id); RegisterNewDevice(cur_dev); } cur_dev = cur_dev->next; } SDL_hid_free_enumeration(devs); } while (Common::StoppableTimedWait(stop_token, std::chrono::seconds{5})); } bool Joycons::IsDeviceNew(SDL_hid_device_info* device_info) const { Joycon::ControllerType type{}; Joycon::SerialNumber serial_number{}; const auto result = Joycon::JoyconDriver::GetDeviceType(device_info, type); if (result != Common::Input::DriverResult::Success) { return false; } const auto result2 = Joycon::JoyconDriver::GetSerialNumber(device_info, serial_number); if (result2 != Common::Input::DriverResult::Success) { return false; } auto is_handle_identical = [serial_number](std::shared_ptr device) { if (!device) { return false; } if (!device->IsConnected()) { return false; } if (device->GetHandleSerialNumber() != serial_number) { return false; } return true; }; // Check if device already exist switch (type) { case Joycon::ControllerType::Left: if (!Settings::values.enable_joycon_driver) { return false; } for (const auto& device : left_joycons) { if (is_handle_identical(device)) { return false; } } break; case Joycon::ControllerType::Right: if (!Settings::values.enable_joycon_driver) { return false; } for (const auto& device : right_joycons) { if (is_handle_identical(device)) { return false; } } break; case Joycon::ControllerType::Pro: if (!Settings::values.enable_procon_driver) { return false; } for (const auto& device : pro_controller) { if (is_handle_identical(device)) { return false; } } break; default: return false; } return true; } void Joycons::RegisterNewDevice(SDL_hid_device_info* device_info) { Joycon::ControllerType type{}; auto result = Joycon::JoyconDriver::GetDeviceType(device_info, type); auto handle = GetNextFreeHandle(type); if (handle == nullptr) { LOG_WARNING(Input, "No free handles available"); return; } if (result == Common::Input::DriverResult::Success) { result = handle->RequestDeviceAccess(device_info); } if (result == Common::Input::DriverResult::Success) { LOG_WARNING(Input, "Initialize device"); const std::size_t port = handle->GetDevicePort(); const Joycon::JoyconCallbacks callbacks{ .on_battery_data = {[this, port, type](Joycon::Battery value) { OnBatteryUpdate(port, type, value); }}, .on_color_data = {[this, port, type](Joycon::Color value) { OnColorUpdate(port, type, value); }}, .on_button_data = {[this, port, type](int id, bool value) { OnButtonUpdate(port, type, id, value); }}, .on_stick_data = {[this, port, type](int id, f32 value) { OnStickUpdate(port, type, id, value); }}, .on_motion_data = {[this, port, type](int id, const Joycon::MotionData& value) { OnMotionUpdate(port, type, id, value); }}, .on_ring_data = {[this](f32 ring_data) { OnRingConUpdate(ring_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& camera_data, Joycon::IrsResolution format) { OnCameraUpdate(port, camera_data, format); }}, }; handle->InitializeDevice(); handle->SetCallbacks(callbacks); } } std::shared_ptr Joycons::GetNextFreeHandle( Joycon::ControllerType type) const { if (type == Joycon::ControllerType::Left) { const auto unconnected_device = std::ranges::find_if(left_joycons, [](auto& device) { return !device->IsConnected(); }); if (unconnected_device != left_joycons.end()) { return *unconnected_device; } } if (type == Joycon::ControllerType::Right) { const auto unconnected_device = std::ranges::find_if( right_joycons, [](auto& device) { return !device->IsConnected(); }); if (unconnected_device != right_joycons.end()) { return *unconnected_device; } } if (type == Joycon::ControllerType::Pro) { const auto unconnected_device = std::ranges::find_if( pro_controller, [](auto& device) { return !device->IsConnected(); }); if (unconnected_device != pro_controller.end()) { return *unconnected_device; } } return nullptr; } bool Joycons::IsVibrationEnabled(const PadIdentifier& identifier) { const auto handle = GetHandle(identifier); if (handle == nullptr) { return false; } return handle->IsVibrationEnabled(); } Common::Input::DriverResult Joycons::SetVibration(const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) { const Joycon::VibrationValue native_vibration{ .low_amplitude = vibration.low_amplitude, .low_frequency = vibration.low_frequency, .high_amplitude = vibration.high_amplitude, .high_frequency = vibration.high_frequency, }; auto handle = GetHandle(identifier); if (handle == nullptr) { return Common::Input::DriverResult::InvalidHandle; } handle->SetVibration(native_vibration); return Common::Input::DriverResult::Success; } Common::Input::DriverResult Joycons::SetLeds(const PadIdentifier& identifier, const Common::Input::LedStatus& led_status) { auto handle = GetHandle(identifier); if (handle == nullptr) { return Common::Input::DriverResult::InvalidHandle; } int led_config = led_status.led_1 ? 1 : 0; led_config += led_status.led_2 ? 2 : 0; led_config += led_status.led_3 ? 4 : 0; led_config += led_status.led_4 ? 8 : 0; return handle->SetLedConfig(static_cast(led_config)); } Common::Input::DriverResult Joycons::SetCameraFormat(const PadIdentifier& identifier, Common::Input::CameraFormat camera_format) { auto handle = GetHandle(identifier); if (handle == nullptr) { return Common::Input::DriverResult::InvalidHandle; } return handle->SetIrsConfig(Joycon::IrsMode::ImageTransfer, static_cast(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& 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& data) { auto handle = GetHandle(identifier); if (handle == nullptr) { return Common::Input::NfcState::Unknown; } 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(request.data[0].command); std::vector 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 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(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(request.data[0].command); std::vector 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, const Common::Input::PollingMode polling_mode) { auto handle = GetHandle(identifier); if (handle == nullptr) { LOG_ERROR(Input, "Invalid handle {}", identifier.port); return Common::Input::DriverResult::InvalidHandle; } switch (polling_mode) { case Common::Input::PollingMode::Active: return handle->SetActiveMode(); case Common::Input::PollingMode::Passive: return handle->SetPassiveMode(); case Common::Input::PollingMode::IR: return handle->SetIrMode(); case Common::Input::PollingMode::NFC: return handle->SetNfcMode(); case Common::Input::PollingMode::Ring: return handle->SetRingConMode(); default: return Common::Input::DriverResult::NotSupported; } } void Joycons::OnBatteryUpdate(std::size_t port, Joycon::ControllerType type, Joycon::Battery value) { const auto identifier = GetIdentifier(port, type); if (value.charging != 0) { SetBattery(identifier, Common::Input::BatteryLevel::Charging); return; } Common::Input::BatteryLevel battery{}; switch (value.status) { case 0: battery = Common::Input::BatteryLevel::Empty; break; case 1: battery = Common::Input::BatteryLevel::Critical; break; case 2: battery = Common::Input::BatteryLevel::Low; break; case 3: battery = Common::Input::BatteryLevel::Medium; break; case 4: default: battery = Common::Input::BatteryLevel::Full; break; } SetBattery(identifier, battery); } void Joycons::OnColorUpdate(std::size_t port, Joycon::ControllerType type, const Joycon::Color& value) { const auto identifier = GetIdentifier(port, type); Common::Input::BodyColorStatus color{ .body = value.body, .buttons = value.buttons, .left_grip = value.left_grip, .right_grip = value.right_grip, }; SetColor(identifier, color); } void Joycons::OnButtonUpdate(std::size_t port, Joycon::ControllerType type, int id, bool value) { const auto identifier = GetIdentifier(port, type); SetButton(identifier, id, value); } void Joycons::OnStickUpdate(std::size_t port, Joycon::ControllerType type, int id, f32 value) { const auto identifier = GetIdentifier(port, type); SetAxis(identifier, id, value); } void Joycons::OnMotionUpdate(std::size_t port, Joycon::ControllerType type, int id, const Joycon::MotionData& value) { const auto identifier = GetIdentifier(port, type); BasicMotion motion_data{ .gyro_x = value.gyro_x, .gyro_y = value.gyro_y, .gyro_z = value.gyro_z, .accel_x = value.accel_x, .accel_y = value.accel_y, .accel_z = value.accel_z, .delta_timestamp = 15000, }; SetMotion(identifier, id, motion_data); } void Joycons::OnRingConUpdate(f32 ring_data) { // To simplify ring detection it will always be mapped to an empty identifier for all // controllers static constexpr PadIdentifier identifier = { .guid = Common::UUID{}, .port = 0, .pad = 0, }; SetAxis(identifier, 100, ring_data); } void Joycons::OnAmiiboUpdate(std::size_t port, Joycon::ControllerType type, const Joycon::TagInfo& tag_info) { const auto identifier = GetIdentifier(port, type); 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& camera_data, Joycon::IrsResolution format) { const auto identifier = GetIdentifier(port, Joycon::ControllerType::Right); SetCamera(identifier, {static_cast(format), camera_data}); } std::shared_ptr Joycons::GetHandle(PadIdentifier identifier) const { auto is_handle_active = [&](std::shared_ptr device) { if (!device) { return false; } if (!device->IsConnected()) { return false; } if (device->GetDevicePort() == identifier.port) { return true; } return false; }; const auto type = static_cast(identifier.pad); if (type == Joycon::ControllerType::Left) { const auto matching_device = std::ranges::find_if( left_joycons, [is_handle_active](auto& device) { return is_handle_active(device); }); if (matching_device != left_joycons.end()) { return *matching_device; } } if (type == Joycon::ControllerType::Right) { const auto matching_device = std::ranges::find_if( right_joycons, [is_handle_active](auto& device) { return is_handle_active(device); }); if (matching_device != right_joycons.end()) { return *matching_device; } } if (type == Joycon::ControllerType::Pro) { const auto matching_device = std::ranges::find_if( pro_controller, [is_handle_active](auto& device) { return is_handle_active(device); }); if (matching_device != pro_controller.end()) { return *matching_device; } } return nullptr; } PadIdentifier Joycons::GetIdentifier(std::size_t port, Joycon::ControllerType type) const { const std::array guid{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, static_cast(type)}; return { .guid = Common::UUID{guid}, .port = port, .pad = static_cast(type), }; } Common::ParamPackage Joycons::GetParamPackage(std::size_t port, Joycon::ControllerType type) const { const auto identifier = GetIdentifier(port, type); return { {"engine", GetEngineName()}, {"guid", identifier.guid.RawString()}, {"port", std::to_string(identifier.port)}, {"pad", std::to_string(identifier.pad)}, }; } std::vector Joycons::GetInputDevices() const { std::vector devices{}; auto add_entry = [&](std::shared_ptr device) { if (!device) { return; } if (!device->IsConnected()) { return; } auto param = GetParamPackage(device->GetDevicePort(), device->GetHandleDeviceType()); std::string name = fmt::format("{} {}", JoyconName(device->GetHandleDeviceType()), device->GetDevicePort() + 1); param.Set("display", std::move(name)); devices.emplace_back(param); }; for (const auto& controller : left_joycons) { add_entry(controller); } for (const auto& controller : right_joycons) { add_entry(controller); } for (const auto& controller : pro_controller) { add_entry(controller); } // List dual joycon pairs for (std::size_t i = 0; i < MaxSupportedControllers; i++) { if (!left_joycons[i] || !right_joycons[i]) { continue; } if (!left_joycons[i]->IsConnected() || !right_joycons[i]->IsConnected()) { continue; } auto main_param = GetParamPackage(i, left_joycons[i]->GetHandleDeviceType()); const auto second_param = GetParamPackage(i, right_joycons[i]->GetHandleDeviceType()); const auto type = Joycon::ControllerType::Dual; std::string name = fmt::format("{} {}", JoyconName(type), i + 1); main_param.Set("display", std::move(name)); main_param.Set("guid2", second_param.Get("guid", "")); main_param.Set("pad", std::to_string(static_cast(type))); devices.emplace_back(main_param); } return devices; } ButtonMapping Joycons::GetButtonMappingForDevice(const Common::ParamPackage& params) { static constexpr std::array, 18> switch_to_joycon_button = { std::tuple{Settings::NativeButton::A, Joycon::PadButton::A, true}, {Settings::NativeButton::B, Joycon::PadButton::B, true}, {Settings::NativeButton::X, Joycon::PadButton::X, true}, {Settings::NativeButton::Y, Joycon::PadButton::Y, true}, {Settings::NativeButton::DLeft, Joycon::PadButton::Left, false}, {Settings::NativeButton::DUp, Joycon::PadButton::Up, false}, {Settings::NativeButton::DRight, Joycon::PadButton::Right, false}, {Settings::NativeButton::DDown, Joycon::PadButton::Down, false}, {Settings::NativeButton::L, Joycon::PadButton::L, false}, {Settings::NativeButton::R, Joycon::PadButton::R, true}, {Settings::NativeButton::ZL, Joycon::PadButton::ZL, false}, {Settings::NativeButton::ZR, Joycon::PadButton::ZR, true}, {Settings::NativeButton::Plus, Joycon::PadButton::Plus, true}, {Settings::NativeButton::Minus, Joycon::PadButton::Minus, false}, {Settings::NativeButton::Home, Joycon::PadButton::Home, true}, {Settings::NativeButton::Screenshot, Joycon::PadButton::Capture, false}, {Settings::NativeButton::LStick, Joycon::PadButton::StickL, false}, {Settings::NativeButton::RStick, Joycon::PadButton::StickR, true}, }; if (!params.Has("port")) { return {}; } ButtonMapping mapping{}; for (const auto& [switch_button, joycon_button, side] : switch_to_joycon_button) { const std::size_t port = static_cast(params.Get("port", 0)); auto pad = static_cast(params.Get("pad", 0)); if (pad == Joycon::ControllerType::Dual) { pad = side ? Joycon::ControllerType::Right : Joycon::ControllerType::Left; } Common::ParamPackage button_params = GetParamPackage(port, pad); button_params.Set("button", static_cast(joycon_button)); mapping.insert_or_assign(switch_button, std::move(button_params)); } // Map SL and SR buttons for left joycons if (params.Get("pad", 0) == static_cast(Joycon::ControllerType::Left)) { const std::size_t port = static_cast(params.Get("port", 0)); Common::ParamPackage button_params = GetParamPackage(port, Joycon::ControllerType::Left); Common::ParamPackage sl_button_params = button_params; Common::ParamPackage sr_button_params = button_params; sl_button_params.Set("button", static_cast(Joycon::PadButton::LeftSL)); sr_button_params.Set("button", static_cast(Joycon::PadButton::LeftSR)); mapping.insert_or_assign(Settings::NativeButton::SLLeft, std::move(sl_button_params)); mapping.insert_or_assign(Settings::NativeButton::SRLeft, std::move(sr_button_params)); } // Map SL and SR buttons for right joycons if (params.Get("pad", 0) == static_cast(Joycon::ControllerType::Right)) { const std::size_t port = static_cast(params.Get("port", 0)); Common::ParamPackage button_params = GetParamPackage(port, Joycon::ControllerType::Right); Common::ParamPackage sl_button_params = button_params; Common::ParamPackage sr_button_params = button_params; sl_button_params.Set("button", static_cast(Joycon::PadButton::RightSL)); sr_button_params.Set("button", static_cast(Joycon::PadButton::RightSR)); mapping.insert_or_assign(Settings::NativeButton::SLRight, std::move(sl_button_params)); mapping.insert_or_assign(Settings::NativeButton::SRRight, std::move(sr_button_params)); } return mapping; } AnalogMapping Joycons::GetAnalogMappingForDevice(const Common::ParamPackage& params) { if (!params.Has("port")) { return {}; } const std::size_t port = static_cast(params.Get("port", 0)); auto pad_left = static_cast(params.Get("pad", 0)); auto pad_right = pad_left; if (pad_left == Joycon::ControllerType::Dual) { pad_left = Joycon::ControllerType::Left; pad_right = Joycon::ControllerType::Right; } AnalogMapping mapping = {}; Common::ParamPackage left_analog_params = GetParamPackage(port, pad_left); left_analog_params.Set("axis_x", static_cast(Joycon::PadAxes::LeftStickX)); left_analog_params.Set("axis_y", static_cast(Joycon::PadAxes::LeftStickY)); mapping.insert_or_assign(Settings::NativeAnalog::LStick, std::move(left_analog_params)); Common::ParamPackage right_analog_params = GetParamPackage(port, pad_right); right_analog_params.Set("axis_x", static_cast(Joycon::PadAxes::RightStickX)); right_analog_params.Set("axis_y", static_cast(Joycon::PadAxes::RightStickY)); mapping.insert_or_assign(Settings::NativeAnalog::RStick, std::move(right_analog_params)); return mapping; } MotionMapping Joycons::GetMotionMappingForDevice(const Common::ParamPackage& params) { if (!params.Has("port")) { return {}; } const std::size_t port = static_cast(params.Get("port", 0)); auto pad_left = static_cast(params.Get("pad", 0)); auto pad_right = pad_left; if (pad_left == Joycon::ControllerType::Dual) { pad_left = Joycon::ControllerType::Left; pad_right = Joycon::ControllerType::Right; } MotionMapping mapping = {}; Common::ParamPackage left_motion_params = GetParamPackage(port, pad_left); left_motion_params.Set("motion", 0); mapping.insert_or_assign(Settings::NativeMotion::MotionLeft, std::move(left_motion_params)); Common::ParamPackage right_Motion_params = GetParamPackage(port, pad_right); right_Motion_params.Set("motion", 1); mapping.insert_or_assign(Settings::NativeMotion::MotionRight, std::move(right_Motion_params)); return mapping; } Common::Input::ButtonNames Joycons::GetUIButtonName(const Common::ParamPackage& params) const { const auto button = static_cast(params.Get("button", 0)); switch (button) { case Joycon::PadButton::Left: return Common::Input::ButtonNames::ButtonLeft; case Joycon::PadButton::Right: return Common::Input::ButtonNames::ButtonRight; case Joycon::PadButton::Down: return Common::Input::ButtonNames::ButtonDown; case Joycon::PadButton::Up: return Common::Input::ButtonNames::ButtonUp; case Joycon::PadButton::LeftSL: case Joycon::PadButton::RightSL: return Common::Input::ButtonNames::TriggerSL; case Joycon::PadButton::LeftSR: case Joycon::PadButton::RightSR: return Common::Input::ButtonNames::TriggerSR; case Joycon::PadButton::L: return Common::Input::ButtonNames::TriggerL; case Joycon::PadButton::R: return Common::Input::ButtonNames::TriggerR; case Joycon::PadButton::ZL: return Common::Input::ButtonNames::TriggerZL; case Joycon::PadButton::ZR: return Common::Input::ButtonNames::TriggerZR; case Joycon::PadButton::A: return Common::Input::ButtonNames::ButtonA; case Joycon::PadButton::B: return Common::Input::ButtonNames::ButtonB; case Joycon::PadButton::X: return Common::Input::ButtonNames::ButtonX; case Joycon::PadButton::Y: return Common::Input::ButtonNames::ButtonY; case Joycon::PadButton::Plus: return Common::Input::ButtonNames::ButtonPlus; case Joycon::PadButton::Minus: return Common::Input::ButtonNames::ButtonMinus; case Joycon::PadButton::Home: return Common::Input::ButtonNames::ButtonHome; case Joycon::PadButton::Capture: return Common::Input::ButtonNames::ButtonCapture; case Joycon::PadButton::StickL: return Common::Input::ButtonNames::ButtonStickL; case Joycon::PadButton::StickR: return Common::Input::ButtonNames::ButtonStickR; default: return Common::Input::ButtonNames::Undefined; } } Common::Input::ButtonNames Joycons::GetUIName(const Common::ParamPackage& params) const { if (params.Has("button")) { return GetUIButtonName(params); } if (params.Has("axis")) { return Common::Input::ButtonNames::Value; } if (params.Has("motion")) { return Common::Input::ButtonNames::Engine; } return Common::Input::ButtonNames::Invalid; } std::string Joycons::JoyconName(Joycon::ControllerType type) const { switch (type) { case Joycon::ControllerType::Left: return "Left Joycon"; case Joycon::ControllerType::Right: return "Right Joycon"; case Joycon::ControllerType::Pro: return "Pro Controller"; case Joycon::ControllerType::Dual: return "Dual Joycon"; default: 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