فهرست منبع

input_common: Fully implement UDP controllers

Narr the Reg 4 سال پیش
والد
کامیت
639402850a

+ 14 - 0
src/common/input.h

@@ -195,6 +195,20 @@ enum class ButtonNames {
     ButtonX,
     ButtonY,
     ButtonStart,
+
+    // DS4 button names
+    L1,
+    L2,
+    L3,
+    R1,
+    R2,
+    R3,
+    Circle,
+    Cross,
+    Square,
+    Triangle,
+    Share,
+    Options,
 };
 
 // Callback data consisting of an input type and the equivalent data status

+ 1 - 0
src/common/settings.h

@@ -560,6 +560,7 @@ struct Values {
 
     Setting<bool> motion_enabled{true, "motion_enabled"};
     BasicSetting<std::string> udp_input_servers{"127.0.0.1:26760", "udp_input_servers"};
+    BasicSetting<bool> enable_udp_controller{false, "enable_udp_controller"};
 
     BasicSetting<bool> pause_tas_on_load{true, "pause_tas_on_load"};
     BasicSetting<bool> tas_enable{false, "tas_enable"};

+ 4 - 2
src/core/hid/emulated_console.cpp

@@ -30,8 +30,10 @@ void EmulatedConsole::SetTouchParams() {
     }
     touch_params[index++] = Common::ParamPackage{"engine:touch,axis_x:0,axis_y:1,button:0"};
     touch_params[index++] = Common::ParamPackage{"engine:touch,axis_x:2,axis_y:3,button:1"};
-    touch_params[index++] = Common::ParamPackage{"engine:cemuhookudp,axis_x:0,axis_y:1,button:0"};
-    touch_params[index++] = Common::ParamPackage{"engine:cemuhookudp,axis_x:2,axis_y:3,button:1"};
+    touch_params[index++] =
+        Common::ParamPackage{"engine:cemuhookudp,axis_x:17,axis_y:18,button:65536"};
+    touch_params[index++] =
+        Common::ParamPackage{"engine:cemuhookudp,axis_x:19,axis_y:20,button:131072"};
 
     const auto button_index =
         static_cast<u64>(Settings::values.touch_from_button_map_index.GetValue());

+ 198 - 8
src/input_common/drivers/udp_client.cpp

@@ -103,7 +103,7 @@ private:
 
         // Send a request for getting pad data for the pad
         const Request::PadData pad_data{
-            Request::PadData::Flags::AllPorts,
+            Request::RegisterFlags::AllPads,
             0,
             EMPTY_MAC_ADDRESS,
         };
@@ -247,7 +247,12 @@ void UDPClient::OnPadData(Response::PadData data, std::size_t client) {
 
     for (std::size_t id = 0; id < data.touch.size(); ++id) {
         const auto touch_pad = data.touch[id];
-        const int touch_id = static_cast<int>(client * 2 + id);
+        const auto touch_axis_x_id =
+            static_cast<int>(id == 0 ? PadAxes::Touch1X : PadAxes::Touch2X);
+        const auto touch_axis_y_id =
+            static_cast<int>(id == 0 ? PadAxes::Touch1Y : PadAxes::Touch2Y);
+        const auto touch_button_id =
+            static_cast<int>(id == 0 ? PadButton::Touch1 : PadButton::touch2);
 
         // TODO: Use custom calibration per device
         const Common::ParamPackage touch_param(Settings::values.touch_device.GetValue());
@@ -264,14 +269,35 @@ void UDPClient::OnPadData(Response::PadData data, std::size_t client) {
             static_cast<f32>(max_y - min_y);
 
         if (touch_pad.is_active) {
-            SetAxis(identifier, touch_id * 2, x);
-            SetAxis(identifier, touch_id * 2 + 1, y);
-            SetButton(identifier, touch_id, true);
+            SetAxis(identifier, touch_axis_x_id, x);
+            SetAxis(identifier, touch_axis_y_id, y);
+            SetButton(identifier, touch_button_id, true);
             continue;
         }
-        SetAxis(identifier, touch_id * 2, 0);
-        SetAxis(identifier, touch_id * 2 + 1, 0);
-        SetButton(identifier, touch_id, false);
+        SetAxis(identifier, touch_axis_x_id, 0);
+        SetAxis(identifier, touch_axis_y_id, 0);
+        SetButton(identifier, touch_button_id, false);
+    }
+
+    SetAxis(identifier, static_cast<int>(PadAxes::LeftStickX),
+            (data.left_stick_x - 127.0f) / 127.0f);
+    SetAxis(identifier, static_cast<int>(PadAxes::LeftStickY),
+            (data.left_stick_y - 127.0f) / 127.0f);
+    SetAxis(identifier, static_cast<int>(PadAxes::RightStickX),
+            (data.right_stick_x - 127.0f) / 127.0f);
+    SetAxis(identifier, static_cast<int>(PadAxes::RightStickY),
+            (data.right_stick_y - 127.0f) / 127.0f);
+
+    static constexpr std::array<PadButton, 16> buttons{
+        PadButton::Share,    PadButton::L3,     PadButton::R3,    PadButton::Options,
+        PadButton::Up,       PadButton::Right,  PadButton::Down,  PadButton::Left,
+        PadButton::L2,       PadButton::R2,     PadButton::L1,    PadButton::R1,
+        PadButton::Triangle, PadButton::Circle, PadButton::Cross, PadButton::Square};
+
+    for (std::size_t i = 0; i < buttons.size(); ++i) {
+        const bool button_status = (data.digital_button & (1U << i)) != 0;
+        const int button = static_cast<int>(buttons[i]);
+        SetButton(identifier, button, button_status);
     }
 }
 
@@ -317,6 +343,170 @@ void UDPClient::Reset() {
     }
 }
 
+std::vector<Common::ParamPackage> UDPClient::GetInputDevices() const {
+    std::vector<Common::ParamPackage> devices;
+    if (!Settings::values.enable_udp_controller) {
+        return devices;
+    }
+    for (std::size_t client = 0; client < clients.size(); client++) {
+        if (clients[client].active != 1) {
+            continue;
+        }
+        for (std::size_t index = 0; index < PADS_PER_CLIENT; ++index) {
+            const std::size_t pad_index = client * PADS_PER_CLIENT + index;
+            if (!pads[pad_index].connected) {
+                continue;
+            }
+            const auto pad_identifier = GetPadIdentifier(pad_index);
+            Common::ParamPackage identifier{};
+            identifier.Set("engine", GetEngineName());
+            identifier.Set("display", fmt::format("UDP Controller {}", pad_identifier.pad));
+            identifier.Set("guid", pad_identifier.guid.Format());
+            identifier.Set("port", static_cast<int>(pad_identifier.port));
+            identifier.Set("pad", static_cast<int>(pad_identifier.pad));
+            devices.emplace_back(identifier);
+        }
+    }
+    return devices;
+}
+
+ButtonMapping UDPClient::GetButtonMappingForDevice(const Common::ParamPackage& params) {
+    // This list excludes any button that can't be really mapped
+    static constexpr std::array<std::pair<Settings::NativeButton::Values, PadButton>, 18>
+        switch_to_dsu_button = {
+            std::pair{Settings::NativeButton::A, PadButton::Circle},
+            {Settings::NativeButton::B, PadButton::Cross},
+            {Settings::NativeButton::X, PadButton::Triangle},
+            {Settings::NativeButton::Y, PadButton::Square},
+            {Settings::NativeButton::Plus, PadButton::Options},
+            {Settings::NativeButton::Minus, PadButton::Share},
+            {Settings::NativeButton::DLeft, PadButton::Left},
+            {Settings::NativeButton::DUp, PadButton::Up},
+            {Settings::NativeButton::DRight, PadButton::Right},
+            {Settings::NativeButton::DDown, PadButton::Down},
+            {Settings::NativeButton::L, PadButton::L1},
+            {Settings::NativeButton::R, PadButton::R1},
+            {Settings::NativeButton::ZL, PadButton::L2},
+            {Settings::NativeButton::ZR, PadButton::R2},
+            {Settings::NativeButton::SL, PadButton::L2},
+            {Settings::NativeButton::SR, PadButton::R2},
+            {Settings::NativeButton::LStick, PadButton::L3},
+            {Settings::NativeButton::RStick, PadButton::R3},
+        };
+    if (!params.Has("guid") || !params.Has("port") || !params.Has("pad")) {
+        return {};
+    }
+
+    ButtonMapping mapping{};
+    for (const auto& [switch_button, dsu_button] : switch_to_dsu_button) {
+        Common::ParamPackage button_params{};
+        button_params.Set("engine", GetEngineName());
+        button_params.Set("guid", params.Get("guid", ""));
+        button_params.Set("port", params.Get("port", 0));
+        button_params.Set("pad", params.Get("pad", 0));
+        button_params.Set("button", static_cast<int>(dsu_button));
+        mapping.insert_or_assign(switch_button, std::move(button_params));
+    }
+
+    return mapping;
+}
+
+AnalogMapping UDPClient::GetAnalogMappingForDevice(const Common::ParamPackage& params) {
+    if (!params.Has("guid") || !params.Has("port") || !params.Has("pad")) {
+        return {};
+    }
+
+    AnalogMapping mapping = {};
+    Common::ParamPackage left_analog_params;
+    left_analog_params.Set("engine", GetEngineName());
+    left_analog_params.Set("guid", params.Get("guid", ""));
+    left_analog_params.Set("port", params.Get("port", 0));
+    left_analog_params.Set("pad", params.Get("pad", 0));
+    left_analog_params.Set("axis_x", static_cast<int>(PadAxes::LeftStickX));
+    left_analog_params.Set("axis_y", static_cast<int>(PadAxes::LeftStickY));
+    mapping.insert_or_assign(Settings::NativeAnalog::LStick, std::move(left_analog_params));
+    Common::ParamPackage right_analog_params;
+    right_analog_params.Set("engine", GetEngineName());
+    right_analog_params.Set("guid", params.Get("guid", ""));
+    right_analog_params.Set("port", params.Get("port", 0));
+    right_analog_params.Set("pad", params.Get("pad", 0));
+    right_analog_params.Set("axis_x", static_cast<int>(PadAxes::RightStickX));
+    right_analog_params.Set("axis_y", static_cast<int>(PadAxes::RightStickY));
+    mapping.insert_or_assign(Settings::NativeAnalog::RStick, std::move(right_analog_params));
+    return mapping;
+}
+
+MotionMapping UDPClient::GetMotionMappingForDevice(const Common::ParamPackage& params) {
+    if (!params.Has("guid") || !params.Has("port") || !params.Has("pad")) {
+        return {};
+    }
+
+    MotionMapping mapping = {};
+    Common::ParamPackage motion_params;
+    motion_params.Set("engine", GetEngineName());
+    motion_params.Set("guid", params.Get("guid", ""));
+    motion_params.Set("port", params.Get("port", 0));
+    motion_params.Set("pad", params.Get("pad", 0));
+    motion_params.Set("motion", 0);
+    mapping.insert_or_assign(Settings::NativeMotion::MotionLeft, std::move(motion_params));
+    mapping.insert_or_assign(Settings::NativeMotion::MotionRight, std::move(motion_params));
+    return mapping;
+}
+
+Common::Input::ButtonNames UDPClient::GetUIButtonName(const Common::ParamPackage& params) const {
+    PadButton button = static_cast<PadButton>(params.Get("button", 0));
+    switch (button) {
+    case PadButton::Left:
+        return Common::Input::ButtonNames::ButtonLeft;
+    case PadButton::Right:
+        return Common::Input::ButtonNames::ButtonRight;
+    case PadButton::Down:
+        return Common::Input::ButtonNames::ButtonDown;
+    case PadButton::Up:
+        return Common::Input::ButtonNames::ButtonUp;
+    case PadButton::L1:
+        return Common::Input::ButtonNames::L1;
+    case PadButton::L2:
+        return Common::Input::ButtonNames::L2;
+    case PadButton::L3:
+        return Common::Input::ButtonNames::L3;
+    case PadButton::R1:
+        return Common::Input::ButtonNames::R1;
+    case PadButton::R2:
+        return Common::Input::ButtonNames::R2;
+    case PadButton::R3:
+        return Common::Input::ButtonNames::R3;
+    case PadButton::Circle:
+        return Common::Input::ButtonNames::Circle;
+    case PadButton::Cross:
+        return Common::Input::ButtonNames::Cross;
+    case PadButton::Square:
+        return Common::Input::ButtonNames::Square;
+    case PadButton::Triangle:
+        return Common::Input::ButtonNames::Triangle;
+    case PadButton::Share:
+        return Common::Input::ButtonNames::Share;
+    case PadButton::Options:
+        return Common::Input::ButtonNames::Options;
+    default:
+        return Common::Input::ButtonNames::Undefined;
+    }
+}
+
+Common::Input::ButtonNames UDPClient::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;
+}
+
 void TestCommunication(const std::string& host, u16 port,
                        const std::function<void()>& success_callback,
                        const std::function<void()>& failure_callback) {

+ 56 - 0
src/input_common/drivers/udp_client.h

@@ -56,7 +56,61 @@ public:
 
     void ReloadSockets();
 
+    /// Used for automapping features
+    std::vector<Common::ParamPackage> GetInputDevices() const override;
+    ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) override;
+    AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) override;
+    MotionMapping GetMotionMappingForDevice(const Common::ParamPackage& params) override;
+    Common::Input::ButtonNames GetUIName(const Common::ParamPackage& params) const override;
+
 private:
+    enum class PadButton {
+        Undefined = 0x0000,
+        Share = 0x0001,
+        L3 = 0x0002,
+        R3 = 0x0004,
+        Options = 0x0008,
+        Up = 0x0010,
+        Right = 0x0020,
+        Down = 0x0040,
+        Left = 0x0080,
+        L2 = 0x0100,
+        R2 = 0x0200,
+        L1 = 0x0400,
+        R1 = 0x0800,
+        Triangle = 0x1000,
+        Circle = 0x2000,
+        Cross = 0x4000,
+        Square = 0x8000,
+        Touch1 = 0x10000,
+        touch2 = 0x20000,
+    };
+
+    enum class PadAxes : u8 {
+        LeftStickX,
+        LeftStickY,
+        RightStickX,
+        RightStickY,
+        AnalogLeft,
+        AnalogDown,
+        AnalogRight,
+        AnalogUp,
+        AnalogSquare,
+        AnalogCross,
+        AnalogCircle,
+        AnalogTriangle,
+        AnalogR1,
+        AnalogL1,
+        AnalogR2,
+        AnalogL3,
+        AnalogR3,
+        Touch1X,
+        Touch1Y,
+        Touch2X,
+        Touch2Y,
+        Undefined,
+    };
+
     struct PadData {
         std::size_t pad_index{};
         bool connected{};
@@ -90,6 +144,8 @@ private:
     const PadIdentifier GetPadIdentifier(std::size_t pad_index) const;
     const Common::UUID GetHostUUID(const std::string host) const;
 
+    Common::Input::ButtonNames GetUIButtonName(const Common::ParamPackage& params) const;
+
     // Allocate clients for 8 udp servers
     static constexpr std::size_t MAX_UDP_CLIENTS = 8;
     static constexpr std::size_t PADS_PER_CLIENT = 4;

+ 53 - 22
src/input_common/helpers/udp_protocol.h

@@ -56,6 +56,12 @@ constexpr Type GetMessageType();
 
 namespace Request {
 
+enum RegisterFlags : u8 {
+    AllPads,
+    PadID,
+    PadMACAdddress,
+};
+
 struct Version {};
 /**
  * Requests the server to send information about what controllers are plugged into the ports
@@ -77,13 +83,8 @@ static_assert(std::is_trivially_copyable_v<PortInfo>,
  * timeout seems to be 5 seconds.
  */
 struct PadData {
-    enum class Flags : u8 {
-        AllPorts,
-        Id,
-        Mac,
-    };
     /// Determines which method will be used as a look up for the controller
-    Flags flags{};
+    RegisterFlags flags{};
     /// Index of the port of the controller to retrieve data about
     u8 port_id{};
     /// Mac address of the controller to retrieve data about
@@ -113,6 +114,36 @@ Message<T> Create(const T data, const u32 client_id = 0) {
 
 namespace Response {
 
+enum class ConnectionType : u8 {
+    None,
+    Usb,
+    Bluetooth,
+};
+
+enum class State : u8 {
+    Disconnected,
+    Reserved,
+    Connected,
+};
+
+enum class Model : u8 {
+    None,
+    PartialGyro,
+    FullGyro,
+    Generic,
+};
+
+enum class Battery : u8 {
+    None = 0x00,
+    Dying = 0x01,
+    Low = 0x02,
+    Medium = 0x03,
+    High = 0x04,
+    Full = 0x05,
+    Charging = 0xEE,
+    Charged = 0xEF,
+};
+
 struct Version {
     u16_le version{};
 };
@@ -122,11 +153,11 @@ static_assert(std::is_trivially_copyable_v<Version>,
 
 struct PortInfo {
     u8 id{};
-    u8 state{};
-    u8 model{};
-    u8 connection_type{};
+    State state{};
+    Model model{};
+    ConnectionType connection_type{};
     MacAddress mac;
-    u8 battery{};
+    Battery battery{};
     u8 is_pad_active{};
 };
 static_assert(sizeof(PortInfo) == 12, "UDP Response PortInfo struct has wrong size");
@@ -177,18 +208,18 @@ struct PadData {
     u8 right_stick_y{};
 
     struct AnalogButton {
-        u8 button_8{};
-        u8 button_7{};
-        u8 button_6{};
-        u8 button_5{};
-        u8 button_12{};
-        u8 button_11{};
-        u8 button_10{};
-        u8 button_9{};
-        u8 button_16{};
-        u8 button_15{};
-        u8 button_14{};
-        u8 button_13{};
+        u8 button_dpad_left_analog{};
+        u8 button_dpad_down_analog{};
+        u8 button_dpad_right_analog{};
+        u8 button_dpad_up_analog{};
+        u8 button_square_analog{};
+        u8 button_cross_analog{};
+        u8 button_circle_analog{};
+        u8 button_triangle_analog{};
+        u8 button_r1_analog{};
+        u8 button_l1_analog{};
+        u8 trigger_r2{};
+        u8 trigger_l2{};
     } analog_button;
 
     std::array<TouchPad, 2> touch;

+ 6 - 0
src/input_common/input_mapping.cpp

@@ -3,6 +3,7 @@
 // Refer to the license.txt file included
 
 #include "common/common_types.h"
+#include "common/settings.h"
 #include "input_common/input_engine.h"
 #include "input_common/input_mapping.h"
 
@@ -182,6 +183,11 @@ bool MappingFactory::IsDriverValid(const MappingData& data) const {
     if (data.engine == "keyboard" && data.pad.port != 0) {
         return false;
     }
+    // To prevent mapping with two devices we disable any UDP except motion
+    if (!Settings::values.enable_udp_controller && data.engine == "cemuhookudp" &&
+        data.type != EngineInputType::Motion) {
+        return false;
+    }
     // The following drivers don't need to be mapped
     if (data.engine == "tas") {
         return false;

+ 21 - 5
src/input_common/main.cpp

@@ -63,9 +63,12 @@ struct InputSubsystem::Impl {
 
         udp_client = std::make_shared<CemuhookUDP::UDPClient>("cemuhookudp");
         udp_client->SetMappingCallback(mapping_callback);
-        udp_client_factory = std::make_shared<InputFactory>(udp_client);
+        udp_client_input_factory = std::make_shared<InputFactory>(udp_client);
+        udp_client_output_factory = std::make_shared<OutputFactory>(udp_client);
         Common::Input::RegisterFactory<Common::Input::InputDevice>(udp_client->GetEngineName(),
-                                                                   udp_client_factory);
+                                                                   udp_client_input_factory);
+        Common::Input::RegisterFactory<Common::Input::OutputDevice>(udp_client->GetEngineName(),
+                                                                    udp_client_output_factory);
 
         tas_input = std::make_shared<TasInput::Tas>("tas");
         tas_input->SetMappingCallback(mapping_callback);
@@ -110,6 +113,7 @@ struct InputSubsystem::Impl {
         gcadapter.reset();
 
         Common::Input::UnregisterFactory<Common::Input::InputDevice>(udp_client->GetEngineName());
+        Common::Input::UnregisterFactory<Common::Input::OutputDevice>(udp_client->GetEngineName());
         udp_client.reset();
 
         Common::Input::UnregisterFactory<Common::Input::InputDevice>(tas_input->GetEngineName());
@@ -137,6 +141,8 @@ struct InputSubsystem::Impl {
         devices.insert(devices.end(), mouse_devices.begin(), mouse_devices.end());
         auto gcadapter_devices = gcadapter->GetInputDevices();
         devices.insert(devices.end(), gcadapter_devices.begin(), gcadapter_devices.end());
+        auto udp_devices = udp_client->GetInputDevices();
+        devices.insert(devices.end(), udp_devices.begin(), udp_devices.end());
 #ifdef HAVE_SDL2
         auto sdl_devices = sdl->GetInputDevices();
         devices.insert(devices.end(), sdl_devices.begin(), sdl_devices.end());
@@ -157,6 +163,9 @@ struct InputSubsystem::Impl {
         if (engine == gcadapter->GetEngineName()) {
             return gcadapter->GetAnalogMappingForDevice(params);
         }
+        if (engine == udp_client->GetEngineName()) {
+            return udp_client->GetAnalogMappingForDevice(params);
+        }
         if (engine == tas_input->GetEngineName()) {
             return tas_input->GetAnalogMappingForDevice(params);
         }
@@ -177,6 +186,9 @@ struct InputSubsystem::Impl {
         if (engine == gcadapter->GetEngineName()) {
             return gcadapter->GetButtonMappingForDevice(params);
         }
+        if (engine == udp_client->GetEngineName()) {
+            return udp_client->GetButtonMappingForDevice(params);
+        }
         if (engine == tas_input->GetEngineName()) {
             return tas_input->GetButtonMappingForDevice(params);
         }
@@ -194,8 +206,8 @@ struct InputSubsystem::Impl {
             return {};
         }
         const std::string engine = params.Get("engine", "");
-        if (engine == gcadapter->GetEngineName()) {
-            return gcadapter->GetMotionMappingForDevice(params);
+        if (engine == udp_client->GetEngineName()) {
+            return udp_client->GetMotionMappingForDevice(params);
         }
 #ifdef HAVE_SDL2
         if (engine == sdl->GetEngineName()) {
@@ -238,6 +250,9 @@ struct InputSubsystem::Impl {
         if (engine == gcadapter->GetEngineName()) {
             return true;
         }
+        if (engine == udp_client->GetEngineName()) {
+            return true;
+        }
         if (engine == tas_input->GetEngineName()) {
             return true;
         }
@@ -286,12 +301,13 @@ struct InputSubsystem::Impl {
     std::shared_ptr<InputFactory> mouse_factory;
     std::shared_ptr<InputFactory> gcadapter_input_factory;
     std::shared_ptr<InputFactory> touch_screen_factory;
-    std::shared_ptr<InputFactory> udp_client_factory;
+    std::shared_ptr<InputFactory> udp_client_input_factory;
     std::shared_ptr<InputFactory> tas_input_factory;
 
     std::shared_ptr<OutputFactory> keyboard_output_factory;
     std::shared_ptr<OutputFactory> mouse_output_factory;
     std::shared_ptr<OutputFactory> gcadapter_output_factory;
+    std::shared_ptr<OutputFactory> udp_client_output_factory;
     std::shared_ptr<OutputFactory> tas_output_factory;
 
 #ifdef HAVE_SDL2

+ 2 - 0
src/yuzu/configuration/config.cpp

@@ -447,6 +447,7 @@ void Config::ReadMotionTouchValues() {
     Settings::values.touch_from_button_map_index = std::clamp(
         Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1);
     ReadBasicSetting(Settings::values.udp_input_servers);
+    ReadBasicSetting(Settings::values.enable_udp_controller);
 }
 
 void Config::ReadCoreValues() {
@@ -942,6 +943,7 @@ void Config::SaveMotionTouchValues() {
     WriteBasicSetting(Settings::values.touch_device);
     WriteBasicSetting(Settings::values.touch_from_button_map_index);
     WriteBasicSetting(Settings::values.udp_input_servers);
+    WriteBasicSetting(Settings::values.enable_udp_controller);
 
     qt_config->beginWriteArray(QStringLiteral("touch_from_button_maps"));
     for (std::size_t p = 0; p < Settings::values.touch_from_button_maps.size(); ++p) {

+ 2 - 0
src/yuzu/configuration/configure_input_advanced.cpp

@@ -130,6 +130,7 @@ void ConfigureInputAdvanced::ApplyConfiguration() {
         static_cast<float>(ui->mouse_panning_sensitivity->value());
     Settings::values.touchscreen.enabled = ui->touchscreen_enabled->isChecked();
     Settings::values.enable_raw_input = ui->enable_raw_input->isChecked();
+    Settings::values.enable_udp_controller = ui->enable_udp_controller->isChecked();
 }
 
 void ConfigureInputAdvanced::LoadConfiguration() {
@@ -160,6 +161,7 @@ void ConfigureInputAdvanced::LoadConfiguration() {
     ui->mouse_panning_sensitivity->setValue(Settings::values.mouse_panning_sensitivity.GetValue());
     ui->touchscreen_enabled->setChecked(Settings::values.touchscreen.enabled);
     ui->enable_raw_input->setChecked(Settings::values.enable_raw_input.GetValue());
+    ui->enable_udp_controller->setChecked(Settings::values.enable_udp_controller.GetValue());
 
     UpdateUIEnabled();
 }

+ 16 - 3
src/yuzu/configuration/configure_input_advanced.ui

@@ -2642,6 +2642,19 @@
                      </widget>
                    </item>
                    <item row="3" column="0">
+                     <widget class="QCheckBox" name="enable_udp_controller">
+                       <property name="minimumSize">
+                         <size>
+                           <width>0</width>
+                           <height>23</height>
+                         </size>
+                       </property>
+                       <property name="text">
+                         <string>Enable UDP controllers (not needed for motion)</string>
+                       </property>
+                     </widget>
+                   </item>
+                   <item row="4" column="0">
                      <widget class="QCheckBox" name="mouse_panning">
                        <property name="minimumSize">
                          <size>
@@ -2654,7 +2667,7 @@
                        </property>
                      </widget>
                    </item>
-                   <item row="3" column="2">
+                   <item row="4" column="2">
                      <widget class="QSpinBox" name="mouse_panning_sensitivity">
                        <property name="toolTip">
                          <string>Mouse sensitivity</string>
@@ -2676,14 +2689,14 @@
                        </property>
                      </widget>
                    </item>
-                   <item row="4" column="0">
+                   <item row="5" column="0">
                      <widget class="QLabel" name="motion_touch">
                        <property name="text">
                          <string>Motion / Touch</string>
                        </property>
                      </widget>
                    </item>
-                   <item row="4" column="2">
+                   <item row="5" column="2">
                      <widget class="QPushButton" name="buttonMotionTouch">
                        <property name="text">
                          <string>Configure</string>

+ 24 - 0
src/yuzu/configuration/configure_input_player.cpp

@@ -78,6 +78,30 @@ QString GetButtonName(Common::Input::ButtonNames button_name) {
         return QObject::tr("Y");
     case Common::Input::ButtonNames::ButtonStart:
         return QObject::tr("Start");
+    case Common::Input::ButtonNames::L1:
+        return QObject::tr("L1");
+    case Common::Input::ButtonNames::L2:
+        return QObject::tr("L2");
+    case Common::Input::ButtonNames::L3:
+        return QObject::tr("L3");
+    case Common::Input::ButtonNames::R1:
+        return QObject::tr("R1");
+    case Common::Input::ButtonNames::R2:
+        return QObject::tr("R2");
+    case Common::Input::ButtonNames::R3:
+        return QObject::tr("R3");
+    case Common::Input::ButtonNames::Circle:
+        return QObject::tr("Circle");
+    case Common::Input::ButtonNames::Cross:
+        return QObject::tr("Cross");
+    case Common::Input::ButtonNames::Square:
+        return QObject::tr("Square");
+    case Common::Input::ButtonNames::Triangle:
+        return QObject::tr("Triangle");
+    case Common::Input::ButtonNames::Share:
+        return QObject::tr("Share");
+    case Common::Input::ButtonNames::Options:
+        return QObject::tr("Options");
     default:
         return QObject::tr("[undefined]");
     }