summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2018-10-17 20:25:17 -0400
committerGravatar GitHub2018-10-17 20:25:17 -0400
commit7dee60d7d24dabcc2c52c8c2135f1c89adb57ff6 (patch)
tree042bae044e7b1f05eb5a561eefe37d847e0417cf /src
parentMerge pull request #1489 from FernandoS27/fix-tlds (diff)
parentUsing dual joycons as the default controller (diff)
downloadyuzu-7dee60d7d24dabcc2c52c8c2135f1c89adb57ff6.tar.gz
yuzu-7dee60d7d24dabcc2c52c8c2135f1c89adb57ff6.tar.xz
yuzu-7dee60d7d24dabcc2c52c8c2135f1c89adb57ff6.zip
Merge pull request #1444 from ogniK5377/better-hid
"Better Hid" Rework Part 1
Diffstat (limited to 'src')
-rw-r--r--src/core/CMakeLists.txt18
-rw-r--r--src/core/hle/service/hid/controllers/controller_base.cpp28
-rw-r--r--src/core/hle/service/hid/controllers/controller_base.h45
-rw-r--r--src/core/hle/service/hid/controllers/debug_pad.cpp42
-rw-r--r--src/core/hle/service/hid/controllers/debug_pad.h55
-rw-r--r--src/core/hle/service/hid/controllers/gesture.cpp43
-rw-r--r--src/core/hle/service/hid/controllers/gesture.h62
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.cpp43
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.h49
-rw-r--r--src/core/hle/service/hid/controllers/mouse.cpp43
-rw-r--r--src/core/hle/service/hid/controllers/mouse.h49
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp429
-rw-r--r--src/core/hle/service/hid/controllers/npad.h288
-rw-r--r--src/core/hle/service/hid/controllers/stubbed.cpp39
-rw-r--r--src/core/hle/service/hid/controllers/stubbed.h33
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.cpp65
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.h62
-rw-r--r--src/core/hle/service/hid/controllers/xpad.cpp45
-rw-r--r--src/core/hle/service/hid/controllers/xpad.h60
-rw-r--r--src/core/hle/service/hid/hid.cpp466
-rw-r--r--src/core/hle/service/hid/hid.h402
-rw-r--r--src/core/hle/service/nfp/nfp.cpp2
22 files changed, 1720 insertions, 648 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 78986deb5..4755ec822 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -236,6 +236,24 @@ add_library(core STATIC
236 hle/service/hid/irs.h 236 hle/service/hid/irs.h
237 hle/service/hid/xcd.cpp 237 hle/service/hid/xcd.cpp
238 hle/service/hid/xcd.h 238 hle/service/hid/xcd.h
239 hle/service/hid/controllers/controller_base.cpp
240 hle/service/hid/controllers/controller_base.h
241 hle/service/hid/controllers/debug_pad.cpp
242 hle/service/hid/controllers/debug_pad.h
243 hle/service/hid/controllers/gesture.cpp
244 hle/service/hid/controllers/gesture.h
245 hle/service/hid/controllers/keyboard.cpp
246 hle/service/hid/controllers/keyboard.h
247 hle/service/hid/controllers/mouse.cpp
248 hle/service/hid/controllers/mouse.h
249 hle/service/hid/controllers/npad.cpp
250 hle/service/hid/controllers/npad.h
251 hle/service/hid/controllers/stubbed.cpp
252 hle/service/hid/controllers/stubbed.h
253 hle/service/hid/controllers/touchscreen.cpp
254 hle/service/hid/controllers/touchscreen.h
255 hle/service/hid/controllers/xpad.cpp
256 hle/service/hid/controllers/xpad.h
239 hle/service/lbl/lbl.cpp 257 hle/service/lbl/lbl.cpp
240 hle/service/lbl/lbl.h 258 hle/service/lbl/lbl.h
241 hle/service/ldn/ldn.cpp 259 hle/service/ldn/ldn.cpp
diff --git a/src/core/hle/service/hid/controllers/controller_base.cpp b/src/core/hle/service/hid/controllers/controller_base.cpp
new file mode 100644
index 000000000..1625e9c3d
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/controller_base.cpp
@@ -0,0 +1,28 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/hle/service/hid/controllers/controller_base.h"
6
7namespace Service::HID {
8ControllerBase::~ControllerBase() = default;
9
10void ControllerBase::ActivateController() {
11 if (is_activated) {
12 OnRelease();
13 }
14 is_activated = true;
15 OnInit();
16}
17
18void ControllerBase::DeactivateController() {
19 if (is_activated) {
20 OnRelease();
21 }
22 is_activated = false;
23}
24
25bool ControllerBase::IsControllerActivated() const {
26 return is_activated;
27}
28} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/controller_base.h b/src/core/hle/service/hid/controllers/controller_base.h
new file mode 100644
index 000000000..fa98e2354
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/controller_base.h
@@ -0,0 +1,45 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8#include "common/swap.h"
9
10namespace Service::HID {
11class ControllerBase {
12public:
13 ControllerBase() = default;
14 virtual ~ControllerBase() = 0;
15
16 // Called when the controller is initialized
17 virtual void OnInit() = 0;
18
19 // When the controller is released
20 virtual void OnRelease() = 0;
21
22 // When the controller is requesting an update for the shared memory
23 virtual void OnUpdate(u8* data, std::size_t size) = 0;
24
25 // Called when input devices should be loaded
26 virtual void OnLoadInputDevices() = 0;
27
28 void ActivateController();
29
30 void DeactivateController();
31
32 bool IsControllerActivated() const;
33
34protected:
35 bool is_activated{false};
36
37 struct CommonHeader {
38 s64_le timestamp;
39 s64_le total_entry_count;
40 s64_le last_entry_index;
41 s64_le entry_count;
42 };
43 static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size");
44};
45} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/debug_pad.cpp b/src/core/hle/service/hid/controllers/debug_pad.cpp
new file mode 100644
index 000000000..6f8ef6e3f
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/debug_pad.cpp
@@ -0,0 +1,42 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <cstring>
6#include "common/common_types.h"
7#include "common/swap.h"
8#include "core/core_timing.h"
9#include "core/hle/service/hid/controllers/debug_pad.h"
10
11namespace Service::HID {
12
13Controller_DebugPad::Controller_DebugPad() = default;
14
15void Controller_DebugPad::OnInit() {}
16
17void Controller_DebugPad::OnRelease() {}
18
19void Controller_DebugPad::OnUpdate(u8* data, std::size_t size) {
20 shared_memory.header.timestamp = CoreTiming::GetTicks();
21 shared_memory.header.total_entry_count = 17;
22
23 if (!IsControllerActivated()) {
24 shared_memory.header.entry_count = 0;
25 shared_memory.header.last_entry_index = 0;
26 return;
27 }
28 shared_memory.header.entry_count = 16;
29
30 const auto& last_entry = shared_memory.pad_states[shared_memory.header.last_entry_index];
31 shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17;
32 auto& cur_entry = shared_memory.pad_states[shared_memory.header.last_entry_index];
33
34 cur_entry.sampling_number = last_entry.sampling_number + 1;
35 cur_entry.sampling_number2 = cur_entry.sampling_number;
36 // TODO(ogniK): Update debug pad states
37
38 std::memcpy(data, &shared_memory, sizeof(SharedMemory));
39}
40
41void Controller_DebugPad::OnLoadInputDevices() {}
42} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/debug_pad.h b/src/core/hle/service/hid/controllers/debug_pad.h
new file mode 100644
index 000000000..e35675fa1
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/debug_pad.h
@@ -0,0 +1,55 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include "common/common_funcs.h"
9#include "common/common_types.h"
10#include "common/swap.h"
11#include "core/hle/service/hid/controllers/controller_base.h"
12
13namespace Service::HID {
14class Controller_DebugPad final : public ControllerBase {
15public:
16 Controller_DebugPad();
17
18 // Called when the controller is initialized
19 void OnInit() override;
20
21 // When the controller is released
22 void OnRelease() override;
23
24 // When the controller is requesting an update for the shared memory
25 void OnUpdate(u8* data, std::size_t size) override;
26
27 // Called when input devices should be loaded
28 void OnLoadInputDevices() override;
29
30private:
31 struct AnalogStick {
32 s32_le x;
33 s32_le y;
34 };
35 static_assert(sizeof(AnalogStick) == 0x8);
36
37 struct PadStates {
38 s64_le sampling_number;
39 s64_le sampling_number2;
40 u32_le attribute;
41 u32_le button_state;
42 AnalogStick r_stick;
43 AnalogStick l_stick;
44 };
45 static_assert(sizeof(PadStates) == 0x28, "PadStates is an invalid state");
46
47 struct SharedMemory {
48 CommonHeader header;
49 std::array<PadStates, 17> pad_states;
50 INSERT_PADDING_BYTES(0x138);
51 };
52 static_assert(sizeof(SharedMemory) == 0x400, "SharedMemory is an invalid size");
53 SharedMemory shared_memory{};
54};
55} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp
new file mode 100644
index 000000000..b473b9e2b
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/gesture.cpp
@@ -0,0 +1,43 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <cstring>
6#include "common/common_types.h"
7#include "common/swap.h"
8#include "core/core_timing.h"
9#include "core/hle/service/hid/controllers/gesture.h"
10
11namespace Service::HID {
12constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3BA00;
13
14Controller_Gesture::Controller_Gesture() = default;
15
16void Controller_Gesture::OnInit() {}
17
18void Controller_Gesture::OnRelease() {}
19
20void Controller_Gesture::OnUpdate(u8* data, std::size_t size) {
21 shared_memory.header.timestamp = CoreTiming::GetTicks();
22 shared_memory.header.total_entry_count = 17;
23
24 if (!IsControllerActivated()) {
25 shared_memory.header.entry_count = 0;
26 shared_memory.header.last_entry_index = 0;
27 return;
28 }
29 shared_memory.header.entry_count = 16;
30
31 const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index];
32 shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17;
33 auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index];
34
35 cur_entry.sampling_number = last_entry.sampling_number + 1;
36 cur_entry.sampling_number2 = cur_entry.sampling_number;
37 // TODO(ogniK): Update gesture states
38
39 std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory));
40}
41
42void Controller_Gesture::OnLoadInputDevices() {}
43} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h
new file mode 100644
index 000000000..0ced50dfd
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/gesture.h
@@ -0,0 +1,62 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include "common/common_types.h"
9#include "common/swap.h"
10#include "core/hle/service/hid/controllers/controller_base.h"
11
12namespace Service::HID {
13class Controller_Gesture final : public ControllerBase {
14public:
15 Controller_Gesture();
16
17 // Called when the controller is initialized
18 void OnInit() override;
19
20 // When the controller is released
21 void OnRelease() override;
22
23 // When the controller is requesting an update for the shared memory
24 void OnUpdate(u8* data, size_t size) override;
25
26 // Called when input devices should be loaded
27 void OnLoadInputDevices() override;
28
29private:
30 struct Locations {
31 s32_le x;
32 s32_le y;
33 };
34
35 struct GestureState {
36 s64_le sampling_number;
37 s64_le sampling_number2;
38
39 s64_le detection_count;
40 s32_le type;
41 s32_le dir;
42 s32_le x;
43 s32_le y;
44 s32_le delta_x;
45 s32_le delta_y;
46 f32 vel_x;
47 f32 vel_y;
48 s32_le attributes;
49 f32 scale;
50 f32 rotation;
51 s32_le location_count;
52 std::array<Locations, 4> locations;
53 };
54 static_assert(sizeof(GestureState) == 0x68, "GestureState is an invalid size");
55
56 struct SharedMemory {
57 CommonHeader header;
58 std::array<GestureState, 17> gesture_states;
59 };
60 SharedMemory shared_memory{};
61};
62} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp
new file mode 100644
index 000000000..089c02ac4
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/keyboard.cpp
@@ -0,0 +1,43 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <cstring>
6#include "common/common_types.h"
7#include "common/swap.h"
8#include "core/core_timing.h"
9#include "core/hle/service/hid/controllers/keyboard.h"
10
11namespace Service::HID {
12constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800;
13
14Controller_Keyboard::Controller_Keyboard() = default;
15
16void Controller_Keyboard::OnInit() {}
17
18void Controller_Keyboard::OnRelease() {}
19
20void Controller_Keyboard::OnUpdate(u8* data, std::size_t size) {
21 shared_memory.header.timestamp = CoreTiming::GetTicks();
22 shared_memory.header.total_entry_count = 17;
23
24 if (!IsControllerActivated()) {
25 shared_memory.header.entry_count = 0;
26 shared_memory.header.last_entry_index = 0;
27 return;
28 }
29 shared_memory.header.entry_count = 16;
30
31 const auto& last_entry = shared_memory.pad_states[shared_memory.header.last_entry_index];
32 shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17;
33 auto& cur_entry = shared_memory.pad_states[shared_memory.header.last_entry_index];
34
35 cur_entry.sampling_number = last_entry.sampling_number + 1;
36 cur_entry.sampling_number2 = cur_entry.sampling_number;
37 // TODO(ogniK): Update keyboard states
38
39 std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory));
40}
41
42void Controller_Keyboard::OnLoadInputDevices() {}
43} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/keyboard.h b/src/core/hle/service/hid/controllers/keyboard.h
new file mode 100644
index 000000000..778e14f7e
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/keyboard.h
@@ -0,0 +1,49 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include "common/common_funcs.h"
9#include "common/common_types.h"
10#include "common/swap.h"
11#include "core/hle/service/hid/controllers/controller_base.h"
12
13namespace Service::HID {
14class Controller_Keyboard final : public ControllerBase {
15public:
16 Controller_Keyboard();
17
18 // Called when the controller is initialized
19 void OnInit() override;
20
21 // When the controller is released
22 void OnRelease() override;
23
24 // When the controller is requesting an update for the shared memory
25 void OnUpdate(u8* data, std::size_t size) override;
26
27 // Called when input devices should be loaded
28 void OnLoadInputDevices() override;
29
30private:
31 struct KeyboardState {
32 s64_le sampling_number;
33 s64_le sampling_number2;
34
35 s32_le modifier;
36 s32_le attribute;
37 std::array<u8, 32> key;
38 };
39 static_assert(sizeof(KeyboardState) == 0x38, "KeyboardState is an invalid size");
40
41 struct SharedMemory {
42 CommonHeader header;
43 std::array<KeyboardState, 17> pad_states;
44 INSERT_PADDING_BYTES(0x28);
45 };
46 static_assert(sizeof(SharedMemory) == 0x400, "SharedMemory is an invalid size");
47 SharedMemory shared_memory{};
48};
49} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/mouse.cpp b/src/core/hle/service/hid/controllers/mouse.cpp
new file mode 100644
index 000000000..78e9b5e9e
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/mouse.cpp
@@ -0,0 +1,43 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <cstring>
6#include "common/common_types.h"
7#include "common/swap.h"
8#include "core/core_timing.h"
9#include "core/hle/service/hid/controllers/mouse.h"
10
11namespace Service::HID {
12constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3400;
13
14Controller_Mouse::Controller_Mouse() = default;
15
16void Controller_Mouse::OnInit() {}
17
18void Controller_Mouse::OnRelease() {}
19
20void Controller_Mouse::OnUpdate(u8* data, std::size_t size) {
21 shared_memory.header.timestamp = CoreTiming::GetTicks();
22 shared_memory.header.total_entry_count = 17;
23
24 if (!IsControllerActivated()) {
25 shared_memory.header.entry_count = 0;
26 shared_memory.header.last_entry_index = 0;
27 return;
28 }
29 shared_memory.header.entry_count = 16;
30
31 auto& last_entry = shared_memory.mouse_states[shared_memory.header.last_entry_index];
32 shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17;
33 auto& cur_entry = shared_memory.mouse_states[shared_memory.header.last_entry_index];
34
35 cur_entry.sampling_number = last_entry.sampling_number + 1;
36 cur_entry.sampling_number2 = cur_entry.sampling_number;
37 // TODO(ogniK): Update mouse states
38
39 std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory));
40}
41
42void Controller_Mouse::OnLoadInputDevices() {}
43} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/mouse.h b/src/core/hle/service/hid/controllers/mouse.h
new file mode 100644
index 000000000..05358a4f5
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/mouse.h
@@ -0,0 +1,49 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include "common/common_types.h"
9#include "common/swap.h"
10#include "core/hle/service/hid/controllers/controller_base.h"
11
12namespace Service::HID {
13class Controller_Mouse final : public ControllerBase {
14public:
15 Controller_Mouse();
16
17 // Called when the controller is initialized
18 void OnInit() override;
19
20 // When the controller is released
21 void OnRelease() override;
22
23 // When the controller is requesting an update for the shared memory
24 void OnUpdate(u8* data, std::size_t size) override;
25
26 // Called when input devices should be loaded
27 void OnLoadInputDevices() override;
28
29private:
30 struct MouseState {
31 s64_le sampling_number;
32 s64_le sampling_number2;
33 s32_le x;
34 s32_le y;
35 s32_le delta_x;
36 s32_le delta_y;
37 s32_le mouse_wheel;
38 s32_le button;
39 s32_le attribute;
40 };
41 static_assert(sizeof(MouseState) == 0x30, "MouseState is an invalid size");
42
43 struct SharedMemory {
44 CommonHeader header;
45 std::array<MouseState, 17> mouse_states;
46 };
47 SharedMemory shared_memory{};
48};
49} // namespace Service::HID
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..d17e64b2a
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -0,0 +1,429 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <algorithm>
8#include <array>
9#include <cstring>
10#include "common/assert.h"
11#include "common/bit_field.h"
12#include "common/common_types.h"
13#include "common/logging/log.h"
14#include "common/swap.h"
15#include "core/core.h"
16#include "core/core_timing.h"
17#include "core/frontend/input.h"
18#include "core/hle/kernel/event.h"
19#include "core/hle/service/hid/controllers/npad.h"
20#include "core/settings.h"
21
22namespace Service::HID {
23constexpr u32 JOYCON_BODY_NEON_RED = 0xFF3C28;
24constexpr u32 JOYCON_BUTTONS_NEON_RED = 0x1E0A0A;
25constexpr u32 JOYCON_BODY_NEON_BLUE = 0x0AB9E6;
26constexpr u32 JOYCON_BUTTONS_NEON_BLUE = 0x001E1E;
27constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
28constexpr s32 HID_JOYSTICK_MIN = -0x7fff;
29constexpr std::size_t NPAD_OFFSET = 0x9A00;
30constexpr u32 BATTERY_FULL = 2;
31enum class JoystickId : std::size_t { Joystick_Left, Joystick_Right };
32
33Controller_NPad::Controller_NPad() = default;
34
35void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) {
36 const auto controller_type = connected_controllers[controller_idx].type;
37 auto& controller = shared_memory_entries[controller_idx];
38 if (controller_type == NPadControllerType::None) {
39 return;
40 }
41 controller.joy_styles.raw = 0; // Zero out
42 controller.device_type.raw = 0;
43 switch (controller_type) {
44 case NPadControllerType::Handheld:
45 controller.joy_styles.handheld.Assign(1);
46 controller.device_type.handheld.Assign(1);
47 controller.pad_assignment = NPadAssignments::Dual;
48 break;
49 case NPadControllerType::JoyDual:
50 controller.joy_styles.joycon_dual.Assign(1);
51 controller.device_type.joycon_left.Assign(1);
52 controller.device_type.joycon_right.Assign(1);
53 controller.pad_assignment = NPadAssignments::Dual;
54 break;
55 case NPadControllerType::JoyLeft:
56 controller.joy_styles.joycon_left.Assign(1);
57 controller.device_type.joycon_left.Assign(1);
58 controller.pad_assignment = NPadAssignments::Dual;
59 break;
60 case NPadControllerType::JoyRight:
61 controller.joy_styles.joycon_right.Assign(1);
62 controller.device_type.joycon_right.Assign(1);
63 controller.pad_assignment = NPadAssignments::Dual;
64 break;
65 case NPadControllerType::Pokeball:
66 controller.joy_styles.pokeball.Assign(1);
67 controller.device_type.pokeball.Assign(1);
68 controller.pad_assignment = NPadAssignments::Single;
69 break;
70 case NPadControllerType::ProController:
71 controller.joy_styles.pro_controller.Assign(1);
72 controller.device_type.pro_controller.Assign(1);
73 controller.pad_assignment = NPadAssignments::Single;
74 break;
75 }
76
77 controller.single_color_error = ColorReadError::ReadOk;
78 controller.single_color.body_color = 0;
79 controller.single_color.button_color = 0;
80
81 controller.dual_color_error = ColorReadError::ReadOk;
82 controller.left_color.body_color = JOYCON_BODY_NEON_BLUE;
83 controller.left_color.button_color = JOYCON_BUTTONS_NEON_BLUE;
84 controller.right_color.body_color = JOYCON_BODY_NEON_RED;
85 controller.right_color.button_color = JOYCON_BUTTONS_NEON_RED;
86
87 controller.properties.is_vertical.Assign(1); // TODO(ogniK): Swap joycons orientations
88 controller.properties.use_plus.Assign(1);
89 controller.properties.use_minus.Assign(1);
90 controller.battery_level[0] = BATTERY_FULL;
91 controller.battery_level[1] = BATTERY_FULL;
92 controller.battery_level[2] = BATTERY_FULL;
93}
94
95void Controller_NPad::OnInit() {
96 auto& kernel = Core::System::GetInstance().Kernel();
97 styleset_changed_event =
98 Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "npad:NpadStyleSetChanged");
99
100 if (!IsControllerActivated())
101 return;
102 std::size_t controller{};
103 if (style.raw == 0) {
104 // We want to support all controllers
105 style.handheld.Assign(1);
106 style.joycon_left.Assign(1);
107 style.joycon_right.Assign(1);
108 style.joycon_dual.Assign(1);
109 style.pro_controller.Assign(1);
110 style.pokeball.Assign(1);
111 }
112 if (std::none_of(connected_controllers.begin(), connected_controllers.end(),
113 [](const ControllerHolder& controller) { return controller.is_connected; })) {
114 supported_npad_id_types.resize(npad_id_list.size());
115 std::memcpy(supported_npad_id_types.data(), npad_id_list.data(),
116 npad_id_list.size() * sizeof(u32));
117 AddNewController(NPadControllerType::JoyDual);
118 }
119}
120
121void Controller_NPad::OnLoadInputDevices() {
122 std::transform(Settings::values.buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN,
123 Settings::values.buttons.begin() + Settings::NativeButton::BUTTON_HID_END,
124 buttons.begin(), Input::CreateDevice<Input::ButtonDevice>);
125 std::transform(Settings::values.analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN,
126 Settings::values.analogs.begin() + Settings::NativeAnalog::STICK_HID_END,
127 sticks.begin(), Input::CreateDevice<Input::AnalogDevice>);
128}
129
130void Controller_NPad::OnRelease() {}
131
132void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) {
133 if (!IsControllerActivated())
134 return;
135 for (std::size_t i = 0; i < shared_memory_entries.size(); i++) {
136 auto& npad = shared_memory_entries[i];
137 const std::array<NPadGeneric*, 7> controller_npads{&npad.main_controller_states,
138 &npad.handheld_states,
139 &npad.dual_states,
140 &npad.left_joy_states,
141 &npad.right_joy_states,
142 &npad.pokeball_states,
143 &npad.libnx};
144
145 for (auto* main_controller : controller_npads) {
146 main_controller->common.entry_count = 16;
147 main_controller->common.total_entry_count = 17;
148
149 const auto& last_entry =
150 main_controller->npad[main_controller->common.last_entry_index];
151
152 main_controller->common.timestamp = CoreTiming::GetTicks();
153 main_controller->common.last_entry_index =
154 (main_controller->common.last_entry_index + 1) % 17;
155
156 auto& cur_entry = main_controller->npad[main_controller->common.last_entry_index];
157
158 cur_entry.timestamp = last_entry.timestamp + 1;
159 cur_entry.timestamp2 = cur_entry.timestamp;
160 }
161
162 const auto& controller_type = connected_controllers[i].type;
163
164 if (controller_type == NPadControllerType::None || !connected_controllers[i].is_connected) {
165 continue;
166 }
167
168 // Pad states
169 ControllerPadState pad_state{};
170 using namespace Settings::NativeButton;
171 pad_state.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus());
172 pad_state.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus());
173 pad_state.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus());
174 pad_state.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus());
175 pad_state.l_stick.Assign(buttons[LStick - BUTTON_HID_BEGIN]->GetStatus());
176 pad_state.r_stick.Assign(buttons[RStick - BUTTON_HID_BEGIN]->GetStatus());
177 pad_state.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus());
178 pad_state.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus());
179 pad_state.zl.Assign(buttons[ZL - BUTTON_HID_BEGIN]->GetStatus());
180 pad_state.zr.Assign(buttons[ZR - BUTTON_HID_BEGIN]->GetStatus());
181 pad_state.plus.Assign(buttons[Plus - BUTTON_HID_BEGIN]->GetStatus());
182 pad_state.minus.Assign(buttons[Minus - BUTTON_HID_BEGIN]->GetStatus());
183
184 pad_state.d_left.Assign(buttons[DLeft - BUTTON_HID_BEGIN]->GetStatus());
185 pad_state.d_up.Assign(buttons[DUp - BUTTON_HID_BEGIN]->GetStatus());
186 pad_state.d_right.Assign(buttons[DRight - BUTTON_HID_BEGIN]->GetStatus());
187 pad_state.d_down.Assign(buttons[DDown - BUTTON_HID_BEGIN]->GetStatus());
188
189 pad_state.l_stick_left.Assign(buttons[LStick_Left - BUTTON_HID_BEGIN]->GetStatus());
190 pad_state.l_stick_up.Assign(buttons[LStick_Up - BUTTON_HID_BEGIN]->GetStatus());
191 pad_state.l_stick_right.Assign(buttons[LStick_Right - BUTTON_HID_BEGIN]->GetStatus());
192 pad_state.l_stick_down.Assign(buttons[LStick_Down - BUTTON_HID_BEGIN]->GetStatus());
193
194 pad_state.r_stick_left.Assign(buttons[RStick_Left - BUTTON_HID_BEGIN]->GetStatus());
195 pad_state.r_stick_up.Assign(buttons[RStick_Up - BUTTON_HID_BEGIN]->GetStatus());
196 pad_state.r_stick_right.Assign(buttons[RStick_Right - BUTTON_HID_BEGIN]->GetStatus());
197 pad_state.r_stick_down.Assign(buttons[RStick_Down - BUTTON_HID_BEGIN]->GetStatus());
198
199 pad_state.sl.Assign(buttons[SL - BUTTON_HID_BEGIN]->GetStatus());
200 pad_state.sr.Assign(buttons[SR - BUTTON_HID_BEGIN]->GetStatus());
201
202 AnalogPosition lstick_entry{};
203 AnalogPosition rstick_entry{};
204
205 const auto [stick_l_x_f, stick_l_y_f] =
206 sticks[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus();
207 const auto [stick_r_x_f, stick_r_y_f] =
208 sticks[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus();
209 lstick_entry.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX);
210 lstick_entry.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX);
211 rstick_entry.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX);
212 rstick_entry.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX);
213
214 auto& main_controller =
215 npad.main_controller_states.npad[npad.main_controller_states.common.last_entry_index];
216 auto& handheld_entry =
217 npad.handheld_states.npad[npad.handheld_states.common.last_entry_index];
218 auto& dual_entry = npad.dual_states.npad[npad.dual_states.common.last_entry_index];
219 auto& left_entry = npad.left_joy_states.npad[npad.left_joy_states.common.last_entry_index];
220 auto& right_entry =
221 npad.right_joy_states.npad[npad.right_joy_states.common.last_entry_index];
222 auto& pokeball_entry =
223 npad.pokeball_states.npad[npad.pokeball_states.common.last_entry_index];
224 auto& libnx_entry = npad.libnx.npad[npad.libnx.common.last_entry_index];
225
226 if (hold_type == NpadHoldType::Horizontal) {
227 // TODO(ogniK): Remap buttons for different orientations
228 }
229 libnx_entry.connection_status.raw = 0;
230
231 switch (controller_type) {
232 case NPadControllerType::Handheld:
233 handheld_entry.connection_status.raw = 0;
234 handheld_entry.connection_status.IsConnected.Assign(1);
235 if (!Settings::values.use_docked_mode) {
236 handheld_entry.connection_status.IsWired.Assign(1);
237 }
238 handheld_entry.pad_states.raw = pad_state.raw;
239 handheld_entry.l_stick = lstick_entry;
240 handheld_entry.r_stick = rstick_entry;
241 break;
242 case NPadControllerType::JoyDual:
243 dual_entry.connection_status.raw = 0;
244
245 dual_entry.connection_status.IsLeftJoyConnected.Assign(1);
246 dual_entry.connection_status.IsRightJoyConnected.Assign(1);
247 dual_entry.connection_status.IsConnected.Assign(1);
248
249 libnx_entry.connection_status.IsLeftJoyConnected.Assign(1);
250 libnx_entry.connection_status.IsRightJoyConnected.Assign(1);
251 libnx_entry.connection_status.IsConnected.Assign(1);
252
253 dual_entry.pad_states.raw = pad_state.raw;
254 dual_entry.l_stick = lstick_entry;
255 dual_entry.r_stick = rstick_entry;
256 case NPadControllerType::JoyLeft:
257 left_entry.connection_status.raw = 0;
258
259 left_entry.connection_status.IsConnected.Assign(1);
260 left_entry.pad_states.raw = pad_state.raw;
261 left_entry.l_stick = lstick_entry;
262 left_entry.r_stick = rstick_entry;
263 break;
264 case NPadControllerType::JoyRight:
265 right_entry.connection_status.raw = 0;
266
267 right_entry.connection_status.IsConnected.Assign(1);
268 right_entry.pad_states.raw = pad_state.raw;
269 right_entry.l_stick = lstick_entry;
270 right_entry.r_stick = rstick_entry;
271 break;
272 case NPadControllerType::Pokeball:
273 pokeball_entry.connection_status.raw = 0;
274
275 pokeball_entry.connection_status.IsConnected.Assign(1);
276 pokeball_entry.connection_status.IsWired.Assign(1);
277
278 pokeball_entry.pad_states.raw = pad_state.raw;
279 pokeball_entry.l_stick = lstick_entry;
280 pokeball_entry.r_stick = rstick_entry;
281 break;
282 case NPadControllerType::ProController:
283 main_controller.connection_status.raw = 0;
284
285 main_controller.connection_status.IsConnected.Assign(1);
286 main_controller.connection_status.IsWired.Assign(1);
287 main_controller.pad_states.raw = pad_state.raw;
288 main_controller.l_stick = lstick_entry;
289 main_controller.r_stick = rstick_entry;
290 break;
291 }
292
293 // LibNX exclusively uses this section, so we always update it since LibNX doesn't activate
294 // any controllers.
295 libnx_entry.pad_states.raw = pad_state.raw;
296 libnx_entry.l_stick = lstick_entry;
297 libnx_entry.r_stick = rstick_entry;
298 }
299 std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(),
300 shared_memory_entries.size() * sizeof(NPadEntry));
301} // namespace Service::HID
302
303void Controller_NPad::SetSupportedStyleSet(NPadType style_set) {
304 style.raw = style_set.raw;
305}
306
307Controller_NPad::NPadType Controller_NPad::GetSupportedStyleSet() const {
308 return style;
309}
310
311void Controller_NPad::SetSupportedNPadIdTypes(u8* data, std::size_t length) {
312 ASSERT(length > 0 && (length % sizeof(u32)) == 0);
313 supported_npad_id_types.clear();
314 supported_npad_id_types.resize(length / sizeof(u32));
315 std::memcpy(supported_npad_id_types.data(), data, length);
316}
317
318const void Controller_NPad::GetSupportedNpadIdTypes(u32* data, std::size_t max_length) {
319 ASSERT(max_length < supported_npad_id_types.size());
320 std::memcpy(data, supported_npad_id_types.data(), supported_npad_id_types.size());
321}
322
323std::size_t Controller_NPad::GetSupportedNPadIdTypesSize() const {
324 return supported_npad_id_types.size();
325}
326
327void Controller_NPad::SetHoldType(NpadHoldType joy_hold_type) {
328 hold_type = joy_hold_type;
329}
330Controller_NPad::NpadHoldType Controller_NPad::GetHoldType() const {
331 return hold_type;
332}
333
334void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode) {
335 ASSERT(npad_id < shared_memory_entries.size());
336 shared_memory_entries[npad_id].pad_assignment = assignment_mode;
337}
338
339void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
340 const std::vector<Vibration>& vibrations) {
341 if (!can_controllers_vibrate) {
342 return;
343 }
344 for (std::size_t i = 0; i < controller_ids.size(); i++) {
345 std::size_t controller_pos = i;
346 // Handheld controller conversion
347 if (controller_pos == 32) {
348 controller_pos = 8;
349 }
350 // Unknown controller conversion
351 if (controller_pos == 16) {
352 controller_pos = 9;
353 }
354 if (connected_controllers[controller_pos].is_connected) {
355 // TODO(ogniK): Vibrate the physical controller
356 }
357 }
358 LOG_WARNING(Service_HID, "(STUBBED) called");
359 last_processed_vibration = vibrations.back();
360}
361
362Kernel::SharedPtr<Kernel::Event> Controller_NPad::GetStyleSetChangedEvent() const {
363 return styleset_changed_event;
364}
365
366Controller_NPad::Vibration Controller_NPad::GetLastVibration() const {
367 return last_processed_vibration;
368}
369void Controller_NPad::AddNewController(NPadControllerType controller) {
370 if (controller == NPadControllerType::Handheld) {
371 connected_controllers[8] = {controller, true};
372 InitNewlyAddedControler(8);
373 return;
374 }
375 const auto pos =
376 std::find_if(connected_controllers.begin(), connected_controllers.end() - 2,
377 [](const ControllerHolder& holder) { return !holder.is_connected; });
378 if (pos == connected_controllers.end() - 2) {
379 LOG_ERROR(Service_HID, "Cannot connect any more controllers!");
380 return;
381 }
382 const auto controller_id = std::distance(connected_controllers.begin(), pos);
383 connected_controllers[controller_id] = {controller, true};
384 InitNewlyAddedControler(controller_id);
385}
386
387void Controller_NPad::ConnectNPad(u32 npad_id) {
388 if (npad_id >= connected_controllers.size())
389 return;
390 connected_controllers[npad_id].is_connected = true;
391}
392
393void Controller_NPad::DisconnectNPad(u32 npad_id) {
394 if (npad_id >= connected_controllers.size())
395 return;
396 connected_controllers[npad_id].is_connected = false;
397}
398
399Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) {
400 if (npad_id == npad_id_list.back() || npad_id == npad_id_list[npad_id_list.size() - 2]) {
401 // These are controllers without led patterns
402 return LedPattern{0, 0, 0, 0};
403 }
404 switch (npad_id) {
405 case 0:
406 return LedPattern{1, 0, 0, 0};
407 case 1:
408 return LedPattern{0, 1, 0, 0};
409 case 2:
410 return LedPattern{0, 0, 1, 0};
411 case 3:
412 return LedPattern{0, 0, 0, 1};
413 case 4:
414 return LedPattern{1, 0, 0, 1};
415 case 5:
416 return LedPattern{1, 0, 1, 0};
417 case 6:
418 return LedPattern{1, 0, 1, 1};
419 case 7:
420 return LedPattern{0, 1, 1, 0};
421 default:
422 UNIMPLEMENTED_MSG("Unhandled npad_id {}", npad_id);
423 return LedPattern{0, 0, 0, 0};
424 };
425}
426void Controller_NPad::SetVibrationEnabled(bool can_vibrate) {
427 can_controllers_vibrate = can_vibrate;
428}
429} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
new file mode 100644
index 000000000..9d07d258d
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -0,0 +1,288 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include "common/common_types.h"
9#include "core/frontend/input.h"
10#include "core/hle/service/hid/controllers/controller_base.h"
11#include "core/settings.h"
12
13namespace Service::HID {
14
15class Controller_NPad final : public ControllerBase {
16public:
17 Controller_NPad();
18
19 // Called when the controller is initialized
20 void OnInit() override;
21
22 // When the controller is released
23 void OnRelease() override;
24
25 // When the controller is requesting an update for the shared memory
26 void OnUpdate(u8* data, std::size_t size) override;
27
28 // Called when input devices should be loaded
29 void OnLoadInputDevices() override;
30
31 struct NPadType {
32 union {
33 u32_le raw{};
34
35 BitField<0, 1, u32_le> pro_controller;
36 BitField<1, 1, u32_le> handheld;
37 BitField<2, 1, u32_le> joycon_dual;
38 BitField<3, 1, u32_le> joycon_left;
39 BitField<4, 1, u32_le> joycon_right;
40
41 BitField<6, 1, u32_le> pokeball; // TODO(ogniK): Confirm when possible
42 };
43 };
44 static_assert(sizeof(NPadType) == 4, "NPadType is an invalid size");
45
46 struct Vibration {
47 f32 amp_low;
48 f32 freq_low;
49 f32 amp_high;
50 f32 freq_high;
51 };
52 static_assert(sizeof(Vibration) == 0x10, "Vibration is an invalid size");
53
54 enum class NpadHoldType : u64 {
55 Vertical = 0,
56 Horizontal = 1,
57 };
58
59 enum class NPadAssignments : u32_le {
60 Dual = 0,
61 Single = 1,
62 };
63
64 enum class NPadControllerType {
65 None,
66 ProController,
67 Handheld,
68 JoyDual,
69 JoyLeft,
70 JoyRight,
71 Pokeball,
72 };
73
74 struct LedPattern {
75 explicit LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) {
76 position1.Assign(light1);
77 position1.Assign(light2);
78 position1.Assign(light3);
79 position1.Assign(light4);
80 };
81 union {
82 u64 raw{};
83 BitField<0, 1, u64> position1;
84 BitField<1, 1, u64> position2;
85 BitField<2, 1, u64> position3;
86 BitField<3, 1, u64> position4;
87 };
88 };
89
90 void SetSupportedStyleSet(NPadType style_set);
91 NPadType GetSupportedStyleSet() const;
92
93 void SetSupportedNPadIdTypes(u8* data, std::size_t length);
94 const void GetSupportedNpadIdTypes(u32* data, std::size_t max_length);
95 std::size_t GetSupportedNPadIdTypesSize() const;
96
97 void SetHoldType(NpadHoldType joy_hold_type);
98 NpadHoldType GetHoldType() const;
99
100 void SetNpadMode(u32 npad_id, NPadAssignments assignment_mode);
101
102 void VibrateController(const std::vector<u32>& controller_ids,
103 const std::vector<Vibration>& vibrations);
104
105 Kernel::SharedPtr<Kernel::Event> GetStyleSetChangedEvent() const;
106 Vibration GetLastVibration() const;
107
108 void AddNewController(NPadControllerType controller);
109
110 void ConnectNPad(u32 npad_id);
111 void DisconnectNPad(u32 npad_id);
112 LedPattern GetLedPattern(u32 npad_id);
113 void SetVibrationEnabled(bool can_vibrate);
114
115private:
116 struct CommonHeader {
117 s64_le timestamp;
118 s64_le total_entry_count;
119 s64_le last_entry_index;
120 s64_le entry_count;
121 };
122 static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size");
123
124 struct ControllerColor {
125 u32_le body_color;
126 u32_le button_color;
127 };
128 static_assert(sizeof(ControllerColor) == 8, "ControllerColor is an invalid size");
129
130 struct ControllerPadState {
131 union {
132 u64_le raw{};
133 // Button states
134 BitField<0, 1, u64_le> a;
135 BitField<1, 1, u64_le> b;
136 BitField<2, 1, u64_le> x;
137 BitField<3, 1, u64_le> y;
138 BitField<4, 1, u64_le> l_stick;
139 BitField<5, 1, u64_le> r_stick;
140 BitField<6, 1, u64_le> l;
141 BitField<7, 1, u64_le> r;
142 BitField<8, 1, u64_le> zl;
143 BitField<9, 1, u64_le> zr;
144 BitField<10, 1, u64_le> plus;
145 BitField<11, 1, u64_le> minus;
146
147 // D-Pad
148 BitField<12, 1, u64_le> d_left;
149 BitField<13, 1, u64_le> d_up;
150 BitField<14, 1, u64_le> d_right;
151 BitField<15, 1, u64_le> d_down;
152
153 // Left JoyStick
154 BitField<16, 1, u64_le> l_stick_left;
155 BitField<17, 1, u64_le> l_stick_up;
156 BitField<18, 1, u64_le> l_stick_right;
157 BitField<19, 1, u64_le> l_stick_down;
158
159 // Right JoyStick
160 BitField<20, 1, u64_le> r_stick_left;
161 BitField<21, 1, u64_le> r_stick_up;
162 BitField<22, 1, u64_le> r_stick_right;
163 BitField<23, 1, u64_le> r_stick_down;
164
165 // Not always active?
166 BitField<24, 1, u64_le> sl;
167 BitField<25, 1, u64_le> sr;
168 };
169 };
170 static_assert(sizeof(ControllerPadState) == 8, "ControllerPadState is an invalid size");
171
172 struct AnalogPosition {
173 s32_le x;
174 s32_le y;
175 };
176 static_assert(sizeof(AnalogPosition) == 8, "AnalogPosition is an invalid size");
177
178 struct ConnectionState {
179 union {
180 u32_le raw{};
181 BitField<0, 1, u32_le> IsConnected;
182 BitField<1, 1, u32_le> IsWired;
183 BitField<2, 1, u32_le> IsLeftJoyConnected;
184 BitField<3, 1, u32_le> IsLeftJoyWired;
185 BitField<4, 1, u32_le> IsRightJoyConnected;
186 BitField<5, 1, u32_le> IsRightJoyWired;
187 };
188 };
189 static_assert(sizeof(ConnectionState) == 4, "ConnectionState is an invalid size");
190
191 struct GenericStates {
192 s64_le timestamp;
193 s64_le timestamp2;
194 ControllerPadState pad_states;
195 AnalogPosition l_stick;
196 AnalogPosition r_stick;
197 ConnectionState connection_status;
198 };
199 static_assert(sizeof(GenericStates) == 0x30, "NPadGenericStates is an invalid size");
200
201 struct NPadGeneric {
202 CommonHeader common;
203 std::array<GenericStates, 17> npad;
204 };
205 static_assert(sizeof(NPadGeneric) == 0x350, "NPadGeneric is an invalid size");
206
207 enum class ColorReadError : u32_le {
208 ReadOk = 0,
209 ColorDoesntExist = 1,
210 NoController = 2,
211 };
212
213 struct NPadProperties {
214 union {
215 s64_le raw{};
216 BitField<11, 1, s64_le> is_vertical;
217 BitField<12, 1, s64_le> is_horizontal;
218 BitField<13, 1, s64_le> use_plus;
219 BitField<14, 1, s64_le> use_minus;
220 };
221 };
222
223 struct NPadDevice {
224 union {
225 u32_le raw{};
226 BitField<0, 1, s32_le> pro_controller;
227 BitField<1, 1, s32_le> handheld;
228 BitField<2, 1, s32_le> handheld_left;
229 BitField<3, 1, s32_le> handheld_right;
230 BitField<4, 1, s32_le> joycon_left;
231 BitField<5, 1, s32_le> joycon_right;
232 BitField<6, 1, s32_le> pokeball;
233 };
234 };
235
236 struct NPadEntry {
237 NPadType joy_styles;
238 NPadAssignments pad_assignment;
239
240 ColorReadError single_color_error;
241 ControllerColor single_color;
242
243 ColorReadError dual_color_error;
244 ControllerColor left_color;
245 ControllerColor right_color;
246
247 NPadGeneric main_controller_states;
248 NPadGeneric handheld_states;
249 NPadGeneric dual_states;
250 NPadGeneric left_joy_states;
251 NPadGeneric right_joy_states;
252 NPadGeneric pokeball_states;
253 NPadGeneric libnx; // TODO(ogniK): Find out what this actually is, libnx seems to only be
254 // relying on this for the time being
255 INSERT_PADDING_BYTES(
256 0x708 *
257 6); // TODO(ogniK): SixAxis states, require more information before implementation
258 NPadDevice device_type;
259 NPadProperties properties;
260 INSERT_PADDING_WORDS(1);
261 std::array<u32, 3> battery_level;
262 INSERT_PADDING_BYTES(0x5c);
263 INSERT_PADDING_BYTES(0xdf8);
264 };
265 static_assert(sizeof(NPadEntry) == 0x5000, "NPadEntry is an invalid size");
266
267 struct ControllerHolder {
268 Controller_NPad::NPadControllerType type;
269 bool is_connected;
270 };
271
272 NPadType style{};
273 std::array<NPadEntry, 10> shared_memory_entries{};
274 std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID>
275 buttons;
276 std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID> sticks;
277 std::vector<u32> supported_npad_id_types{};
278 NpadHoldType hold_type{NpadHoldType::Vertical};
279 Kernel::SharedPtr<Kernel::Event> styleset_changed_event;
280 std::size_t dump_idx{};
281 Vibration last_processed_vibration{};
282 static constexpr std::array<u32, 10> npad_id_list{0, 1, 2, 3, 4, 5, 6, 7, 32, 16};
283 std::array<ControllerHolder, 10> connected_controllers{};
284 bool can_controllers_vibrate{true};
285
286 void InitNewlyAddedControler(std::size_t controller_idx);
287};
288} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/stubbed.cpp b/src/core/hle/service/hid/controllers/stubbed.cpp
new file mode 100644
index 000000000..3a13d5991
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/stubbed.cpp
@@ -0,0 +1,39 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <cstring>
6#include "common/common_types.h"
7#include "common/swap.h"
8#include "core/core_timing.h"
9#include "core/hle/service/hid/controllers/stubbed.h"
10
11namespace Service::HID {
12
13Controller_Stubbed::Controller_Stubbed() = default;
14
15void Controller_Stubbed::OnInit() {}
16
17void Controller_Stubbed::OnRelease() {}
18
19void Controller_Stubbed::OnUpdate(u8* data, std::size_t size) {
20 if (!smart_update) {
21 return;
22 }
23
24 CommonHeader header{};
25 header.timestamp = CoreTiming::GetTicks();
26 header.total_entry_count = 17;
27 header.entry_count = 0;
28 header.last_entry_index = 0;
29
30 std::memcpy(data + common_offset, &header, sizeof(CommonHeader));
31}
32
33void Controller_Stubbed::OnLoadInputDevices() {}
34
35void Controller_Stubbed::SetCommonHeaderOffset(std::size_t off) {
36 common_offset = off;
37 smart_update = true;
38}
39} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/stubbed.h b/src/core/hle/service/hid/controllers/stubbed.h
new file mode 100644
index 000000000..9c1b57f83
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/stubbed.h
@@ -0,0 +1,33 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8#include "core/hle/service/hid/controllers/controller_base.h"
9
10namespace Service::HID {
11class Controller_Stubbed final : public ControllerBase {
12public:
13 Controller_Stubbed();
14
15 // Called when the controller is initialized
16 void OnInit() override;
17
18 // When the controller is released
19 void OnRelease() override;
20
21 // When the controller is requesting an update for the shared memory
22 void OnUpdate(u8* data, std::size_t size) override;
23
24 // Called when input devices should be loaded
25 void OnLoadInputDevices() override;
26
27 void SetCommonHeaderOffset(std::size_t off);
28
29private:
30 bool smart_update{};
31 std::size_t common_offset{};
32};
33} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp
new file mode 100644
index 000000000..e97f84ea1
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/touchscreen.cpp
@@ -0,0 +1,65 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <cstring>
6#include "common/common_types.h"
7#include "common/swap.h"
8#include "core/core_timing.h"
9#include "core/frontend/emu_window.h"
10#include "core/frontend/input.h"
11#include "core/hle/service/hid/controllers/touchscreen.h"
12#include "core/settings.h"
13
14namespace Service::HID {
15constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400;
16
17Controller_Touchscreen::Controller_Touchscreen() = default;
18
19void Controller_Touchscreen::OnInit() {}
20
21void Controller_Touchscreen::OnRelease() {}
22
23void Controller_Touchscreen::OnUpdate(u8* data, std::size_t size) {
24 shared_memory.header.timestamp = CoreTiming::GetTicks();
25 shared_memory.header.total_entry_count = 17;
26
27 if (!IsControllerActivated()) {
28 shared_memory.header.entry_count = 0;
29 shared_memory.header.last_entry_index = 0;
30 return;
31 }
32 shared_memory.header.entry_count = 16;
33
34 const auto& last_entry =
35 shared_memory.shared_memory_entries[shared_memory.header.last_entry_index];
36 shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17;
37 auto& cur_entry = shared_memory.shared_memory_entries[shared_memory.header.last_entry_index];
38
39 cur_entry.sampling_number = last_entry.sampling_number + 1;
40 cur_entry.sampling_number2 = cur_entry.sampling_number;
41
42 const auto [x, y, pressed] = touch_device->GetStatus();
43 auto& touch_entry = cur_entry.states[0];
44 if (pressed) {
45 touch_entry.x = static_cast<u16>(x * Layout::ScreenUndocked::Width);
46 touch_entry.y = static_cast<u16>(y * Layout::ScreenUndocked::Height);
47 touch_entry.diameter_x = 15;
48 touch_entry.diameter_y = 15;
49 touch_entry.rotation_angle = 0;
50 const u64 tick = CoreTiming::GetTicks();
51 touch_entry.delta_time = tick - last_touch;
52 last_touch = tick;
53 touch_entry.finger = 0;
54 cur_entry.entry_count = 1;
55 } else {
56 cur_entry.entry_count = 0;
57 }
58
59 std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(TouchScreenSharedMemory));
60}
61
62void Controller_Touchscreen::OnLoadInputDevices() {
63 touch_device = Input::CreateDevice<Input::TouchDevice>(Settings::values.touch_device);
64}
65} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h
new file mode 100644
index 000000000..1d97b6c2a
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/touchscreen.h
@@ -0,0 +1,62 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_funcs.h"
8#include "common/common_types.h"
9#include "common/swap.h"
10#include "core/frontend/input.h"
11#include "core/hle/service/hid/controllers/controller_base.h"
12
13namespace Service::HID {
14class Controller_Touchscreen final : public ControllerBase {
15public:
16 Controller_Touchscreen();
17
18 // Called when the controller is initialized
19 void OnInit() override;
20
21 // When the controller is released
22 void OnRelease() override;
23
24 // When the controller is requesting an update for the shared memory
25 void OnUpdate(u8* data, std::size_t size) override;
26
27 // Called when input devices should be loaded
28 void OnLoadInputDevices() override;
29
30private:
31 struct TouchState {
32 u64_le delta_time;
33 u32_le attribute;
34 u32_le finger;
35 u32_le x;
36 u32_le y;
37 u32_le diameter_x;
38 u32_le diameter_y;
39 u32_le rotation_angle;
40 };
41 static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size");
42
43 struct TouchScreenEntry {
44 s64_le sampling_number;
45 s64_le sampling_number2;
46 s32_le entry_count;
47 std::array<TouchState, 16> states;
48 };
49 static_assert(sizeof(TouchScreenEntry) == 0x298, "TouchScreenEntry is an invalid size");
50
51 struct TouchScreenSharedMemory {
52 CommonHeader header;
53 std::array<TouchScreenEntry, 17> shared_memory_entries{};
54 INSERT_PADDING_BYTES(0x3c8);
55 };
56 static_assert(sizeof(TouchScreenSharedMemory) == 0x3000,
57 "TouchScreenSharedMemory is an invalid size");
58 TouchScreenSharedMemory shared_memory{};
59 std::unique_ptr<Input::TouchDevice> touch_device;
60 s64_le last_touch{};
61};
62} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/xpad.cpp b/src/core/hle/service/hid/controllers/xpad.cpp
new file mode 100644
index 000000000..df0b48451
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/xpad.cpp
@@ -0,0 +1,45 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <cstring>
6#include "common/common_types.h"
7#include "common/swap.h"
8#include "core/core_timing.h"
9#include "core/hle/service/hid/controllers/xpad.h"
10
11namespace Service::HID {
12constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C00;
13
14Controller_XPad::Controller_XPad() = default;
15
16void Controller_XPad::OnInit() {}
17
18void Controller_XPad::OnRelease() {}
19
20void Controller_XPad::OnUpdate(u8* data, std::size_t size) {
21 for (auto& xpad_entry : shared_memory.shared_memory_entries) {
22 xpad_entry.header.timestamp = CoreTiming::GetTicks();
23 xpad_entry.header.total_entry_count = 17;
24
25 if (!IsControllerActivated()) {
26 xpad_entry.header.entry_count = 0;
27 xpad_entry.header.last_entry_index = 0;
28 return;
29 }
30 xpad_entry.header.entry_count = 16;
31
32 const auto& last_entry = xpad_entry.pad_states[xpad_entry.header.last_entry_index];
33 xpad_entry.header.last_entry_index = (xpad_entry.header.last_entry_index + 1) % 17;
34 auto& cur_entry = xpad_entry.pad_states[xpad_entry.header.last_entry_index];
35
36 cur_entry.sampling_number = last_entry.sampling_number + 1;
37 cur_entry.sampling_number2 = cur_entry.sampling_number;
38 }
39 // TODO(ogniK): Update xpad states
40
41 std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory));
42}
43
44void Controller_XPad::OnLoadInputDevices() {}
45} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/xpad.h b/src/core/hle/service/hid/controllers/xpad.h
new file mode 100644
index 000000000..e2007183d
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/xpad.h
@@ -0,0 +1,60 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_funcs.h"
8#include "common/common_types.h"
9#include "common/swap.h"
10#include "core/frontend/input.h"
11#include "core/hle/service/hid/controllers/controller_base.h"
12
13namespace Service::HID {
14class Controller_XPad final : public ControllerBase {
15public:
16 Controller_XPad();
17
18 // Called when the controller is initialized
19 void OnInit() override;
20
21 // When the controller is released
22 void OnRelease() override;
23
24 // When the controller is requesting an update for the shared memory
25 void OnUpdate(u8* data, std::size_t size) override;
26
27 // Called when input devices should be loaded
28 void OnLoadInputDevices() override;
29
30private:
31 struct AnalogStick {
32 s32_le x;
33 s32_le y;
34 };
35 static_assert(sizeof(AnalogStick) == 0x8, "AnalogStick is an invalid size");
36
37 struct XPadState {
38 s64_le sampling_number;
39 s64_le sampling_number2;
40 s32_le attributes;
41 u32_le pad_states;
42 AnalogStick x_stick;
43 AnalogStick y_stick;
44 };
45 static_assert(sizeof(XPadState) == 0x28, "XPadState is an invalid size");
46
47 struct XPadEntry {
48 CommonHeader header;
49 std::array<XPadState, 17> pad_states{};
50 INSERT_PADDING_BYTES(0x138);
51 };
52 static_assert(sizeof(XPadEntry) == 0x400, "XPadEntry is an invalid size");
53
54 struct SharedMemory {
55 std::array<XPadEntry, 4> shared_memory_entries{};
56 };
57 static_assert(sizeof(SharedMemory) == 0x1000, "SharedMemory is an invalid size");
58 SharedMemory shared_memory{};
59};
60} // namespace Service::HID
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 7c6b0a4e6..8aca0f197 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -2,6 +2,8 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <array>
6#include "common/common_types.h"
5#include "common/logging/log.h" 7#include "common/logging/log.h"
6#include "core/core.h" 8#include "core/core.h"
7#include "core/core_timing.h" 9#include "core/core_timing.h"
@@ -19,6 +21,16 @@
19#include "core/hle/service/service.h" 21#include "core/hle/service/service.h"
20#include "core/settings.h" 22#include "core/settings.h"
21 23
24#include "core/hle/service/hid/controllers/controller_base.h"
25#include "core/hle/service/hid/controllers/debug_pad.h"
26#include "core/hle/service/hid/controllers/gesture.h"
27#include "core/hle/service/hid/controllers/keyboard.h"
28#include "core/hle/service/hid/controllers/mouse.h"
29#include "core/hle/service/hid/controllers/npad.h"
30#include "core/hle/service/hid/controllers/stubbed.h"
31#include "core/hle/service/hid/controllers/touchscreen.h"
32#include "core/hle/service/hid/controllers/xpad.h"
33
22namespace Service::HID { 34namespace Service::HID {
23 35
24// Updating period for each HID device. 36// Updating period for each HID device.
@@ -26,6 +38,22 @@ namespace Service::HID {
26constexpr u64 pad_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100; 38constexpr u64 pad_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100;
27constexpr u64 accelerometer_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100; 39constexpr u64 accelerometer_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100;
28constexpr u64 gyroscope_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100; 40constexpr u64 gyroscope_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100;
41constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000;
42enum class HidController : std::size_t {
43 DebugPad,
44 Touchscreen,
45 Mouse,
46 Keyboard,
47 XPad,
48 Unknown1,
49 Unknown2,
50 Unknown3,
51 SixAxisSensor,
52 NPad,
53 Gesture,
54
55 MaxControllers,
56};
29 57
30class IAppletResource final : public ServiceFramework<IAppletResource> { 58class IAppletResource final : public ServiceFramework<IAppletResource> {
31public: 59public:
@@ -37,19 +65,57 @@ public:
37 65
38 auto& kernel = Core::System::GetInstance().Kernel(); 66 auto& kernel = Core::System::GetInstance().Kernel();
39 shared_mem = Kernel::SharedMemory::Create( 67 shared_mem = Kernel::SharedMemory::Create(
40 kernel, nullptr, 0x40000, Kernel::MemoryPermission::ReadWrite, 68 kernel, nullptr, SHARED_MEMORY_SIZE, Kernel::MemoryPermission::ReadWrite,
41 Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "HID:SharedMemory"); 69 Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "HID:SharedMemory");
42 70
71 MakeController<Controller_DebugPad>(HidController::DebugPad);
72 MakeController<Controller_Touchscreen>(HidController::Touchscreen);
73 MakeController<Controller_Mouse>(HidController::Mouse);
74 MakeController<Controller_Keyboard>(HidController::Keyboard);
75 MakeController<Controller_XPad>(HidController::XPad);
76 MakeController<Controller_Stubbed>(HidController::Unknown1);
77 MakeController<Controller_Stubbed>(HidController::Unknown2);
78 MakeController<Controller_Stubbed>(HidController::Unknown3);
79 MakeController<Controller_Stubbed>(HidController::SixAxisSensor);
80 MakeController<Controller_NPad>(HidController::NPad);
81 MakeController<Controller_Gesture>(HidController::Gesture);
82
83 // Homebrew doesn't try to activate some controllers, so we activate them by default
84 GetController<Controller_NPad>(HidController::NPad).ActivateController();
85 GetController<Controller_Touchscreen>(HidController::Touchscreen).ActivateController();
86
87 GetController<Controller_Stubbed>(HidController::Unknown1).SetCommonHeaderOffset(0x4c00);
88 GetController<Controller_Stubbed>(HidController::Unknown2).SetCommonHeaderOffset(0x4e00);
89 GetController<Controller_Stubbed>(HidController::Unknown3).SetCommonHeaderOffset(0x5000);
90
43 // Register update callbacks 91 // Register update callbacks
44 pad_update_event = CoreTiming::RegisterEvent( 92 pad_update_event = CoreTiming::RegisterEvent(
45 "HID::UpdatePadCallback", 93 "HID::UpdatePadCallback",
46 [this](u64 userdata, int cycles_late) { UpdatePadCallback(userdata, cycles_late); }); 94 [this](u64 userdata, int cycles_late) { UpdateControllers(userdata, cycles_late); });
47 95
48 // TODO(shinyquagsire23): Other update callbacks? (accel, gyro?) 96 // TODO(shinyquagsire23): Other update callbacks? (accel, gyro?)
49 97
50 CoreTiming::ScheduleEvent(pad_update_ticks, pad_update_event); 98 CoreTiming::ScheduleEvent(pad_update_ticks, pad_update_event);
51 } 99 }
52 100
101 void ActivateController(HidController controller) {
102 controllers[static_cast<size_t>(controller)]->ActivateController();
103 }
104
105 void DeactivateController(HidController controller) {
106 controllers[static_cast<size_t>(controller)]->DeactivateController();
107 }
108
109 template <typename T>
110 void MakeController(HidController controller) {
111 controllers[static_cast<std::size_t>(controller)] = std::make_unique<T>();
112 }
113
114 template <typename T>
115 T& GetController(HidController controller) {
116 return static_cast<T&>(*controllers[static_cast<size_t>(controller)]);
117 }
118
53 ~IAppletResource() { 119 ~IAppletResource() {
54 CoreTiming::UnscheduleEvent(pad_update_event, 0); 120 CoreTiming::UnscheduleEvent(pad_update_event, 0);
55 } 121 }
@@ -62,200 +128,15 @@ private:
62 LOG_DEBUG(Service_HID, "called"); 128 LOG_DEBUG(Service_HID, "called");
63 } 129 }
64 130
65 void LoadInputDevices() { 131 void UpdateControllers(u64 userdata, int cycles_late) {
66 std::transform(Settings::values.buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN, 132 const bool should_reload = Settings::values.is_device_reload_pending.exchange(false);
67 Settings::values.buttons.begin() + Settings::NativeButton::BUTTON_HID_END, 133 for (const auto& controller : controllers) {
68 buttons.begin(), Input::CreateDevice<Input::ButtonDevice>); 134 if (should_reload) {
69 std::transform(Settings::values.analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN, 135 controller->OnLoadInputDevices();
70 Settings::values.analogs.begin() + Settings::NativeAnalog::STICK_HID_END,
71 sticks.begin(), Input::CreateDevice<Input::AnalogDevice>);
72 touch_device = Input::CreateDevice<Input::TouchDevice>(Settings::values.touch_device);
73 // TODO(shinyquagsire23): gyro, mouse, keyboard
74 }
75
76 void UpdatePadCallback(u64 userdata, int cycles_late) {
77 SharedMemory mem{};
78 std::memcpy(&mem, shared_mem->GetPointer(), sizeof(SharedMemory));
79
80 if (Settings::values.is_device_reload_pending.exchange(false))
81 LoadInputDevices();
82
83 // Set up controllers as neon red+blue Joy-Con attached to console
84 ControllerHeader& controller_header = mem.controllers[Controller_Handheld].header;
85 controller_header.type = ControllerType_Handheld;
86 controller_header.single_colors_descriptor = ColorDesc_ColorsNonexistent;
87 controller_header.right_color_body = JOYCON_BODY_NEON_RED;
88 controller_header.right_color_buttons = JOYCON_BUTTONS_NEON_RED;
89 controller_header.left_color_body = JOYCON_BODY_NEON_BLUE;
90 controller_header.left_color_buttons = JOYCON_BUTTONS_NEON_BLUE;
91
92 for (std::size_t controller = 0; controller < mem.controllers.size(); controller++) {
93 for (auto& layout : mem.controllers[controller].layouts) {
94 layout.header.num_entries = HID_NUM_ENTRIES;
95 layout.header.max_entry_index = HID_NUM_ENTRIES - 1;
96
97 // HID shared memory stores the state of the past 17 samples in a circlular buffer,
98 // each with a timestamp in number of samples since boot.
99 const ControllerInputEntry& last_entry = layout.entries[layout.header.latest_entry];
100
101 layout.header.timestamp_ticks = CoreTiming::GetTicks();
102 layout.header.latest_entry = (layout.header.latest_entry + 1) % HID_NUM_ENTRIES;
103
104 ControllerInputEntry& entry = layout.entries[layout.header.latest_entry];
105 entry.timestamp = last_entry.timestamp + 1;
106 // TODO(shinyquagsire23): Is this always identical to timestamp?
107 entry.timestamp_2 = entry.timestamp;
108
109 // TODO(shinyquagsire23): More than just handheld input
110 if (controller != Controller_Handheld)
111 continue;
112
113 entry.connection_state = ConnectionState_Connected | ConnectionState_Wired;
114
115 // TODO(shinyquagsire23): Set up some LUTs for each layout mapping in the future?
116 // For now everything is just the default handheld layout, but split Joy-Con will
117 // rotate the face buttons and directions for certain layouts.
118 ControllerPadState& state = entry.buttons;
119 using namespace Settings::NativeButton;
120 state.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus());
121 state.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus());
122 state.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus());
123 state.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus());
124 state.lstick.Assign(buttons[LStick - BUTTON_HID_BEGIN]->GetStatus());
125 state.rstick.Assign(buttons[RStick - BUTTON_HID_BEGIN]->GetStatus());
126 state.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus());
127 state.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus());
128 state.zl.Assign(buttons[ZL - BUTTON_HID_BEGIN]->GetStatus());
129 state.zr.Assign(buttons[ZR - BUTTON_HID_BEGIN]->GetStatus());
130 state.plus.Assign(buttons[Plus - BUTTON_HID_BEGIN]->GetStatus());
131 state.minus.Assign(buttons[Minus - BUTTON_HID_BEGIN]->GetStatus());
132
133 state.dleft.Assign(buttons[DLeft - BUTTON_HID_BEGIN]->GetStatus());
134 state.dup.Assign(buttons[DUp - BUTTON_HID_BEGIN]->GetStatus());
135 state.dright.Assign(buttons[DRight - BUTTON_HID_BEGIN]->GetStatus());
136 state.ddown.Assign(buttons[DDown - BUTTON_HID_BEGIN]->GetStatus());
137
138 state.lstick_left.Assign(buttons[LStick_Left - BUTTON_HID_BEGIN]->GetStatus());
139 state.lstick_up.Assign(buttons[LStick_Up - BUTTON_HID_BEGIN]->GetStatus());
140 state.lstick_right.Assign(buttons[LStick_Right - BUTTON_HID_BEGIN]->GetStatus());
141 state.lstick_down.Assign(buttons[LStick_Down - BUTTON_HID_BEGIN]->GetStatus());
142
143 state.rstick_left.Assign(buttons[RStick_Left - BUTTON_HID_BEGIN]->GetStatus());
144 state.rstick_up.Assign(buttons[RStick_Up - BUTTON_HID_BEGIN]->GetStatus());
145 state.rstick_right.Assign(buttons[RStick_Right - BUTTON_HID_BEGIN]->GetStatus());
146 state.rstick_down.Assign(buttons[RStick_Down - BUTTON_HID_BEGIN]->GetStatus());
147
148 state.sl.Assign(buttons[SL - BUTTON_HID_BEGIN]->GetStatus());
149 state.sr.Assign(buttons[SR - BUTTON_HID_BEGIN]->GetStatus());
150
151 const auto [stick_l_x_f, stick_l_y_f] = sticks[Joystick_Left]->GetStatus();
152 const auto [stick_r_x_f, stick_r_y_f] = sticks[Joystick_Right]->GetStatus();
153 entry.joystick_left_x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX);
154 entry.joystick_left_y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX);
155 entry.joystick_right_x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX);
156 entry.joystick_right_y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX);
157 } 136 }
137 controller->OnUpdate(shared_mem->GetPointer(), SHARED_MEMORY_SIZE);
158 } 138 }
159 139
160 TouchScreen& touchscreen = mem.touchscreen;
161 const u64 last_entry = touchscreen.header.latest_entry;
162 const u64 curr_entry = (last_entry + 1) % touchscreen.entries.size();
163 const u64 timestamp = CoreTiming::GetTicks();
164 const u64 sample_counter = touchscreen.entries[last_entry].header.timestamp + 1;
165 touchscreen.header.timestamp_ticks = timestamp;
166 touchscreen.header.num_entries = touchscreen.entries.size();
167 touchscreen.header.latest_entry = curr_entry;
168 touchscreen.header.max_entry_index = touchscreen.entries.size();
169 touchscreen.header.timestamp = timestamp;
170 touchscreen.entries[curr_entry].header.timestamp = sample_counter;
171
172 TouchScreenEntryTouch touch_entry{};
173 auto [x, y, pressed] = touch_device->GetStatus();
174 touch_entry.timestamp = timestamp;
175 touch_entry.x = static_cast<u16>(x * Layout::ScreenUndocked::Width);
176 touch_entry.y = static_cast<u16>(y * Layout::ScreenUndocked::Height);
177 touch_entry.touch_index = 0;
178
179 // TODO(DarkLordZach): Maybe try to derive these from EmuWindow?
180 touch_entry.diameter_x = 15;
181 touch_entry.diameter_y = 15;
182 touch_entry.angle = 0;
183
184 // TODO(DarkLordZach): Implement multi-touch support
185 if (pressed) {
186 touchscreen.entries[curr_entry].header.num_touches = 1;
187 touchscreen.entries[curr_entry].touches[0] = touch_entry;
188 } else {
189 touchscreen.entries[curr_entry].header.num_touches = 0;
190 }
191
192 // TODO(shinyquagsire23): Properly implement mouse
193 Mouse& mouse = mem.mouse;
194 const u64 last_mouse_entry = mouse.header.latest_entry;
195 const u64 curr_mouse_entry = (mouse.header.latest_entry + 1) % mouse.entries.size();
196 const u64 mouse_sample_counter = mouse.entries[last_mouse_entry].timestamp + 1;
197 mouse.header.timestamp_ticks = timestamp;
198 mouse.header.num_entries = mouse.entries.size();
199 mouse.header.max_entry_index = mouse.entries.size();
200 mouse.header.latest_entry = curr_mouse_entry;
201
202 mouse.entries[curr_mouse_entry].timestamp = mouse_sample_counter;
203 mouse.entries[curr_mouse_entry].timestamp_2 = mouse_sample_counter;
204
205 // TODO(shinyquagsire23): Properly implement keyboard
206 Keyboard& keyboard = mem.keyboard;
207 const u64 last_keyboard_entry = keyboard.header.latest_entry;
208 const u64 curr_keyboard_entry =
209 (keyboard.header.latest_entry + 1) % keyboard.entries.size();
210 const u64 keyboard_sample_counter = keyboard.entries[last_keyboard_entry].timestamp + 1;
211 keyboard.header.timestamp_ticks = timestamp;
212 keyboard.header.num_entries = keyboard.entries.size();
213 keyboard.header.latest_entry = last_keyboard_entry;
214 keyboard.header.max_entry_index = keyboard.entries.size();
215
216 keyboard.entries[curr_keyboard_entry].timestamp = keyboard_sample_counter;
217 keyboard.entries[curr_keyboard_entry].timestamp_2 = keyboard_sample_counter;
218
219 // TODO(shinyquagsire23): Figure out what any of these are
220 for (auto& input : mem.unk_input_1) {
221 const u64 last_input_entry = input.header.latest_entry;
222 const u64 curr_input_entry = (input.header.latest_entry + 1) % input.entries.size();
223 const u64 input_sample_counter = input.entries[last_input_entry].timestamp + 1;
224
225 input.header.timestamp_ticks = timestamp;
226 input.header.num_entries = input.entries.size();
227 input.header.latest_entry = last_input_entry;
228 input.header.max_entry_index = input.entries.size();
229
230 input.entries[curr_input_entry].timestamp = input_sample_counter;
231 input.entries[curr_input_entry].timestamp_2 = input_sample_counter;
232 }
233
234 for (auto& input : mem.unk_input_2) {
235 input.header.timestamp_ticks = timestamp;
236 input.header.num_entries = 17;
237 input.header.latest_entry = 0;
238 input.header.max_entry_index = 0;
239 }
240
241 UnkInput3& input = mem.unk_input_3;
242 const u64 last_input_entry = input.header.latest_entry;
243 const u64 curr_input_entry = (input.header.latest_entry + 1) % input.entries.size();
244 const u64 input_sample_counter = input.entries[last_input_entry].timestamp + 1;
245
246 input.header.timestamp_ticks = timestamp;
247 input.header.num_entries = input.entries.size();
248 input.header.latest_entry = last_input_entry;
249 input.header.max_entry_index = input.entries.size();
250
251 input.entries[curr_input_entry].timestamp = input_sample_counter;
252 input.entries[curr_input_entry].timestamp_2 = input_sample_counter;
253
254 // TODO(shinyquagsire23): Signal events
255
256 std::memcpy(shared_mem->GetPointer(), &mem, sizeof(SharedMemory));
257
258 // Reschedule recurrent event
259 CoreTiming::ScheduleEvent(pad_update_ticks - cycles_late, pad_update_event); 140 CoreTiming::ScheduleEvent(pad_update_ticks - cycles_late, pad_update_event);
260 } 141 }
261 142
@@ -265,11 +146,8 @@ private:
265 // CoreTiming update events 146 // CoreTiming update events
266 CoreTiming::EventType* pad_update_event; 147 CoreTiming::EventType* pad_update_event;
267 148
268 // Stored input state info 149 std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)>
269 std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID> 150 controllers{};
270 buttons;
271 std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID> sticks;
272 std::unique_ptr<Input::TouchDevice> touch_device;
273}; 151};
274 152
275class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> { 153class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> {
@@ -301,7 +179,7 @@ public:
301 {31, &Hid::ActivateKeyboard, "ActivateKeyboard"}, 179 {31, &Hid::ActivateKeyboard, "ActivateKeyboard"},
302 {40, nullptr, "AcquireXpadIdEventHandle"}, 180 {40, nullptr, "AcquireXpadIdEventHandle"},
303 {41, nullptr, "ReleaseXpadIdEventHandle"}, 181 {41, nullptr, "ReleaseXpadIdEventHandle"},
304 {51, nullptr, "ActivateXpad"}, 182 {51, &Hid::ActivateXpad, "ActivateXpad"},
305 {55, nullptr, "GetXpadIds"}, 183 {55, nullptr, "GetXpadIds"},
306 {56, nullptr, "ActivateJoyXpad"}, 184 {56, nullptr, "ActivateJoyXpad"},
307 {58, nullptr, "GetJoyXpadLifoHandle"}, 185 {58, nullptr, "GetJoyXpadLifoHandle"},
@@ -362,8 +240,8 @@ public:
362 {206, &Hid::SendVibrationValues, "SendVibrationValues"}, 240 {206, &Hid::SendVibrationValues, "SendVibrationValues"},
363 {207, nullptr, "SendVibrationGcErmCommand"}, 241 {207, nullptr, "SendVibrationGcErmCommand"},
364 {208, nullptr, "GetActualVibrationGcErmCommand"}, 242 {208, nullptr, "GetActualVibrationGcErmCommand"},
365 {209, nullptr, "BeginPermitVibrationSession"}, 243 {209, &Hid::BeginPermitVibrationSession, "BeginPermitVibrationSession"},
366 {210, nullptr, "EndPermitVibrationSession"}, 244 {210, &Hid::EndPermitVibrationSession, "EndPermitVibrationSession"},
367 {300, &Hid::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"}, 245 {300, &Hid::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"},
368 {301, &Hid::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"}, 246 {301, &Hid::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"},
369 {302, nullptr, "StopConsoleSixAxisSensor"}, 247 {302, nullptr, "StopConsoleSixAxisSensor"},
@@ -401,16 +279,11 @@ public:
401 // clang-format on 279 // clang-format on
402 280
403 RegisterHandlers(functions); 281 RegisterHandlers(functions);
404
405 auto& kernel = Core::System::GetInstance().Kernel();
406 event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "hid:EventHandle");
407 } 282 }
408 ~Hid() = default; 283 ~Hid() = default;
409 284
410private: 285private:
411 std::shared_ptr<IAppletResource> applet_resource; 286 std::shared_ptr<IAppletResource> applet_resource;
412 u32 joy_hold_type{0};
413 Kernel::SharedPtr<Kernel::Event> event;
414 287
415 void CreateAppletResource(Kernel::HLERequestContext& ctx) { 288 void CreateAppletResource(Kernel::HLERequestContext& ctx) {
416 if (applet_resource == nullptr) { 289 if (applet_resource == nullptr) {
@@ -423,31 +296,59 @@ private:
423 LOG_DEBUG(Service_HID, "called"); 296 LOG_DEBUG(Service_HID, "called");
424 } 297 }
425 298
299 void ActivateXpad(Kernel::HLERequestContext& ctx) {
300 applet_resource->ActivateController(HidController::XPad);
301 IPC::ResponseBuilder rb{ctx, 2};
302 rb.Push(RESULT_SUCCESS);
303 LOG_DEBUG(Service_HID, "called");
304 }
305
426 void ActivateDebugPad(Kernel::HLERequestContext& ctx) { 306 void ActivateDebugPad(Kernel::HLERequestContext& ctx) {
307 applet_resource->ActivateController(HidController::DebugPad);
427 IPC::ResponseBuilder rb{ctx, 2}; 308 IPC::ResponseBuilder rb{ctx, 2};
428 rb.Push(RESULT_SUCCESS); 309 rb.Push(RESULT_SUCCESS);
429 LOG_WARNING(Service_HID, "(STUBBED) called"); 310 LOG_DEBUG(Service_HID, "called");
430 } 311 }
431 312
432 void ActivateTouchScreen(Kernel::HLERequestContext& ctx) { 313 void ActivateTouchScreen(Kernel::HLERequestContext& ctx) {
314 applet_resource->ActivateController(HidController::Touchscreen);
433 IPC::ResponseBuilder rb{ctx, 2}; 315 IPC::ResponseBuilder rb{ctx, 2};
434 rb.Push(RESULT_SUCCESS); 316 rb.Push(RESULT_SUCCESS);
435 LOG_WARNING(Service_HID, "(STUBBED) called"); 317 LOG_DEBUG(Service_HID, "called");
436 } 318 }
437 319
438 void ActivateMouse(Kernel::HLERequestContext& ctx) { 320 void ActivateMouse(Kernel::HLERequestContext& ctx) {
321 applet_resource->ActivateController(HidController::Mouse);
439 IPC::ResponseBuilder rb{ctx, 2}; 322 IPC::ResponseBuilder rb{ctx, 2};
440 rb.Push(RESULT_SUCCESS); 323 rb.Push(RESULT_SUCCESS);
441 LOG_WARNING(Service_HID, "(STUBBED) called"); 324 LOG_DEBUG(Service_HID, "called");
442 } 325 }
443 326
444 void ActivateKeyboard(Kernel::HLERequestContext& ctx) { 327 void ActivateKeyboard(Kernel::HLERequestContext& ctx) {
328 applet_resource->ActivateController(HidController::Keyboard);
445 IPC::ResponseBuilder rb{ctx, 2}; 329 IPC::ResponseBuilder rb{ctx, 2};
446 rb.Push(RESULT_SUCCESS); 330 rb.Push(RESULT_SUCCESS);
447 LOG_WARNING(Service_HID, "(STUBBED) called"); 331 LOG_DEBUG(Service_HID, "called");
332 }
333
334 void ActivateGesture(Kernel::HLERequestContext& ctx) {
335 applet_resource->ActivateController(HidController::Gesture);
336 IPC::ResponseBuilder rb{ctx, 2};
337 rb.Push(RESULT_SUCCESS);
338 LOG_DEBUG(Service_HID, "called");
339 }
340
341 void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) {
342 // Should have no effect with how our npad sets up the data
343 applet_resource->ActivateController(HidController::NPad);
344 IPC::ResponseBuilder rb{ctx, 2};
345 rb.Push(RESULT_SUCCESS);
346 LOG_DEBUG(Service_HID, "called");
448 } 347 }
449 348
450 void StartSixAxisSensor(Kernel::HLERequestContext& ctx) { 349 void StartSixAxisSensor(Kernel::HLERequestContext& ctx) {
350 IPC::RequestParser rp{ctx};
351 auto handle = rp.PopRaw<u32>();
451 IPC::ResponseBuilder rb{ctx, 2}; 352 IPC::ResponseBuilder rb{ctx, 2};
452 rb.Push(RESULT_SUCCESS); 353 rb.Push(RESULT_SUCCESS);
453 LOG_WARNING(Service_HID, "(STUBBED) called"); 354 LOG_WARNING(Service_HID, "(STUBBED) called");
@@ -468,84 +369,168 @@ private:
468 } 369 }
469 370
470 void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { 371 void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
372 IPC::RequestParser rp{ctx};
373 auto supported_styleset = rp.PopRaw<u32>();
374 applet_resource->GetController<Controller_NPad>(HidController::NPad)
375 .SetSupportedStyleSet({supported_styleset});
376
471 IPC::ResponseBuilder rb{ctx, 2}; 377 IPC::ResponseBuilder rb{ctx, 2};
472 rb.Push(RESULT_SUCCESS); 378 rb.Push(RESULT_SUCCESS);
473 LOG_WARNING(Service_HID, "(STUBBED) called"); 379
380 LOG_DEBUG(Service_HID, "called");
474 } 381 }
475 382
476 void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { 383 void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
384 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
385
477 IPC::ResponseBuilder rb{ctx, 3}; 386 IPC::ResponseBuilder rb{ctx, 3};
478 rb.Push(RESULT_SUCCESS); 387 rb.Push(RESULT_SUCCESS);
479 rb.Push<u32>(0); 388 rb.Push<u32>(controller.GetSupportedStyleSet().raw);
480 LOG_WARNING(Service_HID, "(STUBBED) called"); 389 LOG_DEBUG(Service_HID, "called");
481 } 390 }
482 391
483 void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) { 392 void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) {
393 applet_resource->GetController<Controller_NPad>(HidController::NPad)
394 .SetSupportedNPadIdTypes(ctx.ReadBuffer().data(), ctx.GetReadBufferSize());
484 IPC::ResponseBuilder rb{ctx, 2}; 395 IPC::ResponseBuilder rb{ctx, 2};
485 rb.Push(RESULT_SUCCESS); 396 rb.Push(RESULT_SUCCESS);
486 LOG_WARNING(Service_HID, "(STUBBED) called"); 397 LOG_DEBUG(Service_HID, "called");
487 } 398 }
488 399
489 void ActivateNpad(Kernel::HLERequestContext& ctx) { 400 void ActivateNpad(Kernel::HLERequestContext& ctx) {
490 IPC::ResponseBuilder rb{ctx, 2}; 401 IPC::ResponseBuilder rb{ctx, 2};
491 rb.Push(RESULT_SUCCESS); 402 rb.Push(RESULT_SUCCESS);
492 LOG_WARNING(Service_HID, "(STUBBED) called"); 403 applet_resource->ActivateController(HidController::NPad);
404 LOG_DEBUG(Service_HID, "called");
493 } 405 }
494 406
495 void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { 407 void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) {
408 IPC::RequestParser rp{ctx};
409 auto npad_id = rp.PopRaw<u32>();
496 IPC::ResponseBuilder rb{ctx, 2, 1}; 410 IPC::ResponseBuilder rb{ctx, 2, 1};
497 rb.Push(RESULT_SUCCESS); 411 rb.Push(RESULT_SUCCESS);
498 rb.PushCopyObjects(event); 412 rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad)
499 LOG_WARNING(Service_HID, "(STUBBED) called"); 413 .GetStyleSetChangedEvent());
414 LOG_DEBUG(Service_HID, "called");
500 } 415 }
501 416
502 void DisconnectNpad(Kernel::HLERequestContext& ctx) { 417 void DisconnectNpad(Kernel::HLERequestContext& ctx) {
418 IPC::RequestParser rp{ctx};
419 auto npad_id = rp.PopRaw<u32>();
420 applet_resource->GetController<Controller_NPad>(HidController::NPad)
421 .DisconnectNPad(npad_id);
503 IPC::ResponseBuilder rb{ctx, 2}; 422 IPC::ResponseBuilder rb{ctx, 2};
504 rb.Push(RESULT_SUCCESS); 423 rb.Push(RESULT_SUCCESS);
505 LOG_WARNING(Service_HID, "(STUBBED) called"); 424 LOG_DEBUG(Service_HID, "called");
506 } 425 }
507 426
508 void GetPlayerLedPattern(Kernel::HLERequestContext& ctx) { 427 void GetPlayerLedPattern(Kernel::HLERequestContext& ctx) {
509 IPC::ResponseBuilder rb{ctx, 2}; 428 IPC::RequestParser rp{ctx};
429 auto npad_id = rp.PopRaw<u32>();
430 IPC::ResponseBuilder rb{ctx, 4};
510 rb.Push(RESULT_SUCCESS); 431 rb.Push(RESULT_SUCCESS);
511 LOG_WARNING(Service_HID, "(STUBBED) called"); 432 rb.PushRaw<u64>(applet_resource->GetController<Controller_NPad>(HidController::NPad)
433 .GetLedPattern(npad_id)
434 .raw);
435 LOG_DEBUG(Service_HID, "called");
512 } 436 }
513 437
514 void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { 438 void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
439 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
440 IPC::RequestParser rp{ctx};
441 const auto hold_type = rp.PopRaw<u64>();
442 controller.SetHoldType(Controller_NPad::NpadHoldType{hold_type});
443
515 IPC::ResponseBuilder rb{ctx, 2}; 444 IPC::ResponseBuilder rb{ctx, 2};
516 rb.Push(RESULT_SUCCESS); 445 rb.Push(RESULT_SUCCESS);
517 LOG_WARNING(Service_HID, "(STUBBED) called"); 446 LOG_DEBUG(Service_HID, "called");
518 } 447 }
519 448
520 void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { 449 void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
521 IPC::ResponseBuilder rb{ctx, 3}; 450 const auto& controller =
451 applet_resource->GetController<Controller_NPad>(HidController::NPad);
452 IPC::ResponseBuilder rb{ctx, 4};
522 rb.Push(RESULT_SUCCESS); 453 rb.Push(RESULT_SUCCESS);
523 rb.Push(joy_hold_type); 454 rb.Push<u64>(static_cast<u64>(controller.GetHoldType()));
524 LOG_WARNING(Service_HID, "(STUBBED) called"); 455 LOG_DEBUG(Service_HID, "called");
525 } 456 }
526 457
527 void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) { 458 void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) {
459 IPC::RequestParser rp{ctx};
460 auto npad_id = rp.PopRaw<u32>();
528 IPC::ResponseBuilder rb{ctx, 2}; 461 IPC::ResponseBuilder rb{ctx, 2};
529 rb.Push(RESULT_SUCCESS); 462 rb.Push(RESULT_SUCCESS);
530 LOG_WARNING(Service_HID, "(STUBBED) called"); 463 LOG_WARNING(Service_HID, "(STUBBED) called");
531 } 464 }
532 465
466 void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) {
467 applet_resource->GetController<Controller_NPad>(HidController::NPad)
468 .SetVibrationEnabled(true);
469 IPC::ResponseBuilder rb{ctx, 2};
470 rb.Push(RESULT_SUCCESS);
471 LOG_DEBUG(Service_HID, "called");
472 }
473
474 void EndPermitVibrationSession(Kernel::HLERequestContext& ctx) {
475 applet_resource->GetController<Controller_NPad>(HidController::NPad)
476 .SetVibrationEnabled(false);
477 IPC::ResponseBuilder rb{ctx, 2};
478 rb.Push(RESULT_SUCCESS);
479 LOG_DEBUG(Service_HID, "called");
480 }
481
533 void SendVibrationValue(Kernel::HLERequestContext& ctx) { 482 void SendVibrationValue(Kernel::HLERequestContext& ctx) {
483 IPC::RequestParser rp{ctx};
484 const auto controller_id = rp.PopRaw<u32>();
485 const auto vibration_values = rp.PopRaw<Controller_NPad::Vibration>();
486
534 IPC::ResponseBuilder rb{ctx, 2}; 487 IPC::ResponseBuilder rb{ctx, 2};
535 rb.Push(RESULT_SUCCESS); 488 rb.Push(RESULT_SUCCESS);
536 LOG_WARNING(Service_HID, "(STUBBED) called"); 489
490 applet_resource->GetController<Controller_NPad>(HidController::NPad)
491 .VibrateController({controller_id}, {vibration_values});
492 LOG_DEBUG(Service_HID, "called");
537 } 493 }
538 494
539 void GetActualVibrationValue(Kernel::HLERequestContext& ctx) { 495 void SendVibrationValues(Kernel::HLERequestContext& ctx) {
496 const auto controllers = ctx.ReadBuffer(0);
497 const auto vibrations = ctx.ReadBuffer(1);
498
499 std::vector<u32> controller_list(controllers.size() / sizeof(u32));
500 std::vector<Controller_NPad::Vibration> vibration_list(vibrations.size() /
501 sizeof(Controller_NPad::Vibration));
502
503 std::memcpy(controller_list.data(), controllers.data(), controllers.size());
504 std::memcpy(vibration_list.data(), vibrations.data(), vibrations.size());
505 std::transform(controller_list.begin(), controller_list.end(), controller_list.begin(),
506 [](u32 controller_id) { return controller_id - 3; });
507
508 applet_resource->GetController<Controller_NPad>(HidController::NPad)
509 .VibrateController(controller_list, vibration_list);
510
540 IPC::ResponseBuilder rb{ctx, 2}; 511 IPC::ResponseBuilder rb{ctx, 2};
541 rb.Push(RESULT_SUCCESS); 512 rb.Push(RESULT_SUCCESS);
542 LOG_WARNING(Service_HID, "(STUBBED) called"); 513 LOG_DEBUG(Service_HID, "called");
514 }
515
516 void GetActualVibrationValue(Kernel::HLERequestContext& ctx) {
517 IPC::ResponseBuilder rb{ctx, 6};
518 rb.Push(RESULT_SUCCESS);
519 rb.PushRaw<Controller_NPad::Vibration>(
520 applet_resource->GetController<Controller_NPad>(HidController::NPad)
521 .GetLastVibration());
522 LOG_DEBUG(Service_HID, "called");
543 } 523 }
544 524
545 void SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { 525 void SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) {
526 IPC::RequestParser rp{ctx};
527 const auto npad_id = rp.PopRaw<u32>();
528 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
529 controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Dual);
530
546 IPC::ResponseBuilder rb{ctx, 2}; 531 IPC::ResponseBuilder rb{ctx, 2};
547 rb.Push(RESULT_SUCCESS); 532 rb.Push(RESULT_SUCCESS);
548 LOG_WARNING(Service_HID, "(STUBBED) called"); 533 LOG_DEBUG(Service_HID, "called");
549 } 534 }
550 535
551 void MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) { 536 void MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) {
@@ -555,6 +540,8 @@ private:
555 } 540 }
556 541
557 void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { 542 void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) {
543 IPC::RequestParser rp{ctx};
544 auto mode = rp.PopRaw<u32>();
558 IPC::ResponseBuilder rb{ctx, 2}; 545 IPC::ResponseBuilder rb{ctx, 2};
559 rb.Push(RESULT_SUCCESS); 546 rb.Push(RESULT_SUCCESS);
560 LOG_WARNING(Service_HID, "(STUBBED) called"); 547 LOG_WARNING(Service_HID, "(STUBBED) called");
@@ -563,8 +550,9 @@ private:
563 void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { 550 void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {
564 IPC::ResponseBuilder rb{ctx, 4}; 551 IPC::ResponseBuilder rb{ctx, 4};
565 rb.Push(RESULT_SUCCESS); 552 rb.Push(RESULT_SUCCESS);
566 rb.Push<u64>(0); 553 rb.Push<u32>(1);
567 LOG_WARNING(Service_HID, "(STUBBED) called"); 554 rb.Push<u32>(0);
555 LOG_DEBUG(Service_HID, "called");
568 } 556 }
569 557
570 void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) { 558 void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) {
@@ -574,12 +562,6 @@ private:
574 LOG_DEBUG(Service_HID, "called"); 562 LOG_DEBUG(Service_HID, "called");
575 } 563 }
576 564
577 void SendVibrationValues(Kernel::HLERequestContext& ctx) {
578 IPC::ResponseBuilder rb{ctx, 2};
579 rb.Push(RESULT_SUCCESS);
580 LOG_WARNING(Service_HID, "(STUBBED) called");
581 }
582
583 void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { 565 void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
584 IPC::ResponseBuilder rb{ctx, 2}; 566 IPC::ResponseBuilder rb{ctx, 2};
585 rb.Push(RESULT_SUCCESS); 567 rb.Push(RESULT_SUCCESS);
@@ -597,18 +579,6 @@ private:
597 rb.Push(RESULT_SUCCESS); 579 rb.Push(RESULT_SUCCESS);
598 LOG_WARNING(Service_HID, "(STUBBED) called"); 580 LOG_WARNING(Service_HID, "(STUBBED) called");
599 } 581 }
600
601 void ActivateGesture(Kernel::HLERequestContext& ctx) {
602 IPC::ResponseBuilder rb{ctx, 2};
603 rb.Push(RESULT_SUCCESS);
604 LOG_WARNING(Service_HID, "(STUBBED) called");
605 }
606
607 void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) {
608 IPC::ResponseBuilder rb{ctx, 2};
609 rb.Push(RESULT_SUCCESS);
610 LOG_WARNING(Service_HID, "(STUBBED) called");
611 }
612}; 582};
613 583
614class HidDbg final : public ServiceFramework<HidDbg> { 584class HidDbg final : public ServiceFramework<HidDbg> {
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index 88d926808..773035460 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -4,408 +4,12 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array> 7namespace SM {
8#include "common/bit_field.h" 8class ServiceManager;
9#include "common/common_types.h" 9}
10#include "core/hle/service/service.h"
11 10
12namespace Service::HID { 11namespace Service::HID {
13 12
14// Begin enums and output structs
15
16constexpr u32 HID_NUM_ENTRIES = 17;
17constexpr u32 HID_NUM_LAYOUTS = 7;
18constexpr s32 HID_JOYSTICK_MAX = 0x8000;
19constexpr s32 HID_JOYSTICK_MIN = -0x8000;
20
21constexpr u32 JOYCON_BODY_NEON_RED = 0xFF3C28;
22constexpr u32 JOYCON_BUTTONS_NEON_RED = 0x1E0A0A;
23constexpr u32 JOYCON_BODY_NEON_BLUE = 0x0AB9E6;
24constexpr u32 JOYCON_BUTTONS_NEON_BLUE = 0x001E1E;
25
26enum ControllerType : u32 {
27 ControllerType_ProController = 1 << 0,
28 ControllerType_Handheld = 1 << 1,
29 ControllerType_JoyconPair = 1 << 2,
30 ControllerType_JoyconLeft = 1 << 3,
31 ControllerType_JoyconRight = 1 << 4,
32};
33
34enum ControllerLayoutType : u32 {
35 Layout_ProController = 0, // Pro Controller or HID gamepad
36 Layout_Handheld = 1, // Two Joy-Con docked to rails
37 Layout_Single = 2, // Horizontal single Joy-Con or pair of Joy-Con, adjusted for orientation
38 Layout_Left = 3, // Only raw left Joy-Con state, no orientation adjustment
39 Layout_Right = 4, // Only raw right Joy-Con state, no orientation adjustment
40 Layout_DefaultDigital = 5, // Same as next, but sticks have 8-direction values only
41 Layout_Default = 6, // Safe default, single Joy-Con have buttons/sticks rotated for orientation
42};
43
44enum ControllerColorDescription {
45 ColorDesc_ColorsNonexistent = 1 << 1,
46};
47
48enum ControllerConnectionState {
49 ConnectionState_Connected = 1 << 0,
50 ConnectionState_Wired = 1 << 1,
51};
52
53enum ControllerJoystick {
54 Joystick_Left = 0,
55 Joystick_Right = 1,
56};
57
58enum ControllerID {
59 Controller_Player1 = 0,
60 Controller_Player2 = 1,
61 Controller_Player3 = 2,
62 Controller_Player4 = 3,
63 Controller_Player5 = 4,
64 Controller_Player6 = 5,
65 Controller_Player7 = 6,
66 Controller_Player8 = 7,
67 Controller_Handheld = 8,
68 Controller_Unknown = 9,
69};
70
71// End enums and output structs
72
73// Begin UnkInput3
74
75struct UnkInput3Header {
76 u64 timestamp_ticks;
77 u64 num_entries;
78 u64 latest_entry;
79 u64 max_entry_index;
80};
81static_assert(sizeof(UnkInput3Header) == 0x20, "HID UnkInput3 header structure has incorrect size");
82
83struct UnkInput3Entry {
84 u64 timestamp;
85 u64 timestamp_2;
86 u64 unk_8;
87 u64 unk_10;
88 u64 unk_18;
89};
90static_assert(sizeof(UnkInput3Entry) == 0x28, "HID UnkInput3 entry structure has incorrect size");
91
92struct UnkInput3 {
93 UnkInput3Header header;
94 std::array<UnkInput3Entry, 17> entries;
95 std::array<u8, 0x138> padding;
96};
97static_assert(sizeof(UnkInput3) == 0x400, "HID UnkInput3 structure has incorrect size");
98
99// End UnkInput3
100
101// Begin TouchScreen
102
103struct TouchScreenHeader {
104 u64 timestamp_ticks;
105 u64 num_entries;
106 u64 latest_entry;
107 u64 max_entry_index;
108 u64 timestamp;
109};
110static_assert(sizeof(TouchScreenHeader) == 0x28,
111 "HID touch screen header structure has incorrect size");
112
113struct TouchScreenEntryHeader {
114 u64 timestamp;
115 u64 num_touches;
116};
117static_assert(sizeof(TouchScreenEntryHeader) == 0x10,
118 "HID touch screen entry header structure has incorrect size");
119
120struct TouchScreenEntryTouch {
121 u64 timestamp;
122 u32 padding;
123 u32 touch_index;
124 u32 x;
125 u32 y;
126 u32 diameter_x;
127 u32 diameter_y;
128 u32 angle;
129 u32 padding_2;
130};
131static_assert(sizeof(TouchScreenEntryTouch) == 0x28,
132 "HID touch screen touch structure has incorrect size");
133
134struct TouchScreenEntry {
135 TouchScreenEntryHeader header;
136 std::array<TouchScreenEntryTouch, 16> touches;
137 u64 unk;
138};
139static_assert(sizeof(TouchScreenEntry) == 0x298,
140 "HID touch screen entry structure has incorrect size");
141
142struct TouchScreen {
143 TouchScreenHeader header;
144 std::array<TouchScreenEntry, 17> entries;
145 std::array<u8, 0x3c0> padding;
146};
147static_assert(sizeof(TouchScreen) == 0x3000, "HID touch screen structure has incorrect size");
148
149// End TouchScreen
150
151// Begin Mouse
152
153struct MouseHeader {
154 u64 timestamp_ticks;
155 u64 num_entries;
156 u64 latest_entry;
157 u64 max_entry_index;
158};
159static_assert(sizeof(MouseHeader) == 0x20, "HID mouse header structure has incorrect size");
160
161struct MouseButtonState {
162 union {
163 u64 hex{};
164
165 // Buttons
166 BitField<0, 1, u64> left;
167 BitField<1, 1, u64> right;
168 BitField<2, 1, u64> middle;
169 BitField<3, 1, u64> forward;
170 BitField<4, 1, u64> back;
171 };
172};
173
174struct MouseEntry {
175 u64 timestamp;
176 u64 timestamp_2;
177 u32 x;
178 u32 y;
179 u32 velocity_x;
180 u32 velocity_y;
181 u32 scroll_velocity_x;
182 u32 scroll_velocity_y;
183 MouseButtonState buttons;
184};
185static_assert(sizeof(MouseEntry) == 0x30, "HID mouse entry structure has incorrect size");
186
187struct Mouse {
188 MouseHeader header;
189 std::array<MouseEntry, 17> entries;
190 std::array<u8, 0xB0> padding;
191};
192static_assert(sizeof(Mouse) == 0x400, "HID mouse structure has incorrect size");
193
194// End Mouse
195
196// Begin Keyboard
197
198struct KeyboardHeader {
199 u64 timestamp_ticks;
200 u64 num_entries;
201 u64 latest_entry;
202 u64 max_entry_index;
203};
204static_assert(sizeof(KeyboardHeader) == 0x20, "HID keyboard header structure has incorrect size");
205
206struct KeyboardModifierKeyState {
207 union {
208 u64 hex{};
209
210 // Buttons
211 BitField<0, 1, u64> lctrl;
212 BitField<1, 1, u64> lshift;
213 BitField<2, 1, u64> lalt;
214 BitField<3, 1, u64> lmeta;
215 BitField<4, 1, u64> rctrl;
216 BitField<5, 1, u64> rshift;
217 BitField<6, 1, u64> ralt;
218 BitField<7, 1, u64> rmeta;
219 BitField<8, 1, u64> capslock;
220 BitField<9, 1, u64> scrolllock;
221 BitField<10, 1, u64> numlock;
222 };
223};
224
225struct KeyboardEntry {
226 u64 timestamp;
227 u64 timestamp_2;
228 KeyboardModifierKeyState modifier;
229 u32 keys[8];
230};
231static_assert(sizeof(KeyboardEntry) == 0x38, "HID keyboard entry structure has incorrect size");
232
233struct Keyboard {
234 KeyboardHeader header;
235 std::array<KeyboardEntry, 17> entries;
236 std::array<u8, 0x28> padding;
237};
238static_assert(sizeof(Keyboard) == 0x400, "HID keyboard structure has incorrect size");
239
240// End Keyboard
241
242// Begin UnkInput1
243
244struct UnkInput1Header {
245 u64 timestamp_ticks;
246 u64 num_entries;
247 u64 latest_entry;
248 u64 max_entry_index;
249};
250static_assert(sizeof(UnkInput1Header) == 0x20, "HID UnkInput1 header structure has incorrect size");
251
252struct UnkInput1Entry {
253 u64 timestamp;
254 u64 timestamp_2;
255 u64 unk_8;
256 u64 unk_10;
257 u64 unk_18;
258};
259static_assert(sizeof(UnkInput1Entry) == 0x28, "HID UnkInput1 entry structure has incorrect size");
260
261struct UnkInput1 {
262 UnkInput1Header header;
263 std::array<UnkInput1Entry, 17> entries;
264 std::array<u8, 0x138> padding;
265};
266static_assert(sizeof(UnkInput1) == 0x400, "HID UnkInput1 structure has incorrect size");
267
268// End UnkInput1
269
270// Begin UnkInput2
271
272struct UnkInput2Header {
273 u64 timestamp_ticks;
274 u64 num_entries;
275 u64 latest_entry;
276 u64 max_entry_index;
277};
278static_assert(sizeof(UnkInput2Header) == 0x20, "HID UnkInput2 header structure has incorrect size");
279
280struct UnkInput2 {
281 UnkInput2Header header;
282 std::array<u8, 0x1E0> padding;
283};
284static_assert(sizeof(UnkInput2) == 0x200, "HID UnkInput2 structure has incorrect size");
285
286// End UnkInput2
287
288// Begin Controller
289
290struct ControllerMAC {
291 u64 timestamp;
292 std::array<u8, 0x8> mac;
293 u64 unk;
294 u64 timestamp_2;
295};
296static_assert(sizeof(ControllerMAC) == 0x20, "HID controller MAC structure has incorrect size");
297
298struct ControllerHeader {
299 u32 type;
300 u32 is_half;
301 u32 single_colors_descriptor;
302 u32 single_color_body;
303 u32 single_color_buttons;
304 u32 split_colors_descriptor;
305 u32 left_color_body;
306 u32 left_color_buttons;
307 u32 right_color_body;
308 u32 right_color_buttons;
309};
310static_assert(sizeof(ControllerHeader) == 0x28,
311 "HID controller header structure has incorrect size");
312
313struct ControllerLayoutHeader {
314 u64 timestamp_ticks;
315 u64 num_entries;
316 u64 latest_entry;
317 u64 max_entry_index;
318};
319static_assert(sizeof(ControllerLayoutHeader) == 0x20,
320 "HID controller layout header structure has incorrect size");
321
322struct ControllerPadState {
323 union {
324 u64 hex{};
325
326 // Buttons
327 BitField<0, 1, u64> a;
328 BitField<1, 1, u64> b;
329 BitField<2, 1, u64> x;
330 BitField<3, 1, u64> y;
331 BitField<4, 1, u64> lstick;
332 BitField<5, 1, u64> rstick;
333 BitField<6, 1, u64> l;
334 BitField<7, 1, u64> r;
335 BitField<8, 1, u64> zl;
336 BitField<9, 1, u64> zr;
337 BitField<10, 1, u64> plus;
338 BitField<11, 1, u64> minus;
339
340 // D-pad buttons
341 BitField<12, 1, u64> dleft;
342 BitField<13, 1, u64> dup;
343 BitField<14, 1, u64> dright;
344 BitField<15, 1, u64> ddown;
345
346 // Left stick directions
347 BitField<16, 1, u64> lstick_left;
348 BitField<17, 1, u64> lstick_up;
349 BitField<18, 1, u64> lstick_right;
350 BitField<19, 1, u64> lstick_down;
351
352 // Right stick directions
353 BitField<20, 1, u64> rstick_left;
354 BitField<21, 1, u64> rstick_up;
355 BitField<22, 1, u64> rstick_right;
356 BitField<23, 1, u64> rstick_down;
357
358 BitField<24, 1, u64> sl;
359 BitField<25, 1, u64> sr;
360 };
361};
362
363struct ControllerInputEntry {
364 u64 timestamp;
365 u64 timestamp_2;
366 ControllerPadState buttons;
367 s32 joystick_left_x;
368 s32 joystick_left_y;
369 s32 joystick_right_x;
370 s32 joystick_right_y;
371 u64 connection_state;
372};
373static_assert(sizeof(ControllerInputEntry) == 0x30,
374 "HID controller input entry structure has incorrect size");
375
376struct ControllerLayout {
377 ControllerLayoutHeader header;
378 std::array<ControllerInputEntry, 17> entries;
379};
380static_assert(sizeof(ControllerLayout) == 0x350,
381 "HID controller layout structure has incorrect size");
382
383struct Controller {
384 ControllerHeader header;
385 std::array<ControllerLayout, HID_NUM_LAYOUTS> layouts;
386 std::array<u8, 0x2a70> unk_1;
387 ControllerMAC mac_left;
388 ControllerMAC mac_right;
389 std::array<u8, 0xdf8> unk_2;
390};
391static_assert(sizeof(Controller) == 0x5000, "HID controller structure has incorrect size");
392
393// End Controller
394
395struct SharedMemory {
396 UnkInput3 unk_input_3;
397 TouchScreen touchscreen;
398 Mouse mouse;
399 Keyboard keyboard;
400 std::array<UnkInput1, 4> unk_input_1;
401 std::array<UnkInput2, 3> unk_input_2;
402 std::array<u8, 0x800> unk_section_8;
403 std::array<u8, 0x4000> controller_serials;
404 std::array<Controller, 10> controllers;
405 std::array<u8, 0x4600> unk_section_9;
406};
407static_assert(sizeof(SharedMemory) == 0x40000, "HID Shared Memory structure has incorrect size");
408
409/// Reload input devices. Used when input configuration changed 13/// Reload input devices. Used when input configuration changed
410void ReloadInputDevices(); 14void ReloadInputDevices();
411 15
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp
index 8c07a05c2..39c0c1e63 100644
--- a/src/core/hle/service/nfp/nfp.cpp
+++ b/src/core/hle/service/nfp/nfp.cpp
@@ -144,7 +144,7 @@ private:
144 } 144 }
145 145
146 const u64 device_handle{0xDEAD}; 146 const u64 device_handle{0xDEAD};
147 const HID::ControllerID npad_id{HID::Controller_Player1}; 147 const u32 npad_id{0}; // This is the first player controller id
148 State state{State::NonInitialized}; 148 State state{State::NonInitialized};
149 DeviceState device_state{DeviceState::Initialized}; 149 DeviceState device_state{DeviceState::Initialized};
150 Kernel::SharedPtr<Kernel::Event> activate_event; 150 Kernel::SharedPtr<Kernel::Event> activate_event;