summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/hid/hid_types.h72
-rw-r--r--src/core/hle/service/hid/controllers/console_sixaxis.cpp20
-rw-r--r--src/core/hle/service/hid/controllers/console_sixaxis.h11
-rw-r--r--src/core/hle/service/hid/controllers/controller_base.h7
-rw-r--r--src/core/hle/service/hid/controllers/debug_pad.cpp19
-rw-r--r--src/core/hle/service/hid/controllers/debug_pad.h29
-rw-r--r--src/core/hle/service/hid/controllers/gesture.cpp32
-rw-r--r--src/core/hle/service/hid/controllers/gesture.h45
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.cpp19
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.h27
-rw-r--r--src/core/hle/service/hid/controllers/mouse.cpp20
-rw-r--r--src/core/hle/service/hid/controllers/mouse.h21
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp290
-rw-r--r--src/core/hle/service/hid/controllers/npad.h32
-rw-r--r--src/core/hle/service/hid/controllers/stubbed.cpp11
-rw-r--r--src/core/hle/service/hid/controllers/stubbed.h13
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.cpp22
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.h28
-rw-r--r--src/core/hle/service/hid/controllers/xpad.cpp21
-rw-r--r--src/core/hle/service/hid/controllers/xpad.h26
-rw-r--r--src/core/hle/service/hid/hid.cpp41
-rw-r--r--src/core/hle/service/hid/hid.h9
-rw-r--r--src/yuzu/configuration/configure_ui.cpp73
23 files changed, 496 insertions, 392 deletions
diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h
index df2b1dfc5..26ec1091b 100644
--- a/src/core/hid/hid_types.h
+++ b/src/core/hid/hid_types.h
@@ -316,27 +316,27 @@ static_assert(sizeof(TouchAttribute) == 0x4, "TouchAttribute is an invalid size"
316 316
317// This is nn::hid::TouchState 317// This is nn::hid::TouchState
318struct TouchState { 318struct TouchState {
319 u64 delta_time; 319 u64 delta_time{};
320 TouchAttribute attribute; 320 TouchAttribute attribute{};
321 u32 finger; 321 u32 finger{};
322 Common::Point<u32> position; 322 Common::Point<u32> position{};
323 u32 diameter_x; 323 u32 diameter_x{};
324 u32 diameter_y; 324 u32 diameter_y{};
325 u32 rotation_angle; 325 u32 rotation_angle{};
326}; 326};
327static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size"); 327static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size");
328 328
329// This is nn::hid::NpadControllerColor 329// This is nn::hid::NpadControllerColor
330struct NpadControllerColor { 330struct NpadControllerColor {
331 u32 body; 331 u32 body{};
332 u32 button; 332 u32 button{};
333}; 333};
334static_assert(sizeof(NpadControllerColor) == 8, "NpadControllerColor is an invalid size"); 334static_assert(sizeof(NpadControllerColor) == 8, "NpadControllerColor is an invalid size");
335 335
336// This is nn::hid::AnalogStickState 336// This is nn::hid::AnalogStickState
337struct AnalogStickState { 337struct AnalogStickState {
338 s32 x; 338 s32 x{};
339 s32 y; 339 s32 y{};
340}; 340};
341static_assert(sizeof(AnalogStickState) == 8, "AnalogStickState is an invalid size"); 341static_assert(sizeof(AnalogStickState) == 8, "AnalogStickState is an invalid size");
342 342
@@ -354,10 +354,10 @@ static_assert(sizeof(NpadBatteryLevel) == 0x4, "NpadBatteryLevel is an invalid s
354 354
355// This is nn::hid::system::NpadPowerInfo 355// This is nn::hid::system::NpadPowerInfo
356struct NpadPowerInfo { 356struct NpadPowerInfo {
357 bool is_powered; 357 bool is_powered{};
358 bool is_charging; 358 bool is_charging{};
359 INSERT_PADDING_BYTES(0x6); 359 INSERT_PADDING_BYTES(0x6);
360 NpadBatteryLevel battery_level; 360 NpadBatteryLevel battery_level{8};
361}; 361};
362static_assert(sizeof(NpadPowerInfo) == 0xC, "NpadPowerInfo is an invalid size"); 362static_assert(sizeof(NpadPowerInfo) == 0xC, "NpadPowerInfo is an invalid size");
363 363
@@ -474,8 +474,8 @@ static_assert(sizeof(DebugPadButton) == 0x4, "DebugPadButton is an invalid size"
474 474
475// This is nn::hid::ConsoleSixAxisSensorHandle 475// This is nn::hid::ConsoleSixAxisSensorHandle
476struct ConsoleSixAxisSensorHandle { 476struct ConsoleSixAxisSensorHandle {
477 u8 unknown_1; 477 u8 unknown_1{};
478 u8 unknown_2; 478 u8 unknown_2{};
479 INSERT_PADDING_BYTES_NOINIT(2); 479 INSERT_PADDING_BYTES_NOINIT(2);
480}; 480};
481static_assert(sizeof(ConsoleSixAxisSensorHandle) == 4, 481static_assert(sizeof(ConsoleSixAxisSensorHandle) == 4,
@@ -483,9 +483,9 @@ static_assert(sizeof(ConsoleSixAxisSensorHandle) == 4,
483 483
484// This is nn::hid::SixAxisSensorHandle 484// This is nn::hid::SixAxisSensorHandle
485struct SixAxisSensorHandle { 485struct SixAxisSensorHandle {
486 NpadStyleIndex npad_type; 486 NpadStyleIndex npad_type{NpadStyleIndex::None};
487 u8 npad_id; 487 u8 npad_id{};
488 DeviceIndex device_index; 488 DeviceIndex device_index{DeviceIndex::None};
489 INSERT_PADDING_BYTES_NOINIT(1); 489 INSERT_PADDING_BYTES_NOINIT(1);
490}; 490};
491static_assert(sizeof(SixAxisSensorHandle) == 4, "SixAxisSensorHandle is an invalid size"); 491static_assert(sizeof(SixAxisSensorHandle) == 4, "SixAxisSensorHandle is an invalid size");
@@ -500,19 +500,19 @@ static_assert(sizeof(SixAxisSensorFusionParameters) == 8,
500 500
501// This is nn::hid::VibrationDeviceHandle 501// This is nn::hid::VibrationDeviceHandle
502struct VibrationDeviceHandle { 502struct VibrationDeviceHandle {
503 NpadStyleIndex npad_type; 503 NpadStyleIndex npad_type{NpadStyleIndex::None};
504 u8 npad_id; 504 u8 npad_id{};
505 DeviceIndex device_index; 505 DeviceIndex device_index{DeviceIndex::None};
506 INSERT_PADDING_BYTES_NOINIT(1); 506 INSERT_PADDING_BYTES_NOINIT(1);
507}; 507};
508static_assert(sizeof(VibrationDeviceHandle) == 4, "SixAxisSensorHandle is an invalid size"); 508static_assert(sizeof(VibrationDeviceHandle) == 4, "SixAxisSensorHandle is an invalid size");
509 509
510// This is nn::hid::VibrationValue 510// This is nn::hid::VibrationValue
511struct VibrationValue { 511struct VibrationValue {
512 f32 low_amplitude; 512 f32 low_amplitude{};
513 f32 low_frequency; 513 f32 low_frequency{};
514 f32 high_amplitude; 514 f32 high_amplitude{};
515 f32 high_frequency; 515 f32 high_frequency{};
516}; 516};
517static_assert(sizeof(VibrationValue) == 0x10, "VibrationValue has incorrect size."); 517static_assert(sizeof(VibrationValue) == 0x10, "VibrationValue has incorrect size.");
518 518
@@ -561,7 +561,7 @@ static_assert(sizeof(KeyboardAttribute) == 0x4, "KeyboardAttribute is an invalid
561// This is nn::hid::KeyboardKey 561// This is nn::hid::KeyboardKey
562struct KeyboardKey { 562struct KeyboardKey {
563 // This should be a 256 bit flag 563 // This should be a 256 bit flag
564 std::array<u8, 32> key; 564 std::array<u8, 32> key{};
565}; 565};
566static_assert(sizeof(KeyboardKey) == 0x20, "KeyboardKey is an invalid size"); 566static_assert(sizeof(KeyboardKey) == 0x20, "KeyboardKey is an invalid size");
567 567
@@ -590,16 +590,16 @@ static_assert(sizeof(MouseAttribute) == 0x4, "MouseAttribute is an invalid size"
590 590
591// This is nn::hid::detail::MouseState 591// This is nn::hid::detail::MouseState
592struct MouseState { 592struct MouseState {
593 s64 sampling_number; 593 s64 sampling_number{};
594 s32 x; 594 s32 x{};
595 s32 y; 595 s32 y{};
596 s32 delta_x; 596 s32 delta_x{};
597 s32 delta_y; 597 s32 delta_y{};
598 // Axis Order in HW is switched for the wheel 598 // Axis Order in HW is switched for the wheel
599 s32 delta_wheel_y; 599 s32 delta_wheel_y{};
600 s32 delta_wheel_x; 600 s32 delta_wheel_x{};
601 MouseButton button; 601 MouseButton button{};
602 MouseAttribute attribute; 602 MouseAttribute attribute{};
603}; 603};
604static_assert(sizeof(MouseState) == 0x28, "MouseState is an invalid size"); 604static_assert(sizeof(MouseState) == 0x28, "MouseState is an invalid size");
605 605
diff --git a/src/core/hle/service/hid/controllers/console_sixaxis.cpp b/src/core/hle/service/hid/controllers/console_sixaxis.cpp
index f5a0b94dd..bb3cba910 100644
--- a/src/core/hle/service/hid/controllers/console_sixaxis.cpp
+++ b/src/core/hle/service/hid/controllers/console_sixaxis.cpp
@@ -9,9 +9,14 @@
9namespace Service::HID { 9namespace Service::HID {
10constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C200; 10constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C200;
11 11
12Controller_ConsoleSixAxis::Controller_ConsoleSixAxis(Core::HID::HIDCore& hid_core_) 12Controller_ConsoleSixAxis::Controller_ConsoleSixAxis(Core::HID::HIDCore& hid_core_,
13 u8* raw_shared_memory_)
13 : ControllerBase{hid_core_} { 14 : ControllerBase{hid_core_} {
14 console = hid_core.GetEmulatedConsole(); 15 console = hid_core.GetEmulatedConsole();
16 static_assert(SHARED_MEMORY_OFFSET + sizeof(ConsoleSharedMemory) < shared_memory_size,
17 "ConsoleSharedMemory is bigger than the shared memory");
18 shared_memory = std::construct_at(
19 reinterpret_cast<ConsoleSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
15} 20}
16 21
17Controller_ConsoleSixAxis::~Controller_ConsoleSixAxis() = default; 22Controller_ConsoleSixAxis::~Controller_ConsoleSixAxis() = default;
@@ -20,8 +25,7 @@ void Controller_ConsoleSixAxis::OnInit() {}
20 25
21void Controller_ConsoleSixAxis::OnRelease() {} 26void Controller_ConsoleSixAxis::OnRelease() {}
22 27
23void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, 28void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
24 std::size_t size) {
25 if (!IsControllerActivated() || !is_transfer_memory_set) { 29 if (!IsControllerActivated() || !is_transfer_memory_set) {
26 seven_sixaxis_lifo.buffer_count = 0; 30 seven_sixaxis_lifo.buffer_count = 0;
27 seven_sixaxis_lifo.buffer_tail = 0; 31 seven_sixaxis_lifo.buffer_tail = 0;
@@ -48,13 +52,11 @@ void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_ti
48 -motion_status.quaternion.xyz.z, 52 -motion_status.quaternion.xyz.z,
49 }; 53 };
50 54
51 console_six_axis.sampling_number++; 55 shared_memory->sampling_number++;
52 console_six_axis.is_seven_six_axis_sensor_at_rest = motion_status.is_at_rest; 56 shared_memory->is_seven_six_axis_sensor_at_rest = motion_status.is_at_rest;
53 console_six_axis.verticalization_error = motion_status.verticalization_error; 57 shared_memory->verticalization_error = motion_status.verticalization_error;
54 console_six_axis.gyro_bias = motion_status.gyro_bias; 58 shared_memory->gyro_bias = motion_status.gyro_bias;
55 59
56 // Update console six axis shared memory
57 std::memcpy(data + SHARED_MEMORY_OFFSET, &console_six_axis, sizeof(console_six_axis));
58 // Update seven six axis transfer memory 60 // Update seven six axis transfer memory
59 seven_sixaxis_lifo.WriteNextEntry(next_seven_sixaxis_state); 61 seven_sixaxis_lifo.WriteNextEntry(next_seven_sixaxis_state);
60 std::memcpy(transfer_memory, &seven_sixaxis_lifo, sizeof(seven_sixaxis_lifo)); 62 std::memcpy(transfer_memory, &seven_sixaxis_lifo, sizeof(seven_sixaxis_lifo));
diff --git a/src/core/hle/service/hid/controllers/console_sixaxis.h b/src/core/hle/service/hid/controllers/console_sixaxis.h
index 6da5e9454..2fd11538f 100644
--- a/src/core/hle/service/hid/controllers/console_sixaxis.h
+++ b/src/core/hle/service/hid/controllers/console_sixaxis.h
@@ -17,7 +17,7 @@ class EmulatedConsole;
17namespace Service::HID { 17namespace Service::HID {
18class Controller_ConsoleSixAxis final : public ControllerBase { 18class Controller_ConsoleSixAxis final : public ControllerBase {
19public: 19public:
20 explicit Controller_ConsoleSixAxis(Core::HID::HIDCore& hid_core_); 20 explicit Controller_ConsoleSixAxis(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
21 ~Controller_ConsoleSixAxis() override; 21 ~Controller_ConsoleSixAxis() override;
22 22
23 // Called when the controller is initialized 23 // Called when the controller is initialized
@@ -27,7 +27,7 @@ public:
27 void OnRelease() override; 27 void OnRelease() override;
28 28
29 // When the controller is requesting an update for the shared memory 29 // When the controller is requesting an update for the shared memory
30 void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, size_t size) override; 30 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
31 31
32 // Called on InitializeSevenSixAxisSensor 32 // Called on InitializeSevenSixAxisSensor
33 void SetTransferMemoryPointer(u8* t_mem); 33 void SetTransferMemoryPointer(u8* t_mem);
@@ -61,12 +61,13 @@ private:
61 Lifo<SevenSixAxisState, 0x21> seven_sixaxis_lifo{}; 61 Lifo<SevenSixAxisState, 0x21> seven_sixaxis_lifo{};
62 static_assert(sizeof(seven_sixaxis_lifo) == 0xA70, "SevenSixAxisState is an invalid size"); 62 static_assert(sizeof(seven_sixaxis_lifo) == 0xA70, "SevenSixAxisState is an invalid size");
63 63
64 Core::HID::EmulatedConsole* console; 64 SevenSixAxisState next_seven_sixaxis_state{};
65 u8* transfer_memory = nullptr; 65 u8* transfer_memory = nullptr;
66 ConsoleSharedMemory* shared_memory = nullptr;
67 Core::HID::EmulatedConsole* console = nullptr;
68
66 bool is_transfer_memory_set = false; 69 bool is_transfer_memory_set = false;
67 u64 last_saved_timestamp{}; 70 u64 last_saved_timestamp{};
68 u64 last_global_timestamp{}; 71 u64 last_global_timestamp{};
69 ConsoleSharedMemory console_six_axis{};
70 SevenSixAxisState next_seven_sixaxis_state{};
71}; 72};
72} // namespace Service::HID 73} // 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
index bb01ea643..d6f7a5073 100644
--- a/src/core/hle/service/hid/controllers/controller_base.h
+++ b/src/core/hle/service/hid/controllers/controller_base.h
@@ -26,12 +26,10 @@ public:
26 virtual void OnRelease() = 0; 26 virtual void OnRelease() = 0;
27 27
28 // When the controller is requesting an update for the shared memory 28 // When the controller is requesting an update for the shared memory
29 virtual void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, 29 virtual void OnUpdate(const Core::Timing::CoreTiming& core_timing) = 0;
30 std::size_t size) = 0;
31 30
32 // When the controller is requesting a motion update for the shared memory 31 // When the controller is requesting a motion update for the shared memory
33 virtual void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, 32 virtual void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing) {}
34 std::size_t size) {}
35 33
36 void ActivateController(); 34 void ActivateController();
37 35
@@ -40,6 +38,7 @@ public:
40 bool IsControllerActivated() const; 38 bool IsControllerActivated() const;
41 39
42 static const std::size_t hid_entry_count = 17; 40 static const std::size_t hid_entry_count = 17;
41 static const std::size_t shared_memory_size = 0x40000;
43 42
44protected: 43protected:
45 bool is_activated{false}; 44 bool is_activated{false};
diff --git a/src/core/hle/service/hid/controllers/debug_pad.cpp b/src/core/hle/service/hid/controllers/debug_pad.cpp
index 73309d64e..8ec9f4a95 100644
--- a/src/core/hle/service/hid/controllers/debug_pad.cpp
+++ b/src/core/hle/service/hid/controllers/debug_pad.cpp
@@ -13,8 +13,12 @@
13namespace Service::HID { 13namespace Service::HID {
14constexpr std::size_t SHARED_MEMORY_OFFSET = 0x00000; 14constexpr std::size_t SHARED_MEMORY_OFFSET = 0x00000;
15 15
16Controller_DebugPad::Controller_DebugPad(Core::HID::HIDCore& hid_core_) 16Controller_DebugPad::Controller_DebugPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
17 : ControllerBase{hid_core_} { 17 : ControllerBase{hid_core_} {
18 static_assert(SHARED_MEMORY_OFFSET + sizeof(DebugPadSharedMemory) < shared_memory_size,
19 "DebugPadSharedMemory is bigger than the shared memory");
20 shared_memory = std::construct_at(
21 reinterpret_cast<DebugPadSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
18 controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other); 22 controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other);
19} 23}
20 24
@@ -24,16 +28,14 @@ void Controller_DebugPad::OnInit() {}
24 28
25void Controller_DebugPad::OnRelease() {} 29void Controller_DebugPad::OnRelease() {}
26 30
27void Controller_DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, 31void Controller_DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
28 std::size_t size) {
29 if (!IsControllerActivated()) { 32 if (!IsControllerActivated()) {
30 debug_pad_lifo.buffer_count = 0; 33 shared_memory->debug_pad_lifo.buffer_count = 0;
31 debug_pad_lifo.buffer_tail = 0; 34 shared_memory->debug_pad_lifo.buffer_tail = 0;
32 std::memcpy(data + SHARED_MEMORY_OFFSET, &debug_pad_lifo, sizeof(debug_pad_lifo));
33 return; 35 return;
34 } 36 }
35 37
36 const auto& last_entry = debug_pad_lifo.ReadCurrentEntry().state; 38 const auto& last_entry = shared_memory->debug_pad_lifo.ReadCurrentEntry().state;
37 next_state.sampling_number = last_entry.sampling_number + 1; 39 next_state.sampling_number = last_entry.sampling_number + 1;
38 40
39 if (Settings::values.debug_pad_enabled) { 41 if (Settings::values.debug_pad_enabled) {
@@ -47,8 +49,7 @@ void Controller_DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing,
47 next_state.r_stick = stick_state.right; 49 next_state.r_stick = stick_state.right;
48 } 50 }
49 51
50 debug_pad_lifo.WriteNextEntry(next_state); 52 shared_memory->debug_pad_lifo.WriteNextEntry(next_state);
51 std::memcpy(data + SHARED_MEMORY_OFFSET, &debug_pad_lifo, sizeof(debug_pad_lifo));
52} 53}
53 54
54} // namespace Service::HID 55} // 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
index 388d25b3c..68ff0ea79 100644
--- a/src/core/hle/service/hid/controllers/debug_pad.h
+++ b/src/core/hle/service/hid/controllers/debug_pad.h
@@ -17,7 +17,7 @@ struct AnalogStickState;
17namespace Service::HID { 17namespace Service::HID {
18class Controller_DebugPad final : public ControllerBase { 18class Controller_DebugPad final : public ControllerBase {
19public: 19public:
20 explicit Controller_DebugPad(Core::HID::HIDCore& hid_core_); 20 explicit Controller_DebugPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
21 ~Controller_DebugPad() override; 21 ~Controller_DebugPad() override;
22 22
23 // Called when the controller is initialized 23 // Called when the controller is initialized
@@ -27,7 +27,7 @@ public:
27 void OnRelease() override; 27 void OnRelease() override;
28 28
29 // When the controller is requesting an update for the shared memory 29 // When the controller is requesting an update for the shared memory
30 void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; 30 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
31 31
32private: 32private:
33 // This is nn::hid::DebugPadAttribute 33 // This is nn::hid::DebugPadAttribute
@@ -41,19 +41,24 @@ private:
41 41
42 // This is nn::hid::DebugPadState 42 // This is nn::hid::DebugPadState
43 struct DebugPadState { 43 struct DebugPadState {
44 s64 sampling_number; 44 s64 sampling_number{};
45 DebugPadAttribute attribute; 45 DebugPadAttribute attribute{};
46 Core::HID::DebugPadButton pad_state; 46 Core::HID::DebugPadButton pad_state{};
47 Core::HID::AnalogStickState r_stick; 47 Core::HID::AnalogStickState r_stick{};
48 Core::HID::AnalogStickState l_stick; 48 Core::HID::AnalogStickState l_stick{};
49 }; 49 };
50 static_assert(sizeof(DebugPadState) == 0x20, "DebugPadState is an invalid state"); 50 static_assert(sizeof(DebugPadState) == 0x20, "DebugPadState is an invalid state");
51 51
52 // This is nn::hid::detail::DebugPadLifo 52 struct DebugPadSharedMemory {
53 Lifo<DebugPadState, hid_entry_count> debug_pad_lifo{}; 53 // This is nn::hid::detail::DebugPadLifo
54 static_assert(sizeof(debug_pad_lifo) == 0x2C8, "debug_pad_lifo is an invalid size"); 54 Lifo<DebugPadState, hid_entry_count> debug_pad_lifo{};
55 DebugPadState next_state{}; 55 static_assert(sizeof(debug_pad_lifo) == 0x2C8, "debug_pad_lifo is an invalid size");
56 INSERT_PADDING_WORDS(0x4E);
57 };
58 static_assert(sizeof(DebugPadSharedMemory) == 0x400, "DebugPadSharedMemory is an invalid size");
56 59
57 Core::HID::EmulatedController* controller; 60 DebugPadState next_state{};
61 DebugPadSharedMemory* shared_memory = nullptr;
62 Core::HID::EmulatedController* controller = nullptr;
58}; 63};
59} // namespace Service::HID 64} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp
index c8dd131dd..3eae1ae35 100644
--- a/src/core/hle/service/hid/controllers/gesture.cpp
+++ b/src/core/hle/service/hid/controllers/gesture.cpp
@@ -23,25 +23,28 @@ constexpr f32 Square(s32 num) {
23 return static_cast<f32>(num * num); 23 return static_cast<f32>(num * num);
24} 24}
25 25
26Controller_Gesture::Controller_Gesture(Core::HID::HIDCore& hid_core_) : ControllerBase(hid_core_) { 26Controller_Gesture::Controller_Gesture(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
27 : ControllerBase(hid_core_) {
28 static_assert(SHARED_MEMORY_OFFSET + sizeof(GestureSharedMemory) < shared_memory_size,
29 "GestureSharedMemory is bigger than the shared memory");
30 shared_memory = std::construct_at(
31 reinterpret_cast<GestureSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
27 console = hid_core.GetEmulatedConsole(); 32 console = hid_core.GetEmulatedConsole();
28} 33}
29Controller_Gesture::~Controller_Gesture() = default; 34Controller_Gesture::~Controller_Gesture() = default;
30 35
31void Controller_Gesture::OnInit() { 36void Controller_Gesture::OnInit() {
32 gesture_lifo.buffer_count = 0; 37 shared_memory->gesture_lifo.buffer_count = 0;
33 gesture_lifo.buffer_tail = 0; 38 shared_memory->gesture_lifo.buffer_tail = 0;
34 force_update = true; 39 force_update = true;
35} 40}
36 41
37void Controller_Gesture::OnRelease() {} 42void Controller_Gesture::OnRelease() {}
38 43
39void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, 44void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
40 std::size_t size) {
41 if (!IsControllerActivated()) { 45 if (!IsControllerActivated()) {
42 gesture_lifo.buffer_count = 0; 46 shared_memory->gesture_lifo.buffer_count = 0;
43 gesture_lifo.buffer_tail = 0; 47 shared_memory->gesture_lifo.buffer_tail = 0;
44 std::memcpy(data + SHARED_MEMORY_OFFSET, &gesture_lifo, sizeof(gesture_lifo));
45 return; 48 return;
46 } 49 }
47 50
@@ -49,15 +52,15 @@ void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u
49 52
50 GestureProperties gesture = GetGestureProperties(); 53 GestureProperties gesture = GetGestureProperties();
51 f32 time_difference = 54 f32 time_difference =
52 static_cast<f32>(gesture_lifo.timestamp - last_update_timestamp) / (1000 * 1000 * 1000); 55 static_cast<f32>(shared_memory->gesture_lifo.timestamp - last_update_timestamp) /
56 (1000 * 1000 * 1000);
53 57
54 // Only update if necesary 58 // Only update if necesary
55 if (!ShouldUpdateGesture(gesture, time_difference)) { 59 if (!ShouldUpdateGesture(gesture, time_difference)) {
56 return; 60 return;
57 } 61 }
58 62
59 last_update_timestamp = gesture_lifo.timestamp; 63 last_update_timestamp = shared_memory->gesture_lifo.timestamp;
60 UpdateGestureSharedMemory(data, size, gesture, time_difference);
61} 64}
62 65
63void Controller_Gesture::ReadTouchInput() { 66void Controller_Gesture::ReadTouchInput() {
@@ -97,7 +100,7 @@ void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size,
97 GestureType type = GestureType::Idle; 100 GestureType type = GestureType::Idle;
98 GestureAttribute attributes{}; 101 GestureAttribute attributes{};
99 102
100 const auto& last_entry = gesture_lifo.ReadCurrentEntry().state; 103 const auto& last_entry = shared_memory->gesture_lifo.ReadCurrentEntry().state;
101 104
102 // Reset next state to default 105 // Reset next state to default
103 next_state.sampling_number = last_entry.sampling_number + 1; 106 next_state.sampling_number = last_entry.sampling_number + 1;
@@ -127,8 +130,7 @@ void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size,
127 next_state.points = gesture.points; 130 next_state.points = gesture.points;
128 last_gesture = gesture; 131 last_gesture = gesture;
129 132
130 gesture_lifo.WriteNextEntry(next_state); 133 shared_memory->gesture_lifo.WriteNextEntry(next_state);
131 std::memcpy(data + SHARED_MEMORY_OFFSET, &gesture_lifo, sizeof(gesture_lifo));
132} 134}
133 135
134void Controller_Gesture::NewGesture(GestureProperties& gesture, GestureType& type, 136void Controller_Gesture::NewGesture(GestureProperties& gesture, GestureType& type,
@@ -305,7 +307,7 @@ void Controller_Gesture::SetSwipeEvent(GestureProperties& gesture,
305} 307}
306 308
307const Controller_Gesture::GestureState& Controller_Gesture::GetLastGestureEntry() const { 309const Controller_Gesture::GestureState& Controller_Gesture::GetLastGestureEntry() const {
308 return gesture_lifo.ReadCurrentEntry().state; 310 return shared_memory->gesture_lifo.ReadCurrentEntry().state;
309} 311}
310 312
311Controller_Gesture::GestureProperties Controller_Gesture::GetGestureProperties() { 313Controller_Gesture::GestureProperties Controller_Gesture::GetGestureProperties() {
diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h
index 7a9d28dc6..c62a341bf 100644
--- a/src/core/hle/service/hid/controllers/gesture.h
+++ b/src/core/hle/service/hid/controllers/gesture.h
@@ -14,7 +14,7 @@
14namespace Service::HID { 14namespace Service::HID {
15class Controller_Gesture final : public ControllerBase { 15class Controller_Gesture final : public ControllerBase {
16public: 16public:
17 explicit Controller_Gesture(Core::HID::HIDCore& hid_core_); 17 explicit Controller_Gesture(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
18 ~Controller_Gesture() override; 18 ~Controller_Gesture() override;
19 19
20 // Called when the controller is initialized 20 // Called when the controller is initialized
@@ -24,7 +24,7 @@ public:
24 void OnRelease() override; 24 void OnRelease() override;
25 25
26 // When the controller is requesting an update for the shared memory 26 // When the controller is requesting an update for the shared memory
27 void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, size_t size) override; 27 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
28 28
29private: 29private:
30 static constexpr size_t MAX_FINGERS = 16; 30 static constexpr size_t MAX_FINGERS = 16;
@@ -66,19 +66,19 @@ private:
66 66
67 // This is nn::hid::GestureState 67 // This is nn::hid::GestureState
68 struct GestureState { 68 struct GestureState {
69 s64 sampling_number; 69 s64 sampling_number{};
70 s64 detection_count; 70 s64 detection_count{};
71 GestureType type; 71 GestureType type{GestureType::Idle};
72 GestureDirection direction; 72 GestureDirection direction{GestureDirection::None};
73 Common::Point<s32> pos; 73 Common::Point<s32> pos{};
74 Common::Point<s32> delta; 74 Common::Point<s32> delta{};
75 f32 vel_x; 75 f32 vel_x{};
76 f32 vel_y; 76 f32 vel_y{};
77 GestureAttribute attributes; 77 GestureAttribute attributes{};
78 f32 scale; 78 f32 scale{};
79 f32 rotation_angle; 79 f32 rotation_angle{};
80 s32 point_count; 80 s32 point_count{};
81 std::array<Common::Point<s32>, 4> points; 81 std::array<Common::Point<s32>, 4> points{};
82 }; 82 };
83 static_assert(sizeof(GestureState) == 0x60, "GestureState is an invalid size"); 83 static_assert(sizeof(GestureState) == 0x60, "GestureState is an invalid size");
84 84
@@ -92,6 +92,14 @@ private:
92 f32 angle{}; 92 f32 angle{};
93 }; 93 };
94 94
95 struct GestureSharedMemory {
96 // This is nn::hid::detail::GestureLifo
97 Lifo<GestureState, hid_entry_count> gesture_lifo{};
98 static_assert(sizeof(gesture_lifo) == 0x708, "gesture_lifo is an invalid size");
99 INSERT_PADDING_WORDS(0x3E);
100 };
101 static_assert(sizeof(GestureSharedMemory) == 0x800, "GestureSharedMemory is an invalid size");
102
95 // Reads input from all available input engines 103 // Reads input from all available input engines
96 void ReadTouchInput(); 104 void ReadTouchInput();
97 105
@@ -134,12 +142,9 @@ private:
134 // Returns the average distance, angle and middle point of the active fingers 142 // Returns the average distance, angle and middle point of the active fingers
135 GestureProperties GetGestureProperties(); 143 GestureProperties GetGestureProperties();
136 144
137 // This is nn::hid::detail::GestureLifo
138 Lifo<GestureState, hid_entry_count> gesture_lifo{};
139 static_assert(sizeof(gesture_lifo) == 0x708, "gesture_lifo is an invalid size");
140 GestureState next_state{}; 145 GestureState next_state{};
141 146 GestureSharedMemory* shared_memory = nullptr;
142 Core::HID::EmulatedConsole* console; 147 Core::HID::EmulatedConsole* console = nullptr;
143 148
144 std::array<Core::HID::TouchFinger, MAX_POINTS> fingers{}; 149 std::array<Core::HID::TouchFinger, MAX_POINTS> fingers{};
145 GestureProperties last_gesture{}; 150 GestureProperties last_gesture{};
diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp
index 8dc67757b..117d87433 100644
--- a/src/core/hle/service/hid/controllers/keyboard.cpp
+++ b/src/core/hle/service/hid/controllers/keyboard.cpp
@@ -12,8 +12,12 @@
12namespace Service::HID { 12namespace Service::HID {
13constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800; 13constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800;
14 14
15Controller_Keyboard::Controller_Keyboard(Core::HID::HIDCore& hid_core_) 15Controller_Keyboard::Controller_Keyboard(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
16 : ControllerBase{hid_core_} { 16 : ControllerBase{hid_core_} {
17 static_assert(SHARED_MEMORY_OFFSET + sizeof(KeyboardSharedMemory) < shared_memory_size,
18 "KeyboardSharedMemory is bigger than the shared memory");
19 shared_memory = std::construct_at(
20 reinterpret_cast<KeyboardSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
17 emulated_devices = hid_core.GetEmulatedDevices(); 21 emulated_devices = hid_core.GetEmulatedDevices();
18} 22}
19 23
@@ -23,16 +27,14 @@ void Controller_Keyboard::OnInit() {}
23 27
24void Controller_Keyboard::OnRelease() {} 28void Controller_Keyboard::OnRelease() {}
25 29
26void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, 30void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
27 std::size_t size) {
28 if (!IsControllerActivated()) { 31 if (!IsControllerActivated()) {
29 keyboard_lifo.buffer_count = 0; 32 shared_memory->keyboard_lifo.buffer_count = 0;
30 keyboard_lifo.buffer_tail = 0; 33 shared_memory->keyboard_lifo.buffer_tail = 0;
31 std::memcpy(data + SHARED_MEMORY_OFFSET, &keyboard_lifo, sizeof(keyboard_lifo));
32 return; 34 return;
33 } 35 }
34 36
35 const auto& last_entry = keyboard_lifo.ReadCurrentEntry().state; 37 const auto& last_entry = shared_memory->keyboard_lifo.ReadCurrentEntry().state;
36 next_state.sampling_number = last_entry.sampling_number + 1; 38 next_state.sampling_number = last_entry.sampling_number + 1;
37 39
38 if (Settings::values.keyboard_enabled) { 40 if (Settings::values.keyboard_enabled) {
@@ -44,8 +46,7 @@ void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing,
44 next_state.attribute.is_connected.Assign(1); 46 next_state.attribute.is_connected.Assign(1);
45 } 47 }
46 48
47 keyboard_lifo.WriteNextEntry(next_state); 49 shared_memory->keyboard_lifo.WriteNextEntry(next_state);
48 std::memcpy(data + SHARED_MEMORY_OFFSET, &keyboard_lifo, sizeof(keyboard_lifo));
49} 50}
50 51
51} // namespace Service::HID 52} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/keyboard.h b/src/core/hle/service/hid/controllers/keyboard.h
index 39c6085f1..7532f53c6 100644
--- a/src/core/hle/service/hid/controllers/keyboard.h
+++ b/src/core/hle/service/hid/controllers/keyboard.h
@@ -16,7 +16,7 @@ struct KeyboardKey;
16namespace Service::HID { 16namespace Service::HID {
17class Controller_Keyboard final : public ControllerBase { 17class Controller_Keyboard final : public ControllerBase {
18public: 18public:
19 explicit Controller_Keyboard(Core::HID::HIDCore& hid_core_); 19 explicit Controller_Keyboard(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
20 ~Controller_Keyboard() override; 20 ~Controller_Keyboard() override;
21 21
22 // Called when the controller is initialized 22 // Called when the controller is initialized
@@ -26,23 +26,28 @@ public:
26 void OnRelease() override; 26 void OnRelease() override;
27 27
28 // When the controller is requesting an update for the shared memory 28 // When the controller is requesting an update for the shared memory
29 void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; 29 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
30 30
31private: 31private:
32 // This is nn::hid::detail::KeyboardState 32 // This is nn::hid::detail::KeyboardState
33 struct KeyboardState { 33 struct KeyboardState {
34 s64 sampling_number; 34 s64 sampling_number{};
35 Core::HID::KeyboardModifier modifier; 35 Core::HID::KeyboardModifier modifier{};
36 Core::HID::KeyboardAttribute attribute; 36 Core::HID::KeyboardAttribute attribute{};
37 Core::HID::KeyboardKey key; 37 Core::HID::KeyboardKey key{};
38 }; 38 };
39 static_assert(sizeof(KeyboardState) == 0x30, "KeyboardState is an invalid size"); 39 static_assert(sizeof(KeyboardState) == 0x30, "KeyboardState is an invalid size");
40 40
41 // This is nn::hid::detail::KeyboardLifo 41 struct KeyboardSharedMemory {
42 Lifo<KeyboardState, hid_entry_count> keyboard_lifo{}; 42 // This is nn::hid::detail::KeyboardLifo
43 static_assert(sizeof(keyboard_lifo) == 0x3D8, "keyboard_lifo is an invalid size"); 43 Lifo<KeyboardState, hid_entry_count> keyboard_lifo{};
44 KeyboardState next_state{}; 44 static_assert(sizeof(keyboard_lifo) == 0x3D8, "keyboard_lifo is an invalid size");
45 INSERT_PADDING_WORDS(0xA);
46 };
47 static_assert(sizeof(KeyboardSharedMemory) == 0x400, "KeyboardSharedMemory is an invalid size");
45 48
46 Core::HID::EmulatedDevices* emulated_devices; 49 KeyboardState next_state{};
50 KeyboardSharedMemory* shared_memory = nullptr;
51 Core::HID::EmulatedDevices* emulated_devices = nullptr;
47}; 52};
48} // namespace Service::HID 53} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/mouse.cpp b/src/core/hle/service/hid/controllers/mouse.cpp
index a0292f586..b11cb438d 100644
--- a/src/core/hle/service/hid/controllers/mouse.cpp
+++ b/src/core/hle/service/hid/controllers/mouse.cpp
@@ -12,7 +12,12 @@
12namespace Service::HID { 12namespace Service::HID {
13constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3400; 13constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3400;
14 14
15Controller_Mouse::Controller_Mouse(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} { 15Controller_Mouse::Controller_Mouse(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
16 : ControllerBase{hid_core_} {
17 static_assert(SHARED_MEMORY_OFFSET + sizeof(MouseSharedMemory) < shared_memory_size,
18 "MouseSharedMemory is bigger than the shared memory");
19 shared_memory = std::construct_at(
20 reinterpret_cast<MouseSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
16 emulated_devices = hid_core.GetEmulatedDevices(); 21 emulated_devices = hid_core.GetEmulatedDevices();
17} 22}
18 23
@@ -21,16 +26,14 @@ Controller_Mouse::~Controller_Mouse() = default;
21void Controller_Mouse::OnInit() {} 26void Controller_Mouse::OnInit() {}
22void Controller_Mouse::OnRelease() {} 27void Controller_Mouse::OnRelease() {}
23 28
24void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, 29void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
25 std::size_t size) {
26 if (!IsControllerActivated()) { 30 if (!IsControllerActivated()) {
27 mouse_lifo.buffer_count = 0; 31 shared_memory->mouse_lifo.buffer_count = 0;
28 mouse_lifo.buffer_tail = 0; 32 shared_memory->mouse_lifo.buffer_tail = 0;
29 std::memcpy(data + SHARED_MEMORY_OFFSET, &mouse_lifo, sizeof(mouse_lifo));
30 return; 33 return;
31 } 34 }
32 35
33 const auto& last_entry = mouse_lifo.ReadCurrentEntry().state; 36 const auto& last_entry = shared_memory->mouse_lifo.ReadCurrentEntry().state;
34 next_state.sampling_number = last_entry.sampling_number + 1; 37 next_state.sampling_number = last_entry.sampling_number + 1;
35 38
36 next_state.attribute.raw = 0; 39 next_state.attribute.raw = 0;
@@ -50,8 +53,7 @@ void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
50 next_state.button = mouse_button_state; 53 next_state.button = mouse_button_state;
51 } 54 }
52 55
53 mouse_lifo.WriteNextEntry(next_state); 56 shared_memory->mouse_lifo.WriteNextEntry(next_state);
54 std::memcpy(data + SHARED_MEMORY_OFFSET, &mouse_lifo, sizeof(mouse_lifo));
55} 57}
56 58
57} // namespace Service::HID 59} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/mouse.h b/src/core/hle/service/hid/controllers/mouse.h
index 62acdfb77..733d00577 100644
--- a/src/core/hle/service/hid/controllers/mouse.h
+++ b/src/core/hle/service/hid/controllers/mouse.h
@@ -16,7 +16,7 @@ struct AnalogStickState;
16namespace Service::HID { 16namespace Service::HID {
17class Controller_Mouse final : public ControllerBase { 17class Controller_Mouse final : public ControllerBase {
18public: 18public:
19 explicit Controller_Mouse(Core::HID::HIDCore& hid_core_); 19 explicit Controller_Mouse(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
20 ~Controller_Mouse() override; 20 ~Controller_Mouse() override;
21 21
22 // Called when the controller is initialized 22 // Called when the controller is initialized
@@ -26,15 +26,20 @@ public:
26 void OnRelease() override; 26 void OnRelease() override;
27 27
28 // When the controller is requesting an update for the shared memory 28 // When the controller is requesting an update for the shared memory
29 void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; 29 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
30 30
31private: 31private:
32 // This is nn::hid::detail::MouseLifo 32 struct MouseSharedMemory {
33 Lifo<Core::HID::MouseState, hid_entry_count> mouse_lifo{}; 33 // This is nn::hid::detail::MouseLifo
34 static_assert(sizeof(mouse_lifo) == 0x350, "mouse_lifo is an invalid size"); 34 Lifo<Core::HID::MouseState, hid_entry_count> mouse_lifo{};
35 Core::HID::MouseState next_state{}; 35 static_assert(sizeof(mouse_lifo) == 0x350, "mouse_lifo is an invalid size");
36 INSERT_PADDING_WORDS(0x2C);
37 };
38 static_assert(sizeof(MouseSharedMemory) == 0x400, "MouseSharedMemory is an invalid size");
36 39
37 Core::HID::AnalogStickState last_mouse_wheel_state; 40 Core::HID::MouseState next_state{};
38 Core::HID::EmulatedDevices* emulated_devices; 41 Core::HID::AnalogStickState last_mouse_wheel_state{};
42 MouseSharedMemory* shared_memory = nullptr;
43 Core::HID::EmulatedDevices* emulated_devices = nullptr;
39}; 44};
40} // namespace Service::HID 45} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 16e973b25..17f71beaf 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -61,11 +61,14 @@ bool Controller_NPad::IsDeviceHandleValid(const Core::HID::SixAxisSensorHandle&
61 return npad_id && npad_type && device_index; 61 return npad_id && npad_type && device_index;
62} 62}
63 63
64Controller_NPad::Controller_NPad(Core::HID::HIDCore& hid_core_, 64Controller_NPad::Controller_NPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_,
65 KernelHelpers::ServiceContext& service_context_) 65 KernelHelpers::ServiceContext& service_context_)
66 : ControllerBase{hid_core_}, service_context{service_context_} { 66 : ControllerBase{hid_core_}, service_context{service_context_} {
67 static_assert(NPAD_OFFSET + (NPAD_COUNT * sizeof(NpadInternalState)) < shared_memory_size);
67 for (std::size_t i = 0; i < controller_data.size(); ++i) { 68 for (std::size_t i = 0; i < controller_data.size(); ++i) {
68 auto& controller = controller_data[i]; 69 auto& controller = controller_data[i];
70 controller.shared_memory = std::construct_at(reinterpret_cast<NpadInternalState*>(
71 raw_shared_memory_ + NPAD_OFFSET + (i * sizeof(NpadInternalState))));
69 controller.device = hid_core.GetEmulatedControllerByIndex(i); 72 controller.device = hid_core.GetEmulatedControllerByIndex(i);
70 controller.vibration[Core::HID::EmulatedDeviceIndex::LeftIndex].latest_vibration_value = 73 controller.vibration[Core::HID::EmulatedDeviceIndex::LeftIndex].latest_vibration_value =
71 Core::HID::DEFAULT_VIBRATION_VALUE; 74 Core::HID::DEFAULT_VIBRATION_VALUE;
@@ -115,11 +118,11 @@ void Controller_NPad::ControllerUpdate(Core::HID::ControllerTriggerType type,
115 if (!controller.device->IsConnected()) { 118 if (!controller.device->IsConnected()) {
116 return; 119 return;
117 } 120 }
118 auto& shared_memory = controller.shared_memory_entry; 121 auto* shared_memory = controller.shared_memory;
119 const auto& battery_level = controller.device->GetBattery(); 122 const auto& battery_level = controller.device->GetBattery();
120 shared_memory.battery_level_dual = battery_level.dual.battery_level; 123 shared_memory->battery_level_dual = battery_level.dual.battery_level;
121 shared_memory.battery_level_left = battery_level.left.battery_level; 124 shared_memory->battery_level_left = battery_level.left.battery_level;
122 shared_memory.battery_level_right = battery_level.right.battery_level; 125 shared_memory->battery_level_right = battery_level.right.battery_level;
123 break; 126 break;
124 } 127 }
125 default: 128 default:
@@ -134,99 +137,100 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
134 } 137 }
135 LOG_DEBUG(Service_HID, "Npad connected {}", npad_id); 138 LOG_DEBUG(Service_HID, "Npad connected {}", npad_id);
136 const auto controller_type = controller.device->GetNpadStyleIndex(); 139 const auto controller_type = controller.device->GetNpadStyleIndex();
137 auto& shared_memory = controller.shared_memory_entry; 140 auto* shared_memory = controller.shared_memory;
138 if (controller_type == Core::HID::NpadStyleIndex::None) { 141 if (controller_type == Core::HID::NpadStyleIndex::None) {
139 controller.styleset_changed_event->GetWritableEvent().Signal(); 142 controller.styleset_changed_event->GetWritableEvent().Signal();
140 return; 143 return;
141 } 144 }
142 shared_memory.style_tag.raw = Core::HID::NpadStyleSet::None; 145 shared_memory->style_tag.raw = Core::HID::NpadStyleSet::None;
143 shared_memory.device_type.raw = 0; 146 shared_memory->device_type.raw = 0;
144 shared_memory.system_properties.raw = 0; 147 shared_memory->system_properties.raw = 0;
145 switch (controller_type) { 148 switch (controller_type) {
146 case Core::HID::NpadStyleIndex::None: 149 case Core::HID::NpadStyleIndex::None:
147 UNREACHABLE(); 150 UNREACHABLE();
148 break; 151 break;
149 case Core::HID::NpadStyleIndex::ProController: 152 case Core::HID::NpadStyleIndex::ProController:
150 shared_memory.style_tag.fullkey.Assign(1); 153 shared_memory->style_tag.fullkey.Assign(1);
151 shared_memory.device_type.fullkey.Assign(1); 154 shared_memory->device_type.fullkey.Assign(1);
152 shared_memory.system_properties.is_vertical.Assign(1); 155 shared_memory->system_properties.is_vertical.Assign(1);
153 shared_memory.system_properties.use_plus.Assign(1); 156 shared_memory->system_properties.use_plus.Assign(1);
154 shared_memory.system_properties.use_minus.Assign(1); 157 shared_memory->system_properties.use_minus.Assign(1);
155 shared_memory.applet_footer.type = AppletFooterUiType::SwitchProController; 158 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::SwitchProController;
156 break; 159 break;
157 case Core::HID::NpadStyleIndex::Handheld: 160 case Core::HID::NpadStyleIndex::Handheld:
158 shared_memory.style_tag.handheld.Assign(1); 161 shared_memory->style_tag.handheld.Assign(1);
159 shared_memory.device_type.handheld_left.Assign(1); 162 shared_memory->device_type.handheld_left.Assign(1);
160 shared_memory.device_type.handheld_right.Assign(1); 163 shared_memory->device_type.handheld_right.Assign(1);
161 shared_memory.system_properties.is_vertical.Assign(1); 164 shared_memory->system_properties.is_vertical.Assign(1);
162 shared_memory.system_properties.use_plus.Assign(1); 165 shared_memory->system_properties.use_plus.Assign(1);
163 shared_memory.system_properties.use_minus.Assign(1); 166 shared_memory->system_properties.use_minus.Assign(1);
164 shared_memory.system_properties.use_directional_buttons.Assign(1); 167 shared_memory->system_properties.use_directional_buttons.Assign(1);
165 shared_memory.assignment_mode = NpadJoyAssignmentMode::Dual; 168 shared_memory->assignment_mode = NpadJoyAssignmentMode::Dual;
166 shared_memory.applet_footer.type = AppletFooterUiType::HandheldJoyConLeftJoyConRight; 169 shared_memory->applet_nfc_xcd.applet_footer.type =
170 AppletFooterUiType::HandheldJoyConLeftJoyConRight;
167 break; 171 break;
168 case Core::HID::NpadStyleIndex::JoyconDual: 172 case Core::HID::NpadStyleIndex::JoyconDual:
169 shared_memory.style_tag.joycon_dual.Assign(1); 173 shared_memory->style_tag.joycon_dual.Assign(1);
170 if (controller.is_dual_left_connected) { 174 if (controller.is_dual_left_connected) {
171 shared_memory.device_type.joycon_left.Assign(1); 175 shared_memory->device_type.joycon_left.Assign(1);
172 shared_memory.system_properties.use_minus.Assign(1); 176 shared_memory->system_properties.use_minus.Assign(1);
173 } 177 }
174 if (controller.is_dual_right_connected) { 178 if (controller.is_dual_right_connected) {
175 shared_memory.device_type.joycon_right.Assign(1); 179 shared_memory->device_type.joycon_right.Assign(1);
176 shared_memory.system_properties.use_plus.Assign(1); 180 shared_memory->system_properties.use_plus.Assign(1);
177 } 181 }
178 shared_memory.system_properties.use_directional_buttons.Assign(1); 182 shared_memory->system_properties.use_directional_buttons.Assign(1);
179 shared_memory.system_properties.is_vertical.Assign(1); 183 shared_memory->system_properties.is_vertical.Assign(1);
180 shared_memory.assignment_mode = NpadJoyAssignmentMode::Dual; 184 shared_memory->assignment_mode = NpadJoyAssignmentMode::Dual;
181 if (controller.is_dual_left_connected && controller.is_dual_right_connected) { 185 if (controller.is_dual_left_connected && controller.is_dual_right_connected) {
182 shared_memory.applet_footer.type = AppletFooterUiType::JoyDual; 186 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDual;
183 } else if (controller.is_dual_left_connected) { 187 } else if (controller.is_dual_left_connected) {
184 shared_memory.applet_footer.type = AppletFooterUiType::JoyDualLeftOnly; 188 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDualLeftOnly;
185 } else { 189 } else {
186 shared_memory.applet_footer.type = AppletFooterUiType::JoyDualRightOnly; 190 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDualRightOnly;
187 } 191 }
188 break; 192 break;
189 case Core::HID::NpadStyleIndex::JoyconLeft: 193 case Core::HID::NpadStyleIndex::JoyconLeft:
190 shared_memory.style_tag.joycon_left.Assign(1); 194 shared_memory->style_tag.joycon_left.Assign(1);
191 shared_memory.device_type.joycon_left.Assign(1); 195 shared_memory->device_type.joycon_left.Assign(1);
192 shared_memory.system_properties.is_horizontal.Assign(1); 196 shared_memory->system_properties.is_horizontal.Assign(1);
193 shared_memory.system_properties.use_minus.Assign(1); 197 shared_memory->system_properties.use_minus.Assign(1);
194 shared_memory.applet_footer.type = AppletFooterUiType::JoyLeftHorizontal; 198 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyLeftHorizontal;
195 break; 199 break;
196 case Core::HID::NpadStyleIndex::JoyconRight: 200 case Core::HID::NpadStyleIndex::JoyconRight:
197 shared_memory.style_tag.joycon_right.Assign(1); 201 shared_memory->style_tag.joycon_right.Assign(1);
198 shared_memory.device_type.joycon_right.Assign(1); 202 shared_memory->device_type.joycon_right.Assign(1);
199 shared_memory.system_properties.is_horizontal.Assign(1); 203 shared_memory->system_properties.is_horizontal.Assign(1);
200 shared_memory.system_properties.use_plus.Assign(1); 204 shared_memory->system_properties.use_plus.Assign(1);
201 shared_memory.applet_footer.type = AppletFooterUiType::JoyRightHorizontal; 205 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyRightHorizontal;
202 break; 206 break;
203 case Core::HID::NpadStyleIndex::GameCube: 207 case Core::HID::NpadStyleIndex::GameCube:
204 shared_memory.style_tag.gamecube.Assign(1); 208 shared_memory->style_tag.gamecube.Assign(1);
205 shared_memory.device_type.fullkey.Assign(1); 209 shared_memory->device_type.fullkey.Assign(1);
206 shared_memory.system_properties.is_vertical.Assign(1); 210 shared_memory->system_properties.is_vertical.Assign(1);
207 shared_memory.system_properties.use_plus.Assign(1); 211 shared_memory->system_properties.use_plus.Assign(1);
208 break; 212 break;
209 case Core::HID::NpadStyleIndex::Pokeball: 213 case Core::HID::NpadStyleIndex::Pokeball:
210 shared_memory.style_tag.palma.Assign(1); 214 shared_memory->style_tag.palma.Assign(1);
211 shared_memory.device_type.palma.Assign(1); 215 shared_memory->device_type.palma.Assign(1);
212 break; 216 break;
213 case Core::HID::NpadStyleIndex::NES: 217 case Core::HID::NpadStyleIndex::NES:
214 shared_memory.style_tag.lark.Assign(1); 218 shared_memory->style_tag.lark.Assign(1);
215 shared_memory.device_type.fullkey.Assign(1); 219 shared_memory->device_type.fullkey.Assign(1);
216 break; 220 break;
217 case Core::HID::NpadStyleIndex::SNES: 221 case Core::HID::NpadStyleIndex::SNES:
218 shared_memory.style_tag.lucia.Assign(1); 222 shared_memory->style_tag.lucia.Assign(1);
219 shared_memory.device_type.fullkey.Assign(1); 223 shared_memory->device_type.fullkey.Assign(1);
220 shared_memory.applet_footer.type = AppletFooterUiType::Lucia; 224 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::Lucia;
221 break; 225 break;
222 case Core::HID::NpadStyleIndex::N64: 226 case Core::HID::NpadStyleIndex::N64:
223 shared_memory.style_tag.lagoon.Assign(1); 227 shared_memory->style_tag.lagoon.Assign(1);
224 shared_memory.device_type.fullkey.Assign(1); 228 shared_memory->device_type.fullkey.Assign(1);
225 shared_memory.applet_footer.type = AppletFooterUiType::Lagon; 229 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::Lagon;
226 break; 230 break;
227 case Core::HID::NpadStyleIndex::SegaGenesis: 231 case Core::HID::NpadStyleIndex::SegaGenesis:
228 shared_memory.style_tag.lager.Assign(1); 232 shared_memory->style_tag.lager.Assign(1);
229 shared_memory.device_type.fullkey.Assign(1); 233 shared_memory->device_type.fullkey.Assign(1);
230 break; 234 break;
231 default: 235 default:
232 break; 236 break;
@@ -234,23 +238,23 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
234 238
235 const auto& body_colors = controller.device->GetColors(); 239 const auto& body_colors = controller.device->GetColors();
236 240
237 shared_memory.fullkey_color.attribute = ColorAttribute::Ok; 241 shared_memory->fullkey_color.attribute = ColorAttribute::Ok;
238 shared_memory.fullkey_color.fullkey = body_colors.fullkey; 242 shared_memory->fullkey_color.fullkey = body_colors.fullkey;
239 243
240 shared_memory.joycon_color.attribute = ColorAttribute::Ok; 244 shared_memory->joycon_color.attribute = ColorAttribute::Ok;
241 shared_memory.joycon_color.left = body_colors.left; 245 shared_memory->joycon_color.left = body_colors.left;
242 shared_memory.joycon_color.right = body_colors.right; 246 shared_memory->joycon_color.right = body_colors.right;
243 247
244 // TODO: Investigate when we should report all batery types 248 // TODO: Investigate when we should report all batery types
245 const auto& battery_level = controller.device->GetBattery(); 249 const auto& battery_level = controller.device->GetBattery();
246 shared_memory.battery_level_dual = battery_level.dual.battery_level; 250 shared_memory->battery_level_dual = battery_level.dual.battery_level;
247 shared_memory.battery_level_left = battery_level.left.battery_level; 251 shared_memory->battery_level_left = battery_level.left.battery_level;
248 shared_memory.battery_level_right = battery_level.right.battery_level; 252 shared_memory->battery_level_right = battery_level.right.battery_level;
249 253
250 controller.is_connected = true; 254 controller.is_connected = true;
251 controller.device->Connect(); 255 controller.device->Connect();
252 SignalStyleSetChangedEvent(npad_id); 256 SignalStyleSetChangedEvent(npad_id);
253 WriteEmptyEntry(controller.shared_memory_entry); 257 WriteEmptyEntry(controller.shared_memory);
254} 258}
255 259
256void Controller_NPad::OnInit() { 260void Controller_NPad::OnInit() {
@@ -270,12 +274,12 @@ void Controller_NPad::OnInit() {
270 274
271 // Prefill controller buffers 275 // Prefill controller buffers
272 for (auto& controller : controller_data) { 276 for (auto& controller : controller_data) {
273 auto& npad = controller.shared_memory_entry; 277 auto* npad = controller.shared_memory;
274 npad.fullkey_color = { 278 npad->fullkey_color = {
275 .attribute = ColorAttribute::NoController, 279 .attribute = ColorAttribute::NoController,
276 .fullkey = {}, 280 .fullkey = {},
277 }; 281 };
278 npad.joycon_color = { 282 npad->joycon_color = {
279 .attribute = ColorAttribute::NoController, 283 .attribute = ColorAttribute::NoController,
280 .left = {}, 284 .left = {},
281 .right = {}, 285 .right = {},
@@ -287,25 +291,25 @@ void Controller_NPad::OnInit() {
287 } 291 }
288} 292}
289 293
290void Controller_NPad::WriteEmptyEntry(NpadInternalState& npad) { 294void Controller_NPad::WriteEmptyEntry(NpadInternalState* npad) {
291 NPadGenericState dummy_pad_state{}; 295 NPadGenericState dummy_pad_state{};
292 NpadGcTriggerState dummy_gc_state{}; 296 NpadGcTriggerState dummy_gc_state{};
293 dummy_pad_state.sampling_number = npad.fullkey_lifo.ReadCurrentEntry().sampling_number + 1; 297 dummy_pad_state.sampling_number = npad->fullkey_lifo.ReadCurrentEntry().sampling_number + 1;
294 npad.fullkey_lifo.WriteNextEntry(dummy_pad_state); 298 npad->fullkey_lifo.WriteNextEntry(dummy_pad_state);
295 dummy_pad_state.sampling_number = npad.handheld_lifo.ReadCurrentEntry().sampling_number + 1; 299 dummy_pad_state.sampling_number = npad->handheld_lifo.ReadCurrentEntry().sampling_number + 1;
296 npad.handheld_lifo.WriteNextEntry(dummy_pad_state); 300 npad->handheld_lifo.WriteNextEntry(dummy_pad_state);
297 dummy_pad_state.sampling_number = npad.joy_dual_lifo.ReadCurrentEntry().sampling_number + 1; 301 dummy_pad_state.sampling_number = npad->joy_dual_lifo.ReadCurrentEntry().sampling_number + 1;
298 npad.joy_dual_lifo.WriteNextEntry(dummy_pad_state); 302 npad->joy_dual_lifo.WriteNextEntry(dummy_pad_state);
299 dummy_pad_state.sampling_number = npad.joy_left_lifo.ReadCurrentEntry().sampling_number + 1; 303 dummy_pad_state.sampling_number = npad->joy_left_lifo.ReadCurrentEntry().sampling_number + 1;
300 npad.joy_left_lifo.WriteNextEntry(dummy_pad_state); 304 npad->joy_left_lifo.WriteNextEntry(dummy_pad_state);
301 dummy_pad_state.sampling_number = npad.joy_right_lifo.ReadCurrentEntry().sampling_number + 1; 305 dummy_pad_state.sampling_number = npad->joy_right_lifo.ReadCurrentEntry().sampling_number + 1;
302 npad.joy_right_lifo.WriteNextEntry(dummy_pad_state); 306 npad->joy_right_lifo.WriteNextEntry(dummy_pad_state);
303 dummy_pad_state.sampling_number = npad.palma_lifo.ReadCurrentEntry().sampling_number + 1; 307 dummy_pad_state.sampling_number = npad->palma_lifo.ReadCurrentEntry().sampling_number + 1;
304 npad.palma_lifo.WriteNextEntry(dummy_pad_state); 308 npad->palma_lifo.WriteNextEntry(dummy_pad_state);
305 dummy_pad_state.sampling_number = npad.system_ext_lifo.ReadCurrentEntry().sampling_number + 1; 309 dummy_pad_state.sampling_number = npad->system_ext_lifo.ReadCurrentEntry().sampling_number + 1;
306 npad.system_ext_lifo.WriteNextEntry(dummy_pad_state); 310 npad->system_ext_lifo.WriteNextEntry(dummy_pad_state);
307 dummy_gc_state.sampling_number = npad.gc_trigger_lifo.ReadCurrentEntry().sampling_number + 1; 311 dummy_gc_state.sampling_number = npad->gc_trigger_lifo.ReadCurrentEntry().sampling_number + 1;
308 npad.gc_trigger_lifo.WriteNextEntry(dummy_gc_state); 312 npad->gc_trigger_lifo.WriteNextEntry(dummy_gc_state);
309} 313}
310 314
311void Controller_NPad::OnRelease() { 315void Controller_NPad::OnRelease() {
@@ -371,23 +375,19 @@ void Controller_NPad::RequestPadStateUpdate(Core::HID::NpadIdType npad_id) {
371 } 375 }
372} 376}
373 377
374void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, 378void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
375 std::size_t data_len) {
376 if (!IsControllerActivated()) { 379 if (!IsControllerActivated()) {
377 return; 380 return;
378 } 381 }
379 382
380 for (std::size_t i = 0; i < controller_data.size(); ++i) { 383 for (std::size_t i = 0; i < controller_data.size(); ++i) {
381 auto& controller = controller_data[i]; 384 auto& controller = controller_data[i];
382 auto& npad = controller.shared_memory_entry; 385 auto* npad = controller.shared_memory;
383 386
384 const auto& controller_type = controller.device->GetNpadStyleIndex(); 387 const auto& controller_type = controller.device->GetNpadStyleIndex();
385 388
386 if (controller_type == Core::HID::NpadStyleIndex::None || 389 if (controller_type == Core::HID::NpadStyleIndex::None ||
387 !controller.device->IsConnected()) { 390 !controller.device->IsConnected()) {
388 // Refresh shared memory
389 std::memcpy(data + NPAD_OFFSET + (i * sizeof(NpadInternalState)),
390 &controller.shared_memory_entry, sizeof(NpadInternalState));
391 continue; 391 continue;
392 } 392 }
393 393
@@ -415,8 +415,8 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
415 415
416 libnx_state.connection_status.is_wired.Assign(1); 416 libnx_state.connection_status.is_wired.Assign(1);
417 pad_state.sampling_number = 417 pad_state.sampling_number =
418 npad.fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; 418 npad->fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1;
419 npad.fullkey_lifo.WriteNextEntry(pad_state); 419 npad->fullkey_lifo.WriteNextEntry(pad_state);
420 break; 420 break;
421 case Core::HID::NpadStyleIndex::Handheld: 421 case Core::HID::NpadStyleIndex::Handheld:
422 pad_state.connection_status.raw = 0; 422 pad_state.connection_status.raw = 0;
@@ -433,8 +433,8 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
433 libnx_state.connection_status.is_left_wired.Assign(1); 433 libnx_state.connection_status.is_left_wired.Assign(1);
434 libnx_state.connection_status.is_right_wired.Assign(1); 434 libnx_state.connection_status.is_right_wired.Assign(1);
435 pad_state.sampling_number = 435 pad_state.sampling_number =
436 npad.handheld_lifo.ReadCurrentEntry().state.sampling_number + 1; 436 npad->handheld_lifo.ReadCurrentEntry().state.sampling_number + 1;
437 npad.handheld_lifo.WriteNextEntry(pad_state); 437 npad->handheld_lifo.WriteNextEntry(pad_state);
438 break; 438 break;
439 case Core::HID::NpadStyleIndex::JoyconDual: 439 case Core::HID::NpadStyleIndex::JoyconDual:
440 pad_state.connection_status.raw = 0; 440 pad_state.connection_status.raw = 0;
@@ -449,8 +449,8 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
449 } 449 }
450 450
451 pad_state.sampling_number = 451 pad_state.sampling_number =
452 npad.joy_dual_lifo.ReadCurrentEntry().state.sampling_number + 1; 452 npad->joy_dual_lifo.ReadCurrentEntry().state.sampling_number + 1;
453 npad.joy_dual_lifo.WriteNextEntry(pad_state); 453 npad->joy_dual_lifo.WriteNextEntry(pad_state);
454 break; 454 break;
455 case Core::HID::NpadStyleIndex::JoyconLeft: 455 case Core::HID::NpadStyleIndex::JoyconLeft:
456 pad_state.connection_status.raw = 0; 456 pad_state.connection_status.raw = 0;
@@ -459,8 +459,8 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
459 459
460 libnx_state.connection_status.is_left_connected.Assign(1); 460 libnx_state.connection_status.is_left_connected.Assign(1);
461 pad_state.sampling_number = 461 pad_state.sampling_number =
462 npad.joy_left_lifo.ReadCurrentEntry().state.sampling_number + 1; 462 npad->joy_left_lifo.ReadCurrentEntry().state.sampling_number + 1;
463 npad.joy_left_lifo.WriteNextEntry(pad_state); 463 npad->joy_left_lifo.WriteNextEntry(pad_state);
464 break; 464 break;
465 case Core::HID::NpadStyleIndex::JoyconRight: 465 case Core::HID::NpadStyleIndex::JoyconRight:
466 pad_state.connection_status.raw = 0; 466 pad_state.connection_status.raw = 0;
@@ -469,8 +469,8 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
469 469
470 libnx_state.connection_status.is_right_connected.Assign(1); 470 libnx_state.connection_status.is_right_connected.Assign(1);
471 pad_state.sampling_number = 471 pad_state.sampling_number =
472 npad.joy_right_lifo.ReadCurrentEntry().state.sampling_number + 1; 472 npad->joy_right_lifo.ReadCurrentEntry().state.sampling_number + 1;
473 npad.joy_right_lifo.WriteNextEntry(pad_state); 473 npad->joy_right_lifo.WriteNextEntry(pad_state);
474 break; 474 break;
475 case Core::HID::NpadStyleIndex::GameCube: 475 case Core::HID::NpadStyleIndex::GameCube:
476 pad_state.connection_status.raw = 0; 476 pad_state.connection_status.raw = 0;
@@ -479,18 +479,18 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
479 479
480 libnx_state.connection_status.is_wired.Assign(1); 480 libnx_state.connection_status.is_wired.Assign(1);
481 pad_state.sampling_number = 481 pad_state.sampling_number =
482 npad.fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; 482 npad->fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1;
483 trigger_state.sampling_number = 483 trigger_state.sampling_number =
484 npad.gc_trigger_lifo.ReadCurrentEntry().state.sampling_number + 1; 484 npad->gc_trigger_lifo.ReadCurrentEntry().state.sampling_number + 1;
485 npad.fullkey_lifo.WriteNextEntry(pad_state); 485 npad->fullkey_lifo.WriteNextEntry(pad_state);
486 npad.gc_trigger_lifo.WriteNextEntry(trigger_state); 486 npad->gc_trigger_lifo.WriteNextEntry(trigger_state);
487 break; 487 break;
488 case Core::HID::NpadStyleIndex::Pokeball: 488 case Core::HID::NpadStyleIndex::Pokeball:
489 pad_state.connection_status.raw = 0; 489 pad_state.connection_status.raw = 0;
490 pad_state.connection_status.is_connected.Assign(1); 490 pad_state.connection_status.is_connected.Assign(1);
491 pad_state.sampling_number = 491 pad_state.sampling_number =
492 npad.palma_lifo.ReadCurrentEntry().state.sampling_number + 1; 492 npad->palma_lifo.ReadCurrentEntry().state.sampling_number + 1;
493 npad.palma_lifo.WriteNextEntry(pad_state); 493 npad->palma_lifo.WriteNextEntry(pad_state);
494 break; 494 break;
495 default: 495 default:
496 break; 496 break;
@@ -499,17 +499,13 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
499 libnx_state.npad_buttons.raw = pad_state.npad_buttons.raw; 499 libnx_state.npad_buttons.raw = pad_state.npad_buttons.raw;
500 libnx_state.l_stick = pad_state.l_stick; 500 libnx_state.l_stick = pad_state.l_stick;
501 libnx_state.r_stick = pad_state.r_stick; 501 libnx_state.r_stick = pad_state.r_stick;
502 npad.system_ext_lifo.WriteNextEntry(pad_state); 502 npad->system_ext_lifo.WriteNextEntry(pad_state);
503 503
504 press_state |= static_cast<u64>(pad_state.npad_buttons.raw); 504 press_state |= static_cast<u64>(pad_state.npad_buttons.raw);
505
506 std::memcpy(data + NPAD_OFFSET + (i * sizeof(NpadInternalState)),
507 &controller.shared_memory_entry, sizeof(NpadInternalState));
508 } 505 }
509} 506}
510 507
511void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, 508void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing) {
512 std::size_t data_len) {
513 if (!IsControllerActivated()) { 509 if (!IsControllerActivated()) {
514 return; 510 return;
515 } 511 }
@@ -524,7 +520,7 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing
524 continue; 520 continue;
525 } 521 }
526 522
527 auto& npad = controller.shared_memory_entry; 523 auto* npad = controller.shared_memory;
528 const auto& motion_state = controller.device->GetMotions(); 524 const auto& motion_state = controller.device->GetMotions();
529 auto& sixaxis_fullkey_state = controller.sixaxis_fullkey_state; 525 auto& sixaxis_fullkey_state = controller.sixaxis_fullkey_state;
530 auto& sixaxis_handheld_state = controller.sixaxis_handheld_state; 526 auto& sixaxis_handheld_state = controller.sixaxis_handheld_state;
@@ -610,32 +606,30 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing
610 } 606 }
611 607
612 sixaxis_fullkey_state.sampling_number = 608 sixaxis_fullkey_state.sampling_number =
613 npad.sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; 609 npad->sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1;
614 sixaxis_handheld_state.sampling_number = 610 sixaxis_handheld_state.sampling_number =
615 npad.sixaxis_handheld_lifo.ReadCurrentEntry().state.sampling_number + 1; 611 npad->sixaxis_handheld_lifo.ReadCurrentEntry().state.sampling_number + 1;
616 sixaxis_dual_left_state.sampling_number = 612 sixaxis_dual_left_state.sampling_number =
617 npad.sixaxis_dual_left_lifo.ReadCurrentEntry().state.sampling_number + 1; 613 npad->sixaxis_dual_left_lifo.ReadCurrentEntry().state.sampling_number + 1;
618 sixaxis_dual_right_state.sampling_number = 614 sixaxis_dual_right_state.sampling_number =
619 npad.sixaxis_dual_right_lifo.ReadCurrentEntry().state.sampling_number + 1; 615 npad->sixaxis_dual_right_lifo.ReadCurrentEntry().state.sampling_number + 1;
620 sixaxis_left_lifo_state.sampling_number = 616 sixaxis_left_lifo_state.sampling_number =
621 npad.sixaxis_left_lifo.ReadCurrentEntry().state.sampling_number + 1; 617 npad->sixaxis_left_lifo.ReadCurrentEntry().state.sampling_number + 1;
622 sixaxis_right_lifo_state.sampling_number = 618 sixaxis_right_lifo_state.sampling_number =
623 npad.sixaxis_right_lifo.ReadCurrentEntry().state.sampling_number + 1; 619 npad->sixaxis_right_lifo.ReadCurrentEntry().state.sampling_number + 1;
624 620
625 if (Core::HID::IndexToNpadIdType(i) == Core::HID::NpadIdType::Handheld) { 621 if (Core::HID::IndexToNpadIdType(i) == Core::HID::NpadIdType::Handheld) {
626 // This buffer only is updated on handheld on HW 622 // This buffer only is updated on handheld on HW
627 npad.sixaxis_handheld_lifo.WriteNextEntry(sixaxis_handheld_state); 623 npad->sixaxis_handheld_lifo.WriteNextEntry(sixaxis_handheld_state);
628 } else { 624 } else {
629 // Handheld doesn't update this buffer on HW 625 // Handheld doesn't update this buffer on HW
630 npad.sixaxis_fullkey_lifo.WriteNextEntry(sixaxis_fullkey_state); 626 npad->sixaxis_fullkey_lifo.WriteNextEntry(sixaxis_fullkey_state);
631 } 627 }
632 628
633 npad.sixaxis_dual_left_lifo.WriteNextEntry(sixaxis_dual_left_state); 629 npad->sixaxis_dual_left_lifo.WriteNextEntry(sixaxis_dual_left_state);
634 npad.sixaxis_dual_right_lifo.WriteNextEntry(sixaxis_dual_right_state); 630 npad->sixaxis_dual_right_lifo.WriteNextEntry(sixaxis_dual_right_state);
635 npad.sixaxis_left_lifo.WriteNextEntry(sixaxis_left_lifo_state); 631 npad->sixaxis_left_lifo.WriteNextEntry(sixaxis_left_lifo_state);
636 npad.sixaxis_right_lifo.WriteNextEntry(sixaxis_right_lifo_state); 632 npad->sixaxis_right_lifo.WriteNextEntry(sixaxis_right_lifo_state);
637 std::memcpy(data + NPAD_OFFSET + (i * sizeof(NpadInternalState)),
638 &controller.shared_memory_entry, sizeof(NpadInternalState));
639 } 633 }
640} 634}
641 635
@@ -713,8 +707,8 @@ void Controller_NPad::SetNpadMode(Core::HID::NpadIdType npad_id, NpadJoyDeviceTy
713 } 707 }
714 708
715 auto& controller = GetControllerFromNpadIdType(npad_id); 709 auto& controller = GetControllerFromNpadIdType(npad_id);
716 if (controller.shared_memory_entry.assignment_mode != assignment_mode) { 710 if (controller.shared_memory->assignment_mode != assignment_mode) {
717 controller.shared_memory_entry.assignment_mode = assignment_mode; 711 controller.shared_memory->assignment_mode = assignment_mode;
718 } 712 }
719 713
720 if (!controller.device->IsConnected()) { 714 if (!controller.device->IsConnected()) {
@@ -981,32 +975,32 @@ void Controller_NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) {
981 controller.vibration[device_idx].device_mounted = false; 975 controller.vibration[device_idx].device_mounted = false;
982 } 976 }
983 977
984 auto& shared_memory_entry = controller.shared_memory_entry; 978 auto* shared_memory = controller.shared_memory;
985 // Don't reset shared_memory_entry.assignment_mode this value is persistent 979 // Don't reset shared_memory->assignment_mode this value is persistent
986 shared_memory_entry.style_tag.raw = Core::HID::NpadStyleSet::None; // Zero out 980 shared_memory->style_tag.raw = Core::HID::NpadStyleSet::None; // Zero out
987 shared_memory_entry.device_type.raw = 0; 981 shared_memory->device_type.raw = 0;
988 shared_memory_entry.system_properties.raw = 0; 982 shared_memory->system_properties.raw = 0;
989 shared_memory_entry.button_properties.raw = 0; 983 shared_memory->button_properties.raw = 0;
990 shared_memory_entry.battery_level_dual = 0; 984 shared_memory->battery_level_dual = 0;
991 shared_memory_entry.battery_level_left = 0; 985 shared_memory->battery_level_left = 0;
992 shared_memory_entry.battery_level_right = 0; 986 shared_memory->battery_level_right = 0;
993 shared_memory_entry.fullkey_color = { 987 shared_memory->fullkey_color = {
994 .attribute = ColorAttribute::NoController, 988 .attribute = ColorAttribute::NoController,
995 .fullkey = {}, 989 .fullkey = {},
996 }; 990 };
997 shared_memory_entry.joycon_color = { 991 shared_memory->joycon_color = {
998 .attribute = ColorAttribute::NoController, 992 .attribute = ColorAttribute::NoController,
999 .left = {}, 993 .left = {},
1000 .right = {}, 994 .right = {},
1001 }; 995 };
1002 shared_memory_entry.applet_footer.type = AppletFooterUiType::None; 996 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::None;
1003 997
1004 controller.is_dual_left_connected = true; 998 controller.is_dual_left_connected = true;
1005 controller.is_dual_right_connected = true; 999 controller.is_dual_right_connected = true;
1006 controller.is_connected = false; 1000 controller.is_connected = false;
1007 controller.device->Disconnect(); 1001 controller.device->Disconnect();
1008 SignalStyleSetChangedEvent(npad_id); 1002 SignalStyleSetChangedEvent(npad_id);
1009 WriteEmptyEntry(controller.shared_memory_entry); 1003 WriteEmptyEntry(shared_memory);
1010} 1004}
1011 1005
1012ResultCode Controller_NPad::SetGyroscopeZeroDriftMode(Core::HID::SixAxisSensorHandle sixaxis_handle, 1006ResultCode Controller_NPad::SetGyroscopeZeroDriftMode(Core::HID::SixAxisSensorHandle sixaxis_handle,
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index b42532b68..0a96825a5 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -35,7 +35,7 @@ namespace Service::HID {
35 35
36class Controller_NPad final : public ControllerBase { 36class Controller_NPad final : public ControllerBase {
37public: 37public:
38 explicit Controller_NPad(Core::HID::HIDCore& hid_core_, 38 explicit Controller_NPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_,
39 KernelHelpers::ServiceContext& service_context_); 39 KernelHelpers::ServiceContext& service_context_);
40 ~Controller_NPad() override; 40 ~Controller_NPad() override;
41 41
@@ -46,11 +46,10 @@ public:
46 void OnRelease() override; 46 void OnRelease() override;
47 47
48 // When the controller is requesting an update for the shared memory 48 // When the controller is requesting an update for the shared memory
49 void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; 49 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
50 50
51 // When the controller is requesting a motion update for the shared memory 51 // When the controller is requesting a motion update for the shared memory
52 void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, 52 void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing) override;
53 std::size_t size) override;
54 53
55 // This is nn::hid::GyroscopeZeroDriftMode 54 // This is nn::hid::GyroscopeZeroDriftMode
56 enum class GyroscopeZeroDriftMode : u32 { 55 enum class GyroscopeZeroDriftMode : u32 {
@@ -188,6 +187,8 @@ public:
188 static bool IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle); 187 static bool IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle);
189 188
190private: 189private:
190 static constexpr std::size_t NPAD_COUNT = 10;
191
191 // This is nn::hid::detail::ColorAttribute 192 // This is nn::hid::detail::ColorAttribute
192 enum class ColorAttribute : u32 { 193 enum class ColorAttribute : u32 {
193 Ok = 0, 194 Ok = 0,
@@ -409,6 +410,13 @@ private:
409 U, 410 U,
410 }; 411 };
411 412
413 struct AppletNfcXcd {
414 union {
415 AppletFooterUi applet_footer{};
416 Lifo<NfcXcdDeviceHandleStateImpl, 0x2> nfc_xcd_device_lifo;
417 };
418 };
419
412 // This is nn::hid::detail::NpadInternalState 420 // This is nn::hid::detail::NpadInternalState
413 struct NpadInternalState { 421 struct NpadInternalState {
414 Core::HID::NpadStyleTag style_tag{Core::HID::NpadStyleSet::None}; 422 Core::HID::NpadStyleTag style_tag{Core::HID::NpadStyleSet::None};
@@ -435,10 +443,7 @@ private:
435 Core::HID::NpadBatteryLevel battery_level_dual{}; 443 Core::HID::NpadBatteryLevel battery_level_dual{};
436 Core::HID::NpadBatteryLevel battery_level_left{}; 444 Core::HID::NpadBatteryLevel battery_level_left{};
437 Core::HID::NpadBatteryLevel battery_level_right{}; 445 Core::HID::NpadBatteryLevel battery_level_right{};
438 union { 446 AppletNfcXcd applet_nfc_xcd{};
439 AppletFooterUi applet_footer{};
440 Lifo<NfcXcdDeviceHandleStateImpl, 0x2> nfc_xcd_device_lifo;
441 };
442 INSERT_PADDING_BYTES(0x20); // Unknown 447 INSERT_PADDING_BYTES(0x20); // Unknown
443 Lifo<NpadGcTriggerState, hid_entry_count> gc_trigger_lifo{}; 448 Lifo<NpadGcTriggerState, hid_entry_count> gc_trigger_lifo{};
444 NpadLarkType lark_type_l_and_main{}; 449 NpadLarkType lark_type_l_and_main{};
@@ -465,9 +470,9 @@ private:
465 }; 470 };
466 471
467 struct NpadControllerData { 472 struct NpadControllerData {
468 Core::HID::EmulatedController* device;
469 Kernel::KEvent* styleset_changed_event{}; 473 Kernel::KEvent* styleset_changed_event{};
470 NpadInternalState shared_memory_entry{}; 474 NpadInternalState* shared_memory = nullptr;
475 Core::HID::EmulatedController* device = nullptr;
471 476
472 std::array<VibrationData, 2> vibration{}; 477 std::array<VibrationData, 2> vibration{};
473 bool unintended_home_button_input_protection{}; 478 bool unintended_home_button_input_protection{};
@@ -497,15 +502,14 @@ private:
497 SixAxisSensorState sixaxis_dual_right_state{}; 502 SixAxisSensorState sixaxis_dual_right_state{};
498 SixAxisSensorState sixaxis_left_lifo_state{}; 503 SixAxisSensorState sixaxis_left_lifo_state{};
499 SixAxisSensorState sixaxis_right_lifo_state{}; 504 SixAxisSensorState sixaxis_right_lifo_state{};
500 505 int callback_key{};
501 int callback_key;
502 }; 506 };
503 507
504 void ControllerUpdate(Core::HID::ControllerTriggerType type, std::size_t controller_idx); 508 void ControllerUpdate(Core::HID::ControllerTriggerType type, std::size_t controller_idx);
505 void InitNewlyAddedController(Core::HID::NpadIdType npad_id); 509 void InitNewlyAddedController(Core::HID::NpadIdType npad_id);
506 bool IsControllerSupported(Core::HID::NpadStyleIndex controller) const; 510 bool IsControllerSupported(Core::HID::NpadStyleIndex controller) const;
507 void RequestPadStateUpdate(Core::HID::NpadIdType npad_id); 511 void RequestPadStateUpdate(Core::HID::NpadIdType npad_id);
508 void WriteEmptyEntry(NpadInternalState& npad); 512 void WriteEmptyEntry(NpadInternalState* npad);
509 513
510 NpadControllerData& GetControllerFromHandle( 514 NpadControllerData& GetControllerFromHandle(
511 const Core::HID::SixAxisSensorHandle& device_handle); 515 const Core::HID::SixAxisSensorHandle& device_handle);
@@ -520,7 +524,7 @@ private:
520 524
521 std::atomic<u64> press_state{}; 525 std::atomic<u64> press_state{};
522 526
523 std::array<NpadControllerData, 10> controller_data{}; 527 std::array<NpadControllerData, NPAD_COUNT> controller_data{};
524 KernelHelpers::ServiceContext& service_context; 528 KernelHelpers::ServiceContext& service_context;
525 std::mutex mutex; 529 std::mutex mutex;
526 std::vector<Core::HID::NpadIdType> supported_npad_id_types{}; 530 std::vector<Core::HID::NpadIdType> supported_npad_id_types{};
diff --git a/src/core/hle/service/hid/controllers/stubbed.cpp b/src/core/hle/service/hid/controllers/stubbed.cpp
index 4d3b9d2be..df9ee0c3f 100644
--- a/src/core/hle/service/hid/controllers/stubbed.cpp
+++ b/src/core/hle/service/hid/controllers/stubbed.cpp
@@ -9,15 +9,18 @@
9 9
10namespace Service::HID { 10namespace Service::HID {
11 11
12Controller_Stubbed::Controller_Stubbed(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {} 12Controller_Stubbed::Controller_Stubbed(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
13 : ControllerBase{hid_core_} {
14 raw_shared_memory = raw_shared_memory_;
15}
16
13Controller_Stubbed::~Controller_Stubbed() = default; 17Controller_Stubbed::~Controller_Stubbed() = default;
14 18
15void Controller_Stubbed::OnInit() {} 19void Controller_Stubbed::OnInit() {}
16 20
17void Controller_Stubbed::OnRelease() {} 21void Controller_Stubbed::OnRelease() {}
18 22
19void Controller_Stubbed::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, 23void Controller_Stubbed::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
20 std::size_t size) {
21 if (!smart_update) { 24 if (!smart_update) {
22 return; 25 return;
23 } 26 }
@@ -28,7 +31,7 @@ void Controller_Stubbed::OnUpdate(const Core::Timing::CoreTiming& core_timing, u
28 header.entry_count = 0; 31 header.entry_count = 0;
29 header.last_entry_index = 0; 32 header.last_entry_index = 0;
30 33
31 std::memcpy(data + common_offset, &header, sizeof(CommonHeader)); 34 std::memcpy(raw_shared_memory + common_offset, &header, sizeof(CommonHeader));
32} 35}
33 36
34void Controller_Stubbed::SetCommonHeaderOffset(std::size_t off) { 37void Controller_Stubbed::SetCommonHeaderOffset(std::size_t off) {
diff --git a/src/core/hle/service/hid/controllers/stubbed.h b/src/core/hle/service/hid/controllers/stubbed.h
index 512066eb3..1483a968e 100644
--- a/src/core/hle/service/hid/controllers/stubbed.h
+++ b/src/core/hle/service/hid/controllers/stubbed.h
@@ -9,7 +9,7 @@
9namespace Service::HID { 9namespace Service::HID {
10class Controller_Stubbed final : public ControllerBase { 10class Controller_Stubbed final : public ControllerBase {
11public: 11public:
12 explicit Controller_Stubbed(Core::HID::HIDCore& hid_core_); 12 explicit Controller_Stubbed(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
13 ~Controller_Stubbed() override; 13 ~Controller_Stubbed() override;
14 14
15 // Called when the controller is initialized 15 // Called when the controller is initialized
@@ -19,19 +19,20 @@ public:
19 void OnRelease() override; 19 void OnRelease() override;
20 20
21 // When the controller is requesting an update for the shared memory 21 // When the controller is requesting an update for the shared memory
22 void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; 22 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
23 23
24 void SetCommonHeaderOffset(std::size_t off); 24 void SetCommonHeaderOffset(std::size_t off);
25 25
26private: 26private:
27 struct CommonHeader { 27 struct CommonHeader {
28 s64 timestamp; 28 s64 timestamp{};
29 s64 total_entry_count; 29 s64 total_entry_count{};
30 s64 last_entry_index; 30 s64 last_entry_index{};
31 s64 entry_count; 31 s64 entry_count{};
32 }; 32 };
33 static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size"); 33 static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size");
34 34
35 u8* raw_shared_memory = nullptr;
35 bool smart_update{}; 36 bool smart_update{};
36 std::size_t common_offset{}; 37 std::size_t common_offset{};
37}; 38};
diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp
index 5b4b51a69..108ce5a41 100644
--- a/src/core/hle/service/hid/controllers/touchscreen.cpp
+++ b/src/core/hle/service/hid/controllers/touchscreen.cpp
@@ -15,8 +15,13 @@
15namespace Service::HID { 15namespace Service::HID {
16constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400; 16constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400;
17 17
18Controller_Touchscreen::Controller_Touchscreen(Core::HID::HIDCore& hid_core_) 18Controller_Touchscreen::Controller_Touchscreen(Core::HID::HIDCore& hid_core_,
19 u8* raw_shared_memory_)
19 : ControllerBase{hid_core_} { 20 : ControllerBase{hid_core_} {
21 static_assert(SHARED_MEMORY_OFFSET + sizeof(TouchSharedMemory) < shared_memory_size,
22 "TouchSharedMemory is bigger than the shared memory");
23 shared_memory = std::construct_at(
24 reinterpret_cast<TouchSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
20 console = hid_core.GetEmulatedConsole(); 25 console = hid_core.GetEmulatedConsole();
21} 26}
22 27
@@ -26,14 +31,12 @@ void Controller_Touchscreen::OnInit() {}
26 31
27void Controller_Touchscreen::OnRelease() {} 32void Controller_Touchscreen::OnRelease() {}
28 33
29void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, 34void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
30 std::size_t size) { 35 shared_memory->touch_screen_lifo.timestamp = core_timing.GetCPUTicks();
31 touch_screen_lifo.timestamp = core_timing.GetCPUTicks();
32 36
33 if (!IsControllerActivated()) { 37 if (!IsControllerActivated()) {
34 touch_screen_lifo.buffer_count = 0; 38 shared_memory->touch_screen_lifo.buffer_count = 0;
35 touch_screen_lifo.buffer_tail = 0; 39 shared_memory->touch_screen_lifo.buffer_tail = 0;
36 std::memcpy(data, &touch_screen_lifo, sizeof(touch_screen_lifo));
37 return; 40 return;
38 } 41 }
39 42
@@ -74,7 +77,7 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin
74 static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter)); 77 static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter));
75 78
76 const u64 tick = core_timing.GetCPUTicks(); 79 const u64 tick = core_timing.GetCPUTicks();
77 const auto& last_entry = touch_screen_lifo.ReadCurrentEntry().state; 80 const auto& last_entry = shared_memory->touch_screen_lifo.ReadCurrentEntry().state;
78 81
79 next_state.sampling_number = last_entry.sampling_number + 1; 82 next_state.sampling_number = last_entry.sampling_number + 1;
80 next_state.entry_count = static_cast<s32>(active_fingers_count); 83 next_state.entry_count = static_cast<s32>(active_fingers_count);
@@ -106,8 +109,7 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin
106 } 109 }
107 } 110 }
108 111
109 touch_screen_lifo.WriteNextEntry(next_state); 112 shared_memory->touch_screen_lifo.WriteNextEntry(next_state);
110 std::memcpy(data + SHARED_MEMORY_OFFSET, &touch_screen_lifo, sizeof(touch_screen_lifo));
111} 113}
112 114
113} // namespace Service::HID 115} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h
index 424973b38..e57a3a80e 100644
--- a/src/core/hle/service/hid/controllers/touchscreen.h
+++ b/src/core/hle/service/hid/controllers/touchscreen.h
@@ -25,14 +25,14 @@ public:
25 25
26 // This is nn::hid::TouchScreenConfigurationForNx 26 // This is nn::hid::TouchScreenConfigurationForNx
27 struct TouchScreenConfigurationForNx { 27 struct TouchScreenConfigurationForNx {
28 TouchScreenModeForNx mode; 28 TouchScreenModeForNx mode{TouchScreenModeForNx::UseSystemSetting};
29 INSERT_PADDING_BYTES_NOINIT(0x7); 29 INSERT_PADDING_BYTES_NOINIT(0x7);
30 INSERT_PADDING_BYTES_NOINIT(0xF); // Reserved 30 INSERT_PADDING_BYTES_NOINIT(0xF); // Reserved
31 }; 31 };
32 static_assert(sizeof(TouchScreenConfigurationForNx) == 0x17, 32 static_assert(sizeof(TouchScreenConfigurationForNx) == 0x17,
33 "TouchScreenConfigurationForNx is an invalid size"); 33 "TouchScreenConfigurationForNx is an invalid size");
34 34
35 explicit Controller_Touchscreen(Core::HID::HIDCore& hid_core_); 35 explicit Controller_Touchscreen(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
36 ~Controller_Touchscreen() override; 36 ~Controller_Touchscreen() override;
37 37
38 // Called when the controller is initialized 38 // Called when the controller is initialized
@@ -42,26 +42,32 @@ public:
42 void OnRelease() override; 42 void OnRelease() override;
43 43
44 // When the controller is requesting an update for the shared memory 44 // When the controller is requesting an update for the shared memory
45 void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; 45 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
46 46
47private: 47private:
48 static constexpr std::size_t MAX_FINGERS = 16; 48 static constexpr std::size_t MAX_FINGERS = 16;
49 49
50 // This is nn::hid::TouchScreenState 50 // This is nn::hid::TouchScreenState
51 struct TouchScreenState { 51 struct TouchScreenState {
52 s64 sampling_number; 52 s64 sampling_number{};
53 s32 entry_count; 53 s32 entry_count{};
54 INSERT_PADDING_BYTES(4); // Reserved 54 INSERT_PADDING_BYTES(4); // Reserved
55 std::array<Core::HID::TouchState, MAX_FINGERS> states; 55 std::array<Core::HID::TouchState, MAX_FINGERS> states{};
56 }; 56 };
57 static_assert(sizeof(TouchScreenState) == 0x290, "TouchScreenState is an invalid size"); 57 static_assert(sizeof(TouchScreenState) == 0x290, "TouchScreenState is an invalid size");
58 58
59 // This is nn::hid::detail::TouchScreenLifo 59 struct TouchSharedMemory {
60 Lifo<TouchScreenState, hid_entry_count> touch_screen_lifo{}; 60 // This is nn::hid::detail::TouchScreenLifo
61 static_assert(sizeof(touch_screen_lifo) == 0x2C38, "touch_screen_lifo is an invalid size"); 61 Lifo<TouchScreenState, hid_entry_count> touch_screen_lifo{};
62 static_assert(sizeof(touch_screen_lifo) == 0x2C38, "touch_screen_lifo is an invalid size");
63 INSERT_PADDING_WORDS(0xF2);
64 };
65 static_assert(sizeof(TouchSharedMemory) == 0x3000, "TouchSharedMemory is an invalid size");
66
62 TouchScreenState next_state{}; 67 TouchScreenState next_state{};
68 TouchSharedMemory* shared_memory = nullptr;
69 Core::HID::EmulatedConsole* console = nullptr;
63 70
64 std::array<Core::HID::TouchFinger, MAX_FINGERS> fingers; 71 std::array<Core::HID::TouchFinger, MAX_FINGERS> fingers{};
65 Core::HID::EmulatedConsole* console;
66}; 72};
67} // namespace Service::HID 73} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/xpad.cpp b/src/core/hle/service/hid/controllers/xpad.cpp
index fc6ac6457..62119e2c5 100644
--- a/src/core/hle/service/hid/controllers/xpad.cpp
+++ b/src/core/hle/service/hid/controllers/xpad.cpp
@@ -10,28 +10,31 @@
10namespace Service::HID { 10namespace Service::HID {
11constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C00; 11constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C00;
12 12
13Controller_XPad::Controller_XPad(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {} 13Controller_XPad::Controller_XPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
14 : ControllerBase{hid_core_} {
15 static_assert(SHARED_MEMORY_OFFSET + sizeof(XpadSharedMemory) < shared_memory_size,
16 "XpadSharedMemory is bigger than the shared memory");
17 shared_memory = std::construct_at(
18 reinterpret_cast<XpadSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
19}
14Controller_XPad::~Controller_XPad() = default; 20Controller_XPad::~Controller_XPad() = default;
15 21
16void Controller_XPad::OnInit() {} 22void Controller_XPad::OnInit() {}
17 23
18void Controller_XPad::OnRelease() {} 24void Controller_XPad::OnRelease() {}
19 25
20void Controller_XPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, 26void Controller_XPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
21 std::size_t size) {
22 if (!IsControllerActivated()) { 27 if (!IsControllerActivated()) {
23 basic_xpad_lifo.buffer_count = 0; 28 shared_memory->basic_xpad_lifo.buffer_count = 0;
24 basic_xpad_lifo.buffer_tail = 0; 29 shared_memory->basic_xpad_lifo.buffer_tail = 0;
25 std::memcpy(data + SHARED_MEMORY_OFFSET, &basic_xpad_lifo, sizeof(basic_xpad_lifo));
26 return; 30 return;
27 } 31 }
28 32
29 const auto& last_entry = basic_xpad_lifo.ReadCurrentEntry().state; 33 const auto& last_entry = shared_memory->basic_xpad_lifo.ReadCurrentEntry().state;
30 next_state.sampling_number = last_entry.sampling_number + 1; 34 next_state.sampling_number = last_entry.sampling_number + 1;
31 // TODO(ogniK): Update xpad states 35 // TODO(ogniK): Update xpad states
32 36
33 basic_xpad_lifo.WriteNextEntry(next_state); 37 shared_memory->basic_xpad_lifo.WriteNextEntry(next_state);
34 std::memcpy(data + SHARED_MEMORY_OFFSET, &basic_xpad_lifo, sizeof(basic_xpad_lifo));
35} 38}
36 39
37} // namespace Service::HID 40} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/xpad.h b/src/core/hle/service/hid/controllers/xpad.h
index 8211b6ee3..d01dee5fc 100644
--- a/src/core/hle/service/hid/controllers/xpad.h
+++ b/src/core/hle/service/hid/controllers/xpad.h
@@ -12,7 +12,7 @@
12namespace Service::HID { 12namespace Service::HID {
13class Controller_XPad final : public ControllerBase { 13class Controller_XPad final : public ControllerBase {
14public: 14public:
15 explicit Controller_XPad(Core::HID::HIDCore& hid_core_); 15 explicit Controller_XPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
16 ~Controller_XPad() override; 16 ~Controller_XPad() override;
17 17
18 // Called when the controller is initialized 18 // Called when the controller is initialized
@@ -22,7 +22,7 @@ public:
22 void OnRelease() override; 22 void OnRelease() override;
23 23
24 // When the controller is requesting an update for the shared memory 24 // When the controller is requesting an update for the shared memory
25 void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; 25 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
26 26
27private: 27private:
28 // This is nn::hid::BasicXpadAttributeSet 28 // This is nn::hid::BasicXpadAttributeSet
@@ -90,17 +90,23 @@ private:
90 90
91 // This is nn::hid::detail::BasicXpadState 91 // This is nn::hid::detail::BasicXpadState
92 struct BasicXpadState { 92 struct BasicXpadState {
93 s64 sampling_number; 93 s64 sampling_number{};
94 BasicXpadAttributeSet attributes; 94 BasicXpadAttributeSet attributes{};
95 BasicXpadButtonSet pad_states; 95 BasicXpadButtonSet pad_states{};
96 Core::HID::AnalogStickState l_stick; 96 Core::HID::AnalogStickState l_stick{};
97 Core::HID::AnalogStickState r_stick; 97 Core::HID::AnalogStickState r_stick{};
98 }; 98 };
99 static_assert(sizeof(BasicXpadState) == 0x20, "BasicXpadState is an invalid size"); 99 static_assert(sizeof(BasicXpadState) == 0x20, "BasicXpadState is an invalid size");
100 100
101 // This is nn::hid::detail::BasicXpadLifo 101 struct XpadSharedMemory {
102 Lifo<BasicXpadState, hid_entry_count> basic_xpad_lifo{}; 102 // This is nn::hid::detail::BasicXpadLifo
103 static_assert(sizeof(basic_xpad_lifo) == 0x2C8, "basic_xpad_lifo is an invalid size"); 103 Lifo<BasicXpadState, hid_entry_count> basic_xpad_lifo{};
104 static_assert(sizeof(basic_xpad_lifo) == 0x2C8, "basic_xpad_lifo is an invalid size");
105 INSERT_PADDING_WORDS(0x4E);
106 };
107 static_assert(sizeof(XpadSharedMemory) == 0x400, "XpadSharedMemory is an invalid size");
108
104 BasicXpadState next_state{}; 109 BasicXpadState next_state{};
110 XpadSharedMemory* shared_memory = nullptr;
105}; 111};
106} // namespace Service::HID 112} // namespace Service::HID
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index fb1ec52b2..36162ac97 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -39,7 +39,6 @@ constexpr auto pad_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000};
39constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz) 39constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz)
40// TODO: Correct update rate for motion is 5ms. Check why some games don't behave at that speed 40// TODO: Correct update rate for motion is 5ms. Check why some games don't behave at that speed
41constexpr auto motion_update_ns = std::chrono::nanoseconds{10 * 1000 * 1000}; // (10ms, 100Hz) 41constexpr auto motion_update_ns = std::chrono::nanoseconds{10 * 1000 * 1000}; // (10ms, 100Hz)
42constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000;
43 42
44IAppletResource::IAppletResource(Core::System& system_, 43IAppletResource::IAppletResource(Core::System& system_,
45 KernelHelpers::ServiceContext& service_context_) 44 KernelHelpers::ServiceContext& service_context_)
@@ -48,20 +47,20 @@ IAppletResource::IAppletResource(Core::System& system_,
48 {0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"}, 47 {0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"},
49 }; 48 };
50 RegisterHandlers(functions); 49 RegisterHandlers(functions);
51 50 u8* shared_memory = system.Kernel().GetHidSharedMem().GetPointer();
52 MakeController<Controller_DebugPad>(HidController::DebugPad); 51 MakeController<Controller_DebugPad>(HidController::DebugPad, shared_memory);
53 MakeController<Controller_Touchscreen>(HidController::Touchscreen); 52 MakeController<Controller_Touchscreen>(HidController::Touchscreen, shared_memory);
54 MakeController<Controller_Mouse>(HidController::Mouse); 53 MakeController<Controller_Mouse>(HidController::Mouse, shared_memory);
55 MakeController<Controller_Keyboard>(HidController::Keyboard); 54 MakeController<Controller_Keyboard>(HidController::Keyboard, shared_memory);
56 MakeController<Controller_XPad>(HidController::XPad); 55 MakeController<Controller_XPad>(HidController::XPad, shared_memory);
57 MakeController<Controller_Stubbed>(HidController::HomeButton); 56 MakeController<Controller_Stubbed>(HidController::HomeButton, shared_memory);
58 MakeController<Controller_Stubbed>(HidController::SleepButton); 57 MakeController<Controller_Stubbed>(HidController::SleepButton, shared_memory);
59 MakeController<Controller_Stubbed>(HidController::CaptureButton); 58 MakeController<Controller_Stubbed>(HidController::CaptureButton, shared_memory);
60 MakeController<Controller_Stubbed>(HidController::InputDetector); 59 MakeController<Controller_Stubbed>(HidController::InputDetector, shared_memory);
61 MakeController<Controller_Stubbed>(HidController::UniquePad); 60 MakeController<Controller_Stubbed>(HidController::UniquePad, shared_memory);
62 MakeControllerWithServiceContext<Controller_NPad>(HidController::NPad); 61 MakeControllerWithServiceContext<Controller_NPad>(HidController::NPad, shared_memory);
63 MakeController<Controller_Gesture>(HidController::Gesture); 62 MakeController<Controller_Gesture>(HidController::Gesture, shared_memory);
64 MakeController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor); 63 MakeController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor, shared_memory);
65 64
66 // Homebrew doesn't try to activate some controllers, so we activate them by default 65 // Homebrew doesn't try to activate some controllers, so we activate them by default
67 GetController<Controller_NPad>(HidController::NPad).ActivateController(); 66 GetController<Controller_NPad>(HidController::NPad).ActivateController();
@@ -135,8 +134,7 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data,
135 if (controller == controllers[static_cast<size_t>(HidController::Mouse)]) { 134 if (controller == controllers[static_cast<size_t>(HidController::Mouse)]) {
136 continue; 135 continue;
137 } 136 }
138 controller->OnUpdate(core_timing, system.Kernel().GetHidSharedMem().GetPointer(), 137 controller->OnUpdate(core_timing);
139 SHARED_MEMORY_SIZE);
140 } 138 }
141 139
142 // If ns_late is higher than the update rate ignore the delay 140 // If ns_late is higher than the update rate ignore the delay
@@ -151,10 +149,8 @@ void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data,
151 std::chrono::nanoseconds ns_late) { 149 std::chrono::nanoseconds ns_late) {
152 auto& core_timing = system.CoreTiming(); 150 auto& core_timing = system.CoreTiming();
153 151
154 controllers[static_cast<size_t>(HidController::Mouse)]->OnUpdate( 152 controllers[static_cast<size_t>(HidController::Mouse)]->OnUpdate(core_timing);
155 core_timing, system.Kernel().GetHidSharedMem().GetPointer(), SHARED_MEMORY_SIZE); 153 controllers[static_cast<size_t>(HidController::Keyboard)]->OnUpdate(core_timing);
156 controllers[static_cast<size_t>(HidController::Keyboard)]->OnUpdate(
157 core_timing, system.Kernel().GetHidSharedMem().GetPointer(), SHARED_MEMORY_SIZE);
158 154
159 // If ns_late is higher than the update rate ignore the delay 155 // If ns_late is higher than the update rate ignore the delay
160 if (ns_late > mouse_keyboard_update_ns) { 156 if (ns_late > mouse_keyboard_update_ns) {
@@ -167,8 +163,7 @@ void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data,
167void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { 163void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
168 auto& core_timing = system.CoreTiming(); 164 auto& core_timing = system.CoreTiming();
169 165
170 controllers[static_cast<size_t>(HidController::NPad)]->OnMotionUpdate( 166 controllers[static_cast<size_t>(HidController::NPad)]->OnMotionUpdate(core_timing);
171 core_timing, system.Kernel().GetHidSharedMem().GetPointer(), SHARED_MEMORY_SIZE);
172 167
173 // If ns_late is higher than the update rate ignore the delay 168 // If ns_late is higher than the update rate ignore the delay
174 if (ns_late > motion_update_ns) { 169 if (ns_late > motion_update_ns) {
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index 95778e673..e61f8ed08 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -58,13 +58,14 @@ public:
58 58
59private: 59private:
60 template <typename T> 60 template <typename T>
61 void MakeController(HidController controller) { 61 void MakeController(HidController controller, u8* shared_memory) {
62 controllers[static_cast<std::size_t>(controller)] = std::make_unique<T>(system.HIDCore()); 62 controllers[static_cast<std::size_t>(controller)] =
63 std::make_unique<T>(system.HIDCore(), shared_memory);
63 } 64 }
64 template <typename T> 65 template <typename T>
65 void MakeControllerWithServiceContext(HidController controller) { 66 void MakeControllerWithServiceContext(HidController controller, u8* shared_memory) {
66 controllers[static_cast<std::size_t>(controller)] = 67 controllers[static_cast<std::size_t>(controller)] =
67 std::make_unique<T>(system.HIDCore(), service_context); 68 std::make_unique<T>(system.HIDCore(), shared_memory, service_context);
68 } 69 }
69 70
70 void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx); 71 void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx);
diff --git a/src/yuzu/configuration/configure_ui.cpp b/src/yuzu/configuration/configure_ui.cpp
index 46e5409db..d3a60cdd1 100644
--- a/src/yuzu/configuration/configure_ui.cpp
+++ b/src/yuzu/configuration/configure_ui.cpp
@@ -9,6 +9,7 @@
9#include <QDirIterator> 9#include <QDirIterator>
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "common/fs/path_util.h" 11#include "common/fs/path_util.h"
12#include "common/logging/log.h"
12#include "common/settings.h" 13#include "common/settings.h"
13#include "core/core.h" 14#include "core/core.h"
14#include "ui_configure_ui.h" 15#include "ui_configure_ui.h"
@@ -170,14 +171,74 @@ void ConfigureUi::RetranslateUI() {
170} 171}
171 172
172void ConfigureUi::InitializeLanguageComboBox() { 173void ConfigureUi::InitializeLanguageComboBox() {
174 // This is a list of lexicographically sorted languages, only the available translations are
175 // shown to the user.
176 static const struct {
177 const QString name;
178 const char* id;
179 } languages[] = {
180 // clang-format off
181 {QStringLiteral(u"Bahasa Indonesia"), "id"}, // Indonesian
182 {QStringLiteral(u"Bahasa Melayu"), "ms"}, // Malay
183 {QStringLiteral(u"Catal\u00E0"), "ca"}, // Catalan
184 {QStringLiteral(u"\u010Ce\u0161tina"), "cs"}, // Czech
185 {QStringLiteral(u"Dansk"), "da"}, // Danish
186 {QStringLiteral(u"Deutsch"), "de"}, // German
187 {QStringLiteral(u"English"), "en"}, // English
188 {QStringLiteral(u"Espa\u00F1ol"), "es"}, // Spanish
189 {QStringLiteral(u"Fran\u00E7ais"), "fr"}, // French
190 {QStringLiteral(u"Hrvatski"), "hr"}, // Croatian
191 {QStringLiteral(u"Italiano"), "it"}, // Italian
192 {QStringLiteral(u"Magyar"), "hu"}, // Hungarian
193 {QStringLiteral(u"Nederlands"), "nl"}, // Dutch
194 {QStringLiteral(u"Norsk bokm\u00E5l"), "nb"}, // Norwegian
195 {QStringLiteral(u"Polski"), "pl"}, // Polish
196 {QStringLiteral(u"Portugu\u00EAs"), "pt_PT"}, // Portuguese
197 {QStringLiteral(u"Portugu\u00EAs (Brasil)"), "pt_BR"}, // Portuguese (Brazil)
198 {QStringLiteral(u"Rom\u00E2n\u0103"), "ro"}, // Romanian
199 {QStringLiteral(u"Srpski"), "sr"}, // Serbian
200 {QStringLiteral(u"Suomi"), "fi"}, // Finnish
201 {QStringLiteral(u"Svenska"), "sv"}, // Swedish
202 {QStringLiteral(u"Ti\u1EBFng Vi\u1EC7t"), "vi"}, // Vietnamese
203 {QStringLiteral(u"Ti\u1EBFng Vi\u1EC7t (Vi\u1EC7t Nam)"), "vi_VN"}, // Vietnamese
204 {QStringLiteral(u"T\u00FCrk\u00E7e"), "tr_TR"}, // Turkish
205 {QStringLiteral(u"\u0395\u03BB\u03BB\u03B7\u03BD\u03B9\u03BA\u03AC"), "el"}, // Greek
206 {QStringLiteral(u"\u0420\u0443\u0441\u0441\u043A\u0438\u0439"), "ru_RU"}, // Russian
207 {QStringLiteral(u"\u0423\u043A\u0440\u0430\u0457\u043D\u0441\u044C\u043A\u0430"),
208 "uk"}, // Ukrainian
209 {QStringLiteral(u"\u0627\u0644\u0639\u0631\u0628\u064A\u0629"), "ar"}, // Arabic
210 {QStringLiteral(u"\u0641\u0627\u0631\u0633\u06CC"), "fa"}, // Farsi
211 {QStringLiteral(u"\uD55C\uAD6D\uC5B4"), "ko_KR"}, // Korean
212 {QStringLiteral(u"\u65E5\u672C\u8A9E"), "ja_JP"}, // Japanese
213 {QStringLiteral(u"\u7B80\u4F53\u4E2D\u6587"), "zh_CN"}, // Simplified Chinese
214 {QStringLiteral(u"\u7E41\u9AD4\u4E2D\u6587"), "zh_TW"}, // Traditional Chinese
215 // clang-format on
216 };
173 ui->language_combobox->addItem(tr("<System>"), QString{}); 217 ui->language_combobox->addItem(tr("<System>"), QString{});
174 ui->language_combobox->addItem(tr("English"), QStringLiteral("en")); 218 QDir languages_dir{QStringLiteral(":/languages")};
175 QDirIterator it(QStringLiteral(":/languages"), QDirIterator::NoIteratorFlags); 219 QStringList language_files = languages_dir.entryList();
176 while (it.hasNext()) { 220 for (const auto& lang : languages) {
177 QString locale = it.next(); 221 if (QString::fromLatin1(lang.id) == QStringLiteral("en")) {
222 ui->language_combobox->addItem(lang.name, QStringLiteral("en"));
223 continue;
224 }
225 for (int i = 0; i < language_files.size(); ++i) {
226 QString locale = language_files[i];
227 locale.truncate(locale.lastIndexOf(QLatin1Char{'.'}));
228 if (QString::fromLatin1(lang.id) == locale) {
229 ui->language_combobox->addItem(lang.name, locale);
230 language_files.removeAt(i);
231 break;
232 }
233 }
234 }
235 // Anything remaining will be at the bottom
236 for (const QString& file : language_files) {
237 LOG_CRITICAL(Frontend, "Unexpected Language File: {}", file.toStdString());
238 QString locale = file;
178 locale.truncate(locale.lastIndexOf(QLatin1Char{'.'})); 239 locale.truncate(locale.lastIndexOf(QLatin1Char{'.'}));
179 locale.remove(0, locale.lastIndexOf(QLatin1Char{'/'}) + 1); 240 const QString language_name = QLocale::languageToString(QLocale(locale).language());
180 const QString lang = QLocale::languageToString(QLocale(locale).language()); 241 const QString lang = QStringLiteral("%1 [%2]").arg(language_name, locale);
181 ui->language_combobox->addItem(lang, locale); 242 ui->language_combobox->addItem(lang, locale);
182 } 243 }
183 244