summaryrefslogtreecommitdiffstats
path: root/src/core/hle/service/hid/controllers/npad.cpp
diff options
context:
space:
mode:
authorDavid Marcec <dmarcecguzman@gmail.com>2018-10-05 16:23:21 +0200
committerDavid Marcec <dmarcecguzman@gmail.com>2018-10-10 04:15:35 +0200
commit56f35ab2629c3753dbb624799bd8aaff2a179f58 (patch)
treed4c27964cf6f7679529f1042e9d71005f1e73864 /src/core/hle/service/hid/controllers/npad.cpp
parentMerge pull request #1466 from lioncash/unused (diff)
downloadyuzu-56f35ab2629c3753dbb624799bd8aaff2a179f58.tar
yuzu-56f35ab2629c3753dbb624799bd8aaff2a179f58.tar.gz
yuzu-56f35ab2629c3753dbb624799bd8aaff2a179f58.tar.bz2
yuzu-56f35ab2629c3753dbb624799bd8aaff2a179f58.tar.lz
yuzu-56f35ab2629c3753dbb624799bd8aaff2a179f58.tar.xz
yuzu-56f35ab2629c3753dbb624799bd8aaff2a179f58.tar.zst
yuzu-56f35ab2629c3753dbb624799bd8aaff2a179f58.zip
Diffstat (limited to 'src/core/hle/service/hid/controllers/npad.cpp')
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp336
1 files changed, 336 insertions, 0 deletions
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
new file mode 100644
index 000000000..a53687b91
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -0,0 +1,336 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+#include <array>
+#include "common/assert.h"
+#include "common/bit_field.h"
+#include "common/common_types.h"
+#include "common/swap.h"
+#include "core/core.h"
+#include "core/core_timing.h"
+#include "core/frontend/input.h"
+#include "core/hle/kernel/event.h"
+#include "core/hle/service/hid/controllers/npad.h"
+#include "core/settings.h"
+
+namespace Service::HID {
+constexpr u32 JOYCON_BODY_NEON_RED = 0xFF3C28;
+constexpr u32 JOYCON_BUTTONS_NEON_RED = 0x1E0A0A;
+constexpr u32 JOYCON_BODY_NEON_BLUE = 0x0AB9E6;
+constexpr u32 JOYCON_BUTTONS_NEON_BLUE = 0x001E1E;
+constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
+constexpr s32 HID_JOYSTICK_MIN = -0x7fff;
+constexpr size_t NPAD_OFFSET = 0x9A00;
+constexpr size_t MAX_CONTROLLER_COUNT = 9;
+
+enum class JoystickId : size_t { Joystick_Left, Joystick_Right };
+constexpr std::array<u32, MAX_CONTROLLER_COUNT> NPAD_ID_LIST{0, 1, 2, 3, 4, 5, 6, 7, 32};
+size_t CONTROLLER_COUNT{};
+std::array<Controller_NPad::NPadControllerType, MAX_CONTROLLER_COUNT> CONNECTED_CONTROLLERS{};
+
+void Controller_NPad::InitNewlyAddedControler(size_t controller_idx) {
+ const auto controller_type = CONNECTED_CONTROLLERS[controller_idx];
+ auto& controller = shared_memory_entries[controller_idx];
+ if (controller_type == NPadControllerType::None) {
+ return;
+ }
+ controller.joy_styles.raw = 0; // Zero out
+ controller.device_type.raw = 0;
+ switch (controller_type) {
+ case NPadControllerType::Handheld:
+ controller.joy_styles.handheld.Assign(1);
+ controller.device_type.handheld.Assign(1);
+ controller.pad_assignment = NPadAssignments::Dual;
+ break;
+ case NPadControllerType::JoyLeft:
+ controller.joy_styles.joycon_left.Assign(1);
+ controller.device_type.joycon_left.Assign(1);
+ controller.pad_assignment = NPadAssignments::Dual;
+ break;
+ case NPadControllerType::JoyRight:
+ controller.joy_styles.joycon_right.Assign(1);
+ controller.device_type.joycon_right.Assign(1);
+ controller.pad_assignment = NPadAssignments::Dual;
+ break;
+ case NPadControllerType::Tabletop:
+ UNIMPLEMENTED_MSG("Tabletop is not implemented");
+ break;
+ case NPadControllerType::Pokeball:
+ controller.joy_styles.pokeball.Assign(1);
+ controller.device_type.pokeball.Assign(1);
+ controller.pad_assignment = NPadAssignments::Single;
+ break;
+ case NPadControllerType::ProController:
+ controller.joy_styles.pro_controller.Assign(1);
+ controller.device_type.pro_controller.Assign(1);
+ controller.pad_assignment = NPadAssignments::Single;
+ break;
+ }
+
+ controller.single_color_error = ColorReadError::ReadOk;
+ controller.single_color.body_color = 0;
+ controller.single_color.button_color = 0;
+
+ controller.dual_color_error = ColorReadError::ReadOk;
+ controller.left_color.body_color = JOYCON_BODY_NEON_BLUE;
+ controller.left_color.button_color = JOYCON_BUTTONS_NEON_BLUE;
+ controller.right_color.body_color = JOYCON_BODY_NEON_RED;
+ controller.right_color.button_color = JOYCON_BUTTONS_NEON_RED;
+
+ controller.properties.is_verticle.Assign(1); // TODO(ogniK): Swap joycons orientations
+}
+
+void Controller_NPad::OnInit() {
+ auto& kernel = Core::System::GetInstance().Kernel();
+ styleset_changed_event =
+ Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "npad:NpadStyleSetChanged");
+
+ if (!IsControllerActivated())
+ return;
+ size_t controller{};
+ supported_npad_id_types.resize(NPAD_ID_LIST.size());
+ if (style.raw == 0) {
+ // We want to support all controllers
+ style.handheld.Assign(1);
+ style.joycon_left.Assign(1);
+ style.joycon_right.Assign(1);
+ style.joycon_dual.Assign(1);
+ style.pro_controller.Assign(1);
+ style.pokeball.Assign(1);
+ }
+ std::memcpy(supported_npad_id_types.data(), NPAD_ID_LIST.data(),
+ NPAD_ID_LIST.size() * sizeof(u32));
+ if (CONTROLLER_COUNT == 0) {
+ AddNewController(NPadControllerType::Handheld);
+ }
+}
+
+void Controller_NPad::OnLoadInputDevices() {
+ std::transform(Settings::values.buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN,
+ Settings::values.buttons.begin() + Settings::NativeButton::BUTTON_HID_END,
+ buttons.begin(), Input::CreateDevice<Input::ButtonDevice>);
+ std::transform(Settings::values.analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN,
+ Settings::values.analogs.begin() + Settings::NativeAnalog::STICK_HID_END,
+ sticks.begin(), Input::CreateDevice<Input::AnalogDevice>);
+}
+
+void Controller_NPad::OnRelease() {}
+
+void Controller_NPad::OnUpdate(u8* data, size_t data_len) {
+ if (!IsControllerActivated())
+ return;
+ for (size_t i = 0; i < shared_memory_entries.size(); i++) {
+ auto& npad = shared_memory_entries[i];
+ const std::array<NPadGeneric*, 7> controller_npads{&npad.main_controller_states,
+ &npad.handheld_states,
+ &npad.dual_states,
+ &npad.left_joy_states,
+ &npad.right_joy_states,
+ &npad.pokeball_states,
+ &npad.libnx};
+
+ for (auto main_controller : controller_npads) {
+ main_controller->common.entry_count = 16;
+ main_controller->common.total_entry_count = 17;
+
+ auto& last_entry = main_controller->npad[main_controller->common.last_entry_index];
+
+ main_controller->common.timestamp = CoreTiming::GetTicks();
+ main_controller->common.last_entry_index =
+ (main_controller->common.last_entry_index + 1) % 17;
+
+ auto& cur_entry = main_controller->npad[main_controller->common.last_entry_index];
+
+ cur_entry.timestamp = last_entry.timestamp + 1;
+ cur_entry.timestamp2 = cur_entry.timestamp;
+ }
+
+ if (CONNECTED_CONTROLLERS[i] == NPadControllerType::None) {
+ continue;
+ }
+
+ const auto& controller_type = CONNECTED_CONTROLLERS[i];
+
+ // Pad states
+ auto pad_state = ControllerPadState{};
+ 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.dleft.Assign(buttons[DLeft - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.dup.Assign(buttons[DUp - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.dright.Assign(buttons[DRight - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.ddown.Assign(buttons[DDown - BUTTON_HID_BEGIN]->GetStatus());
+
+ pad_state.lstickleft.Assign(buttons[LStick_Left - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.lstickup.Assign(buttons[LStick_Up - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.lstickright.Assign(buttons[LStick_Right - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.lstickdown.Assign(buttons[LStick_Down - BUTTON_HID_BEGIN]->GetStatus());
+
+ pad_state.rstickleft.Assign(buttons[RStick_Left - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.rstickup.Assign(buttons[RStick_Up - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.rstickright.Assign(buttons[RStick_Right - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.rstickdown.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<size_t>(JoystickId::Joystick_Left)]->GetStatus();
+ const auto [stick_r_x_f, stick_r_y_f] =
+ sticks[static_cast<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);
+
+ auto& main_controller =
+ npad.main_controller_states.npad[npad.main_controller_states.common.last_entry_index];
+ auto& handheld_entry =
+ npad.handheld_states.npad[npad.handheld_states.common.last_entry_index];
+ auto& dual_entry = npad.dual_states.npad[npad.dual_states.common.last_entry_index];
+ auto& left_entry = npad.left_joy_states.npad[npad.left_joy_states.common.last_entry_index];
+ auto& right_entry =
+ npad.right_joy_states.npad[npad.right_joy_states.common.last_entry_index];
+ auto& pokeball_entry =
+ npad.pokeball_states.npad[npad.pokeball_states.common.last_entry_index];
+ auto& libnx_entry = npad.libnx.npad[npad.libnx.common.last_entry_index];
+
+ if (hold_type == NpadHoldType::Horizontal) {
+ // TODO(ogniK): Remap buttons for different orientations
+ }
+
+ switch (controller_type) {
+ case NPadControllerType::Handheld:
+ handheld_entry.connection_status.IsConnected.Assign(1);
+ handheld_entry.connection_status.IsWired.Assign(1);
+ handheld_entry.pad_states.raw = pad_state.raw;
+ handheld_entry.lstick = lstick_entry;
+ handheld_entry.rstick = rstick_entry;
+ break;
+ case NPadControllerType::JoyLeft:
+ left_entry.connection_status.IsConnected.Assign(1);
+ left_entry.pad_states.raw = pad_state.raw;
+ left_entry.lstick = lstick_entry;
+ left_entry.rstick = rstick_entry;
+ break;
+ case NPadControllerType::JoyRight:
+ right_entry.connection_status.IsConnected.Assign(1);
+ right_entry.pad_states.raw = pad_state.raw;
+ right_entry.lstick = lstick_entry;
+ right_entry.rstick = rstick_entry;
+ break;
+ case NPadControllerType::Tabletop:
+ // TODO(ogniK): Figure out how to add proper tabletop support
+ dual_entry.pad_states.raw = pad_state.raw;
+ dual_entry.lstick = lstick_entry;
+ dual_entry.rstick = rstick_entry;
+ dual_entry.connection_status.IsConnected.Assign(1);
+ break;
+ case NPadControllerType::Pokeball:
+ pokeball_entry.connection_status.IsConnected.Assign(1);
+ pokeball_entry.connection_status.IsWired.Assign(1);
+
+ pokeball_entry.pad_states.raw = pad_state.raw;
+ pokeball_entry.lstick = lstick_entry;
+ pokeball_entry.rstick = rstick_entry;
+ break;
+ case NPadControllerType::ProController:
+ main_controller.pad_states.raw = pad_state.raw;
+ main_controller.lstick = lstick_entry;
+ main_controller.rstick = rstick_entry;
+ main_controller.connection_status.IsConnected.Assign(1);
+ main_controller.connection_status.IsWired.Assign(1);
+ break;
+ }
+
+ // LibNX exclusively uses this section, so we always update it since LibNX doesn't activate
+ // any controllers.
+ libnx_entry.connection_status.IsConnected.Assign(1);
+ libnx_entry.connection_status.IsWired.Assign(1);
+ libnx_entry.pad_states.raw = pad_state.raw;
+ libnx_entry.lstick = lstick_entry;
+ libnx_entry.rstick = rstick_entry;
+ }
+ std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(),
+ shared_memory_entries.size() * sizeof(NPadEntry));
+}
+
+void Controller_NPad::SetSupportedStyleSet(NPadType style_set) {
+ style.raw = style_set.raw;
+}
+
+Controller_NPad::NPadType Controller_NPad::GetSupportedStyleSet() const {
+ return style;
+}
+
+void Controller_NPad::SetSupportedNPadIdTypes(u8* data, size_t length) {
+ ASSERT(length > 0 && (length % sizeof(u32)) == 0);
+ supported_npad_id_types.resize(length / 4);
+ std::memcpy(supported_npad_id_types.data(), data, length);
+}
+
+void Controller_NPad::GetSupportedNpadIdTypes(u32* data, size_t max_length) {
+ ASSERT(max_length < supported_npad_id_types.size());
+ std::memcpy(data, supported_npad_id_types.data(), supported_npad_id_types.size());
+}
+
+size_t Controller_NPad::GetSupportedNPadIdTypesSize() const {
+ return supported_npad_id_types.size();
+}
+
+void Controller_NPad::SetHoldType(NpadHoldType joy_hold_type) {
+ hold_type = joy_hold_type;
+}
+Controller_NPad::NpadHoldType Controller_NPad::GetHoldType() const {
+ return hold_type;
+}
+
+void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode) {
+ ASSERT(npad_id < shared_memory_entries.size());
+ shared_memory_entries[npad_id].pad_assignment = assignment_mode;
+}
+
+void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
+ const std::vector<Vibration>& vibrations) {
+ for (size_t i = 0; i < controller_ids.size(); i++) {
+ if (i >= CONTROLLER_COUNT) {
+ continue;
+ }
+ // TODO(ogniK): Vibrate the physical controller
+ }
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+ last_processed_vibration = vibrations.back();
+}
+
+Kernel::SharedPtr<Kernel::Event> Controller_NPad::GetStyleSetChangedEvent() const {
+ return styleset_changed_event;
+}
+
+Controller_NPad::Vibration Controller_NPad::GetLastVibration() const {
+ return last_processed_vibration;
+}
+void Controller_NPad::AddNewController(NPadControllerType controller) {
+ if (CONTROLLER_COUNT >= MAX_CONTROLLER_COUNT) {
+ LOG_ERROR(Service_HID, "Cannot connect any more controllers!");
+ return;
+ }
+ CONNECTED_CONTROLLERS[CONTROLLER_COUNT] = controller;
+ InitNewlyAddedControler(CONTROLLER_COUNT++);
+}
+}; // namespace Service::HID