Procházet zdrojové kódy

Added multi-input support and controller assignment at any port

David Marcec před 7 roky
rodič
revize
beab38601b

+ 168 - 119
src/core/hle/service/hid/controllers/npad.cpp

@@ -164,6 +164,57 @@ void Controller_NPad::OnLoadInputDevices() {
 
 void Controller_NPad::OnRelease() {}
 
+void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {
+    const auto controller_idx = NPadIdToIndex(npad_id);
+    const auto controller_type = connected_controllers[controller_idx].type;
+    if (!connected_controllers[controller_idx].is_connected) {
+        return;
+    }
+    auto& pad_state = npad_pad_states[controller_idx].pad_states;
+    auto& lstick_entry = npad_pad_states[controller_idx].l_stick;
+    auto& rstick_entry = npad_pad_states[controller_idx].r_stick;
+    using namespace Settings::NativeButton;
+    pad_state.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus());
+    pad_state.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus());
+    pad_state.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus());
+    pad_state.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus());
+    pad_state.l_stick.Assign(buttons[LStick - BUTTON_HID_BEGIN]->GetStatus());
+    pad_state.r_stick.Assign(buttons[RStick - BUTTON_HID_BEGIN]->GetStatus());
+    pad_state.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus());
+    pad_state.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus());
+    pad_state.zl.Assign(buttons[ZL - BUTTON_HID_BEGIN]->GetStatus());
+    pad_state.zr.Assign(buttons[ZR - BUTTON_HID_BEGIN]->GetStatus());
+    pad_state.plus.Assign(buttons[Plus - BUTTON_HID_BEGIN]->GetStatus());
+    pad_state.minus.Assign(buttons[Minus - BUTTON_HID_BEGIN]->GetStatus());
+
+    pad_state.d_left.Assign(buttons[DLeft - BUTTON_HID_BEGIN]->GetStatus());
+    pad_state.d_up.Assign(buttons[DUp - BUTTON_HID_BEGIN]->GetStatus());
+    pad_state.d_right.Assign(buttons[DRight - BUTTON_HID_BEGIN]->GetStatus());
+    pad_state.d_down.Assign(buttons[DDown - BUTTON_HID_BEGIN]->GetStatus());
+
+    pad_state.l_stick_left.Assign(buttons[LStick_Left - BUTTON_HID_BEGIN]->GetStatus());
+    pad_state.l_stick_up.Assign(buttons[LStick_Up - BUTTON_HID_BEGIN]->GetStatus());
+    pad_state.l_stick_right.Assign(buttons[LStick_Right - BUTTON_HID_BEGIN]->GetStatus());
+    pad_state.l_stick_down.Assign(buttons[LStick_Down - BUTTON_HID_BEGIN]->GetStatus());
+
+    pad_state.r_stick_left.Assign(buttons[RStick_Left - BUTTON_HID_BEGIN]->GetStatus());
+    pad_state.r_stick_up.Assign(buttons[RStick_Up - BUTTON_HID_BEGIN]->GetStatus());
+    pad_state.r_stick_right.Assign(buttons[RStick_Right - BUTTON_HID_BEGIN]->GetStatus());
+    pad_state.r_stick_down.Assign(buttons[RStick_Down - BUTTON_HID_BEGIN]->GetStatus());
+
+    pad_state.sl.Assign(buttons[SL - BUTTON_HID_BEGIN]->GetStatus());
+    pad_state.sr.Assign(buttons[SR - BUTTON_HID_BEGIN]->GetStatus());
+
+    const auto [stick_l_x_f, stick_l_y_f] =
+        sticks[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus();
+    const auto [stick_r_x_f, stick_r_y_f] =
+        sticks[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus();
+    lstick_entry.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX);
+    lstick_entry.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX);
+    rstick_entry.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX);
+    rstick_entry.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX);
+}
+
 void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) {
     if (!IsControllerActivated())
         return;
@@ -199,97 +250,9 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) {
         if (controller_type == NPadControllerType::None || !connected_controllers[i].is_connected) {
             continue;
         }
-
-        // Pad states
-        ControllerPadState pad_state{};
-        using namespace Settings::NativeButton;
-        pad_state.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus());
-        pad_state.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus());
-        pad_state.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus());
-        pad_state.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus());
-        pad_state.l_stick.Assign(buttons[LStick - BUTTON_HID_BEGIN]->GetStatus());
-        pad_state.r_stick.Assign(buttons[RStick - BUTTON_HID_BEGIN]->GetStatus());
-        pad_state.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus());
-        pad_state.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus());
-        pad_state.zl.Assign(buttons[ZL - BUTTON_HID_BEGIN]->GetStatus());
-        pad_state.zr.Assign(buttons[ZR - BUTTON_HID_BEGIN]->GetStatus());
-        pad_state.plus.Assign(buttons[Plus - BUTTON_HID_BEGIN]->GetStatus());
-        pad_state.minus.Assign(buttons[Minus - BUTTON_HID_BEGIN]->GetStatus());
-
-        pad_state.d_left.Assign(buttons[DLeft - BUTTON_HID_BEGIN]->GetStatus());
-        pad_state.d_up.Assign(buttons[DUp - BUTTON_HID_BEGIN]->GetStatus());
-        pad_state.d_right.Assign(buttons[DRight - BUTTON_HID_BEGIN]->GetStatus());
-        pad_state.d_down.Assign(buttons[DDown - BUTTON_HID_BEGIN]->GetStatus());
-
-        pad_state.l_stick_left.Assign(buttons[LStick_Left - BUTTON_HID_BEGIN]->GetStatus());
-        pad_state.l_stick_up.Assign(buttons[LStick_Up - BUTTON_HID_BEGIN]->GetStatus());
-        pad_state.l_stick_right.Assign(buttons[LStick_Right - BUTTON_HID_BEGIN]->GetStatus());
-        pad_state.l_stick_down.Assign(buttons[LStick_Down - BUTTON_HID_BEGIN]->GetStatus());
-
-        pad_state.r_stick_left.Assign(buttons[RStick_Left - BUTTON_HID_BEGIN]->GetStatus());
-        pad_state.r_stick_up.Assign(buttons[RStick_Up - BUTTON_HID_BEGIN]->GetStatus());
-        pad_state.r_stick_right.Assign(buttons[RStick_Right - BUTTON_HID_BEGIN]->GetStatus());
-        pad_state.r_stick_down.Assign(buttons[RStick_Down - BUTTON_HID_BEGIN]->GetStatus());
-
-        pad_state.sl.Assign(buttons[SL - BUTTON_HID_BEGIN]->GetStatus());
-        pad_state.sr.Assign(buttons[SR - BUTTON_HID_BEGIN]->GetStatus());
-
-        AnalogPosition lstick_entry{};
-        AnalogPosition rstick_entry{};
-
-        const auto [stick_l_x_f, stick_l_y_f] =
-            sticks[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus();
-        const auto [stick_r_x_f, stick_r_y_f] =
-            sticks[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus();
-        lstick_entry.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX);
-        lstick_entry.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX);
-        rstick_entry.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX);
-        rstick_entry.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX);
-
-        if (controller_type == NPadControllerType::JoyLeft ||
-            controller_type == NPadControllerType::JoyRight) {
-            if (npad.properties.is_horizontal) {
-                ControllerPadState state{};
-                AnalogPosition temp_lstick_entry{};
-                AnalogPosition temp_rstick_entry{};
-                if (controller_type == NPadControllerType::JoyLeft) {
-                    state.d_down.Assign(pad_state.d_left.Value());
-                    state.d_left.Assign(pad_state.d_up.Value());
-                    state.d_right.Assign(pad_state.d_down.Value());
-                    state.d_up.Assign(pad_state.d_right.Value());
-                    state.l.Assign(pad_state.l.Value() | pad_state.sl.Value());
-                    state.r.Assign(pad_state.r.Value() | pad_state.sr.Value());
-
-                    state.zl.Assign(pad_state.zl.Value());
-                    state.plus.Assign(pad_state.minus.Value());
-
-                    temp_lstick_entry = lstick_entry;
-                    temp_rstick_entry = rstick_entry;
-                    std::swap(temp_lstick_entry.x, temp_lstick_entry.y);
-                    std::swap(temp_rstick_entry.x, temp_rstick_entry.y);
-                    temp_lstick_entry.y *= -1;
-                } else if (controller_type == NPadControllerType::JoyRight) {
-                    state.x.Assign(pad_state.a.Value());
-                    state.a.Assign(pad_state.b.Value());
-                    state.b.Assign(pad_state.y.Value());
-                    state.y.Assign(pad_state.b.Value());
-
-                    state.l.Assign(pad_state.l.Value() | pad_state.sl.Value());
-                    state.r.Assign(pad_state.r.Value() | pad_state.sr.Value());
-                    state.zr.Assign(pad_state.zr.Value());
-                    state.plus.Assign(pad_state.plus.Value());
-
-                    temp_lstick_entry = lstick_entry;
-                    temp_rstick_entry = rstick_entry;
-                    std::swap(temp_lstick_entry.x, temp_lstick_entry.y);
-                    std::swap(temp_rstick_entry.x, temp_rstick_entry.y);
-                    temp_rstick_entry.x *= -1;
-                }
-                pad_state.raw = state.raw;
-                lstick_entry = temp_lstick_entry;
-                rstick_entry = temp_rstick_entry;
-            }
-        }
+        const u32 npad_index = static_cast<u32>(i);
+        RequestPadStateUpdate(npad_index);
+        auto& pad_state = npad_pad_states[npad_index];
 
         auto& main_controller =
             npad.main_controller_states.npad[npad.main_controller_states.common.last_entry_index];
@@ -304,7 +267,45 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) {
         auto& libnx_entry = npad.libnx.npad[npad.libnx.common.last_entry_index];
 
         if (hold_type == NpadHoldType::Horizontal) {
-            // TODO(ogniK): Remap buttons for different orientations
+            ControllerPadState state{};
+            AnalogPosition temp_lstick_entry{};
+            AnalogPosition temp_rstick_entry{};
+            if (controller_type == NPadControllerType::JoyLeft) {
+                state.d_down.Assign(pad_state.pad_states.d_left.Value());
+                state.d_left.Assign(pad_state.pad_states.d_up.Value());
+                state.d_right.Assign(pad_state.pad_states.d_down.Value());
+                state.d_up.Assign(pad_state.pad_states.d_right.Value());
+                state.l.Assign(pad_state.pad_states.l.Value() | pad_state.pad_states.sl.Value());
+                state.r.Assign(pad_state.pad_states.r.Value() | pad_state.pad_states.sr.Value());
+
+                state.zl.Assign(pad_state.pad_states.zl.Value());
+                state.plus.Assign(pad_state.pad_states.minus.Value());
+
+                temp_lstick_entry = pad_state.l_stick;
+                temp_rstick_entry = pad_state.r_stick;
+                std::swap(temp_lstick_entry.x, temp_lstick_entry.y);
+                std::swap(temp_rstick_entry.x, temp_rstick_entry.y);
+                temp_lstick_entry.y *= -1;
+            } else if (controller_type == NPadControllerType::JoyRight) {
+                state.x.Assign(pad_state.pad_states.a.Value());
+                state.a.Assign(pad_state.pad_states.b.Value());
+                state.b.Assign(pad_state.pad_states.y.Value());
+                state.y.Assign(pad_state.pad_states.b.Value());
+
+                state.l.Assign(pad_state.pad_states.l.Value() | pad_state.pad_states.sl.Value());
+                state.r.Assign(pad_state.pad_states.r.Value() | pad_state.pad_states.sr.Value());
+                state.zr.Assign(pad_state.pad_states.zr.Value());
+                state.plus.Assign(pad_state.pad_states.plus.Value());
+
+                temp_lstick_entry = pad_state.l_stick;
+                temp_rstick_entry = pad_state.r_stick;
+                std::swap(temp_lstick_entry.x, temp_lstick_entry.y);
+                std::swap(temp_rstick_entry.x, temp_rstick_entry.y);
+                temp_rstick_entry.x *= -1;
+            }
+            pad_state.pad_states.raw = state.raw;
+            pad_state.l_stick = temp_lstick_entry;
+            pad_state.r_stick = temp_rstick_entry;
         }
         libnx_entry.connection_status.raw = 0;
 
@@ -316,9 +317,9 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) {
             handheld_entry.connection_status.IsRightJoyConnected.Assign(1);
             handheld_entry.connection_status.IsLeftJoyWired.Assign(1);
             handheld_entry.connection_status.IsRightJoyWired.Assign(1);
-            handheld_entry.pad_states.raw = pad_state.raw;
-            handheld_entry.l_stick = lstick_entry;
-            handheld_entry.r_stick = rstick_entry;
+            handheld_entry.pad.pad_states.raw = pad_state.pad_states.raw;
+            handheld_entry.pad.l_stick = pad_state.l_stick;
+            handheld_entry.pad.r_stick = pad_state.r_stick;
             break;
         case NPadControllerType::JoyDual:
             dual_entry.connection_status.raw = 0;
@@ -339,17 +340,17 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) {
             left_entry.connection_status.raw = 0;
 
             left_entry.connection_status.IsConnected.Assign(1);
-            left_entry.pad_states.raw = pad_state.raw;
-            left_entry.l_stick = lstick_entry;
-            left_entry.r_stick = rstick_entry;
+            left_entry.pad.pad_states.raw = pad_state.pad_states.raw;
+            left_entry.pad.l_stick = pad_state.l_stick;
+            left_entry.pad.r_stick = pad_state.r_stick;
             break;
         case NPadControllerType::JoyRight:
             right_entry.connection_status.raw = 0;
 
             right_entry.connection_status.IsConnected.Assign(1);
-            right_entry.pad_states.raw = pad_state.raw;
-            right_entry.l_stick = lstick_entry;
-            right_entry.r_stick = rstick_entry;
+            right_entry.pad.pad_states.raw = pad_state.pad_states.raw;
+            right_entry.pad.l_stick = pad_state.l_stick;
+            right_entry.pad.r_stick = pad_state.r_stick;
             break;
         case NPadControllerType::Pokeball:
             pokeball_entry.connection_status.raw = 0;
@@ -357,26 +358,26 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) {
             pokeball_entry.connection_status.IsConnected.Assign(1);
             pokeball_entry.connection_status.IsWired.Assign(1);
 
-            pokeball_entry.pad_states.raw = pad_state.raw;
-            pokeball_entry.l_stick = lstick_entry;
-            pokeball_entry.r_stick = rstick_entry;
+            pokeball_entry.pad.pad_states.raw = pad_state.pad_states.raw;
+            pokeball_entry.pad.l_stick = pad_state.l_stick;
+            pokeball_entry.pad.r_stick = pad_state.r_stick;
             break;
         case NPadControllerType::ProController:
             main_controller.connection_status.raw = 0;
 
             main_controller.connection_status.IsConnected.Assign(1);
             main_controller.connection_status.IsWired.Assign(1);
-            main_controller.pad_states.raw = pad_state.raw;
-            main_controller.l_stick = lstick_entry;
-            main_controller.r_stick = rstick_entry;
+            main_controller.pad.pad_states.raw = pad_state.pad_states.raw;
+            main_controller.pad.l_stick = pad_state.l_stick;
+            main_controller.pad.r_stick = pad_state.r_stick;
             break;
         }
 
         // LibNX exclusively uses this section, so we always update it since LibNX doesn't activate
         // any controllers.
-        libnx_entry.pad_states.raw = pad_state.raw;
-        libnx_entry.l_stick = lstick_entry;
-        libnx_entry.r_stick = rstick_entry;
+        libnx_entry.pad.pad_states.raw = pad_state.pad_states.raw;
+        libnx_entry.pad.l_stick = pad_state.l_stick;
+        libnx_entry.pad.r_stick = pad_state.r_stick;
     }
     std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(),
                 shared_memory_entries.size() * sizeof(NPadEntry));
@@ -450,15 +451,7 @@ void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
         return;
     }
     for (std::size_t i = 0; i < controller_ids.size(); i++) {
-        std::size_t controller_pos = i;
-        // Handheld controller conversion
-        if (controller_pos == NPAD_HANDHELD) {
-            controller_pos = 8;
-        }
-        // Unknown controller conversion
-        if (controller_pos == NPAD_UNKNOWN) {
-            controller_pos = 9;
-        }
+        std::size_t controller_pos = NPadIdToIndex(static_cast<u32>(i));
         if (connected_controllers[controller_pos].is_connected) {
             // TODO(ogniK): Vibrate the physical controller
         }
@@ -477,6 +470,51 @@ Kernel::SharedPtr<Kernel::Event> Controller_NPad::GetStyleSetChangedEvent() cons
 Controller_NPad::Vibration Controller_NPad::GetLastVibration() const {
     return last_processed_vibration;
 }
+
+std::size_t Controller_NPad::NPadIdToIndex(u32 npad_id) {
+    switch (npad_id) {
+    case 0:
+    case 1:
+    case 2:
+    case 3:
+    case 4:
+    case 5:
+    case 6:
+    case 7:
+        return static_cast<std::size_t>(npad_id);
+    case 8:
+    case 32:
+        return 8;
+    case 9:
+    case 16:
+        return 9;
+    default:
+        UNIMPLEMENTED_MSG("Unknown npad id {}", npad_id);
+        return 0;
+    }
+}
+
+u32 Controller_NPad::IndexToNPad(std::size_t index) {
+    switch (index) {
+    case 0:
+    case 1:
+    case 2:
+    case 3:
+    case 4:
+    case 5:
+    case 6:
+    case 7:
+        return static_cast<u32>(index);
+    case 8:
+        return 32;
+    case 9:
+        return 16;
+    default:
+        UNIMPLEMENTED_MSG("Unknown npad index {}", index);
+        return 0;
+    };
+}
+
 void Controller_NPad::AddNewController(NPadControllerType controller) {
     if (controller == NPadControllerType::Handheld) {
         connected_controllers[8] = {controller, true};
@@ -495,6 +533,17 @@ void Controller_NPad::AddNewController(NPadControllerType controller) {
     InitNewlyAddedControler(controller_id);
 }
 
+void Controller_NPad::AddNewControllerAt(NPadControllerType controller, u32 npad_id) {
+    if (controller == NPadControllerType::Handheld) {
+        connected_controllers[8] = {controller, true};
+        InitNewlyAddedControler(8);
+        return;
+    }
+    const size_t controller_id = static_cast<std::size_t>(npad_id);
+    connected_controllers[controller_id] = {controller, true};
+    InitNewlyAddedControler(controller_id);
+}
+
 void Controller_NPad::ConnectNPad(u32 npad_id) {
     connected_controllers[NPadIdToIndex(npad_id)].is_connected = true;
 }

+ 13 - 3
src/core/hle/service/hid/controllers/npad.h

@@ -107,6 +107,7 @@ public:
     Vibration GetLastVibration() const;
 
     void AddNewController(NPadControllerType controller);
+    void AddNewControllerAt(NPadControllerType controller, u32 npad_id);
 
     void ConnectNPad(u32 npad_id);
     void DisconnectNPad(u32 npad_id);
@@ -189,12 +190,17 @@ private:
     };
     static_assert(sizeof(ConnectionState) == 4, "ConnectionState is an invalid size");
 
-    struct GenericStates {
-        s64_le timestamp;
-        s64_le timestamp2;
+    struct ControllerPad {
         ControllerPadState pad_states;
         AnalogPosition l_stick;
         AnalogPosition r_stick;
+    };
+    static_assert(sizeof(ControllerPad) == 0x18, "ControllerPad is an invalid size");
+
+    struct GenericStates {
+        s64_le timestamp;
+        s64_le timestamp2;
+        ControllerPad pad;
         ConnectionState connection_status;
     };
     static_assert(sizeof(GenericStates) == 0x30, "NPadGenericStates is an invalid size");
@@ -285,5 +291,9 @@ private:
     void InitNewlyAddedControler(std::size_t controller_idx);
     bool IsControllerSupported(NPadControllerType controller) const;
     NPadControllerType DecideBestController(NPadControllerType priority) const;
+    void RequestPadStateUpdate(u32 npad_id);
+    std::size_t NPadIdToIndex(u32 npad_id);
+    u32 IndexToNPad(std::size_t index);
+    std::array<ControllerPad, 10> npad_pad_states{};
 };
 } // namespace Service::HID