diff options
Diffstat (limited to 'src')
30 files changed, 973 insertions, 130 deletions
diff --git a/src/audio_core/sink/cubeb_sink.cpp b/src/audio_core/sink/cubeb_sink.cpp index a4e28de6d..90d049e8e 100644 --- a/src/audio_core/sink/cubeb_sink.cpp +++ b/src/audio_core/sink/cubeb_sink.cpp | |||
| @@ -185,6 +185,9 @@ public: | |||
| 185 | constexpr s32 max{std::numeric_limits<s16>::max()}; | 185 | constexpr s32 max{std::numeric_limits<s16>::max()}; |
| 186 | 186 | ||
| 187 | auto yuzu_volume{Settings::Volume()}; | 187 | auto yuzu_volume{Settings::Volume()}; |
| 188 | if (yuzu_volume > 1.0f) { | ||
| 189 | yuzu_volume = 0.6f + 20 * std::log10(yuzu_volume); | ||
| 190 | } | ||
| 188 | auto volume{system_volume * device_volume * yuzu_volume}; | 191 | auto volume{system_volume * device_volume * yuzu_volume}; |
| 189 | 192 | ||
| 190 | if (system_channels == 6 && device_channels == 2) { | 193 | if (system_channels == 6 && device_channels == 2) { |
diff --git a/src/common/settings.cpp b/src/common/settings.cpp index 1c7b6dfae..7282a45d3 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp | |||
| @@ -105,7 +105,7 @@ float Volume() { | |||
| 105 | if (values.audio_muted) { | 105 | if (values.audio_muted) { |
| 106 | return 0.0f; | 106 | return 0.0f; |
| 107 | } | 107 | } |
| 108 | return values.volume.GetValue() / 100.0f; | 108 | return values.volume.GetValue() / static_cast<f32>(values.volume.GetDefault()); |
| 109 | } | 109 | } |
| 110 | 110 | ||
| 111 | void UpdateRescalingInfo() { | 111 | void UpdateRescalingInfo() { |
diff --git a/src/common/settings.h b/src/common/settings.h index 1079cf8cb..14ed9b237 100644 --- a/src/common/settings.h +++ b/src/common/settings.h | |||
| @@ -374,7 +374,7 @@ struct Values { | |||
| 374 | Setting<std::string> audio_output_device_id{"auto", "output_device"}; | 374 | Setting<std::string> audio_output_device_id{"auto", "output_device"}; |
| 375 | Setting<std::string> audio_input_device_id{"auto", "input_device"}; | 375 | Setting<std::string> audio_input_device_id{"auto", "input_device"}; |
| 376 | Setting<bool> audio_muted{false, "audio_muted"}; | 376 | Setting<bool> audio_muted{false, "audio_muted"}; |
| 377 | SwitchableSetting<u8, true> volume{100, 0, 100, "volume"}; | 377 | SwitchableSetting<u8, true> volume{100, 0, 200, "volume"}; |
| 378 | Setting<bool> dump_audio_commands{false, "dump_audio_commands"}; | 378 | Setting<bool> dump_audio_commands{false, "dump_audio_commands"}; |
| 379 | 379 | ||
| 380 | // Core | 380 | // Core |
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 052357be4..4e39649a8 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -502,9 +502,10 @@ add_library(core STATIC | |||
| 502 | hle/service/jit/jit.h | 502 | hle/service/jit/jit.h |
| 503 | hle/service/lbl/lbl.cpp | 503 | hle/service/lbl/lbl.cpp |
| 504 | hle/service/lbl/lbl.h | 504 | hle/service/lbl/lbl.h |
| 505 | hle/service/ldn/errors.h | 505 | hle/service/ldn/ldn_results.h |
| 506 | hle/service/ldn/ldn.cpp | 506 | hle/service/ldn/ldn.cpp |
| 507 | hle/service/ldn/ldn.h | 507 | hle/service/ldn/ldn.h |
| 508 | hle/service/ldn/ldn_types.h | ||
| 508 | hle/service/ldr/ldr.cpp | 509 | hle/service/ldr/ldr.cpp |
| 509 | hle/service/ldr/ldr.h | 510 | hle/service/ldr/ldr.h |
| 510 | hle/service/lm/lm.cpp | 511 | hle/service/lm/lm.cpp |
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 1638bc41d..3b8b43994 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp | |||
| @@ -195,14 +195,16 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable* | |||
| 195 | if (page_table) { | 195 | if (page_table) { |
| 196 | config.page_table = reinterpret_cast<std::array<std::uint8_t*, NUM_PAGE_TABLE_ENTRIES>*>( | 196 | config.page_table = reinterpret_cast<std::array<std::uint8_t*, NUM_PAGE_TABLE_ENTRIES>*>( |
| 197 | page_table->pointers.data()); | 197 | page_table->pointers.data()); |
| 198 | config.absolute_offset_page_table = true; | ||
| 199 | config.page_table_pointer_mask_bits = Common::PageTable::ATTRIBUTE_BITS; | ||
| 200 | config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128; | ||
| 201 | config.only_detect_misalignment_via_page_table_on_page_boundary = true; | ||
| 202 | |||
| 198 | config.fastmem_pointer = page_table->fastmem_arena; | 203 | config.fastmem_pointer = page_table->fastmem_arena; |
| 204 | |||
| 205 | config.fastmem_exclusive_access = config.fastmem_pointer != nullptr; | ||
| 206 | config.recompile_on_exclusive_fastmem_failure = true; | ||
| 199 | } | 207 | } |
| 200 | config.absolute_offset_page_table = true; | ||
| 201 | config.page_table_pointer_mask_bits = Common::PageTable::ATTRIBUTE_BITS; | ||
| 202 | config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128; | ||
| 203 | config.only_detect_misalignment_via_page_table_on_page_boundary = true; | ||
| 204 | config.fastmem_exclusive_access = true; | ||
| 205 | config.recompile_on_exclusive_fastmem_failure = true; | ||
| 206 | 208 | ||
| 207 | // Multi-process state | 209 | // Multi-process state |
| 208 | config.processor_id = core_index; | 210 | config.processor_id = core_index; |
| @@ -254,6 +256,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable* | |||
| 254 | } | 256 | } |
| 255 | if (!Settings::values.cpuopt_fastmem) { | 257 | if (!Settings::values.cpuopt_fastmem) { |
| 256 | config.fastmem_pointer = nullptr; | 258 | config.fastmem_pointer = nullptr; |
| 259 | config.fastmem_exclusive_access = false; | ||
| 257 | } | 260 | } |
| 258 | if (!Settings::values.cpuopt_fastmem_exclusives) { | 261 | if (!Settings::values.cpuopt_fastmem_exclusives) { |
| 259 | config.fastmem_exclusive_access = false; | 262 | config.fastmem_exclusive_access = false; |
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 921a5a734..1d46f6d40 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp | |||
| @@ -250,7 +250,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable* | |||
| 250 | config.fastmem_address_space_bits = address_space_bits; | 250 | config.fastmem_address_space_bits = address_space_bits; |
| 251 | config.silently_mirror_fastmem = false; | 251 | config.silently_mirror_fastmem = false; |
| 252 | 252 | ||
| 253 | config.fastmem_exclusive_access = true; | 253 | config.fastmem_exclusive_access = config.fastmem_pointer != nullptr; |
| 254 | config.recompile_on_exclusive_fastmem_failure = true; | 254 | config.recompile_on_exclusive_fastmem_failure = true; |
| 255 | } | 255 | } |
| 256 | 256 | ||
| @@ -314,6 +314,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable* | |||
| 314 | } | 314 | } |
| 315 | if (!Settings::values.cpuopt_fastmem) { | 315 | if (!Settings::values.cpuopt_fastmem) { |
| 316 | config.fastmem_pointer = nullptr; | 316 | config.fastmem_pointer = nullptr; |
| 317 | config.fastmem_exclusive_access = false; | ||
| 317 | } | 318 | } |
| 318 | if (!Settings::values.cpuopt_fastmem_exclusives) { | 319 | if (!Settings::values.cpuopt_fastmem_exclusives) { |
| 319 | config.fastmem_exclusive_access = false; | 320 | config.fastmem_exclusive_access = false; |
diff --git a/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp b/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp index e9123c13d..200efe4db 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp | |||
| @@ -8,6 +8,10 @@ | |||
| 8 | #include "core/core.h" | 8 | #include "core/core.h" |
| 9 | #include "core/core_timing.h" | 9 | #include "core/core_timing.h" |
| 10 | 10 | ||
| 11 | #ifdef _MSC_VER | ||
| 12 | #include <intrin.h> | ||
| 13 | #endif | ||
| 14 | |||
| 11 | using Callback = Dynarmic::A32::Coprocessor::Callback; | 15 | using Callback = Dynarmic::A32::Coprocessor::Callback; |
| 12 | using CallbackOrAccessOneWord = Dynarmic::A32::Coprocessor::CallbackOrAccessOneWord; | 16 | using CallbackOrAccessOneWord = Dynarmic::A32::Coprocessor::CallbackOrAccessOneWord; |
| 13 | using CallbackOrAccessTwoWords = Dynarmic::A32::Coprocessor::CallbackOrAccessTwoWords; | 17 | using CallbackOrAccessTwoWords = Dynarmic::A32::Coprocessor::CallbackOrAccessTwoWords; |
| @@ -47,12 +51,31 @@ CallbackOrAccessOneWord DynarmicCP15::CompileSendOneWord(bool two, unsigned opc1 | |||
| 47 | switch (opc2) { | 51 | switch (opc2) { |
| 48 | case 4: | 52 | case 4: |
| 49 | // CP15_DATA_SYNC_BARRIER | 53 | // CP15_DATA_SYNC_BARRIER |
| 50 | // This is a dummy write, we ignore the value written here. | 54 | return Callback{ |
| 51 | return &dummy_value; | 55 | [](Dynarmic::A32::Jit*, void*, std::uint32_t, std::uint32_t) -> std::uint64_t { |
| 56 | #ifdef _MSC_VER | ||
| 57 | _mm_mfence(); | ||
| 58 | _mm_lfence(); | ||
| 59 | #else | ||
| 60 | asm volatile("mfence\n\tlfence\n\t" : : : "memory"); | ||
| 61 | #endif | ||
| 62 | return 0; | ||
| 63 | }, | ||
| 64 | std::nullopt, | ||
| 65 | }; | ||
| 52 | case 5: | 66 | case 5: |
| 53 | // CP15_DATA_MEMORY_BARRIER | 67 | // CP15_DATA_MEMORY_BARRIER |
| 54 | // This is a dummy write, we ignore the value written here. | 68 | return Callback{ |
| 55 | return &dummy_value; | 69 | [](Dynarmic::A32::Jit*, void*, std::uint32_t, std::uint32_t) -> std::uint64_t { |
| 70 | #ifdef _MSC_VER | ||
| 71 | _mm_mfence(); | ||
| 72 | #else | ||
| 73 | asm volatile("mfence\n\t" : : : "memory"); | ||
| 74 | #endif | ||
| 75 | return 0; | ||
| 76 | }, | ||
| 77 | std::nullopt, | ||
| 78 | }; | ||
| 56 | } | 79 | } |
| 57 | } | 80 | } |
| 58 | 81 | ||
diff --git a/src/core/arm/dynarmic/arm_dynarmic_cp15.h b/src/core/arm/dynarmic/arm_dynarmic_cp15.h index 5b2a51636..d90b3e568 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_cp15.h +++ b/src/core/arm/dynarmic/arm_dynarmic_cp15.h | |||
| @@ -35,6 +35,8 @@ public: | |||
| 35 | ARM_Dynarmic_32& parent; | 35 | ARM_Dynarmic_32& parent; |
| 36 | u32 uprw = 0; | 36 | u32 uprw = 0; |
| 37 | u32 uro = 0; | 37 | u32 uro = 0; |
| 38 | |||
| 39 | friend class ARM_Dynarmic_32; | ||
| 38 | }; | 40 | }; |
| 39 | 41 | ||
| 40 | } // namespace Core | 42 | } // namespace Core |
diff --git a/src/core/file_sys/ips_layer.cpp b/src/core/file_sys/ips_layer.cpp index 4b35ca82f..a33dbe94b 100644 --- a/src/core/file_sys/ips_layer.cpp +++ b/src/core/file_sys/ips_layer.cpp | |||
| @@ -287,7 +287,8 @@ void IPSwitchCompiler::Parse() { | |||
| 287 | std::copy(value.begin(), value.end(), std::back_inserter(replace)); | 287 | std::copy(value.begin(), value.end(), std::back_inserter(replace)); |
| 288 | } else { | 288 | } else { |
| 289 | // hex replacement | 289 | // hex replacement |
| 290 | const auto value = patch_line.substr(9); | 290 | const auto value = |
| 291 | patch_line.substr(9, patch_line.find_first_of(" /\r\n", 9) - 9); | ||
| 291 | replace = Common::HexStringToVector(value, is_little_endian); | 292 | replace = Common::HexStringToVector(value, is_little_endian); |
| 292 | } | 293 | } |
| 293 | 294 | ||
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 8c3895937..049602e7d 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include "common/thread.h" | ||
| 4 | #include "core/hid/emulated_controller.h" | 5 | #include "core/hid/emulated_controller.h" |
| 5 | #include "core/hid/input_converter.h" | 6 | #include "core/hid/input_converter.h" |
| 6 | 7 | ||
| @@ -84,18 +85,19 @@ void EmulatedController::ReloadFromSettings() { | |||
| 84 | motion_params[index] = Common::ParamPackage(player.motions[index]); | 85 | motion_params[index] = Common::ParamPackage(player.motions[index]); |
| 85 | } | 86 | } |
| 86 | 87 | ||
| 88 | controller.colors_state.fullkey = { | ||
| 89 | .body = GetNpadColor(player.body_color_left), | ||
| 90 | .button = GetNpadColor(player.button_color_left), | ||
| 91 | }; | ||
| 87 | controller.colors_state.left = { | 92 | controller.colors_state.left = { |
| 88 | .body = player.body_color_left, | 93 | .body = GetNpadColor(player.body_color_left), |
| 89 | .button = player.button_color_left, | 94 | .button = GetNpadColor(player.button_color_left), |
| 90 | }; | 95 | }; |
| 91 | 96 | controller.colors_state.left = { | |
| 92 | controller.colors_state.right = { | 97 | .body = GetNpadColor(player.body_color_right), |
| 93 | .body = player.body_color_right, | 98 | .button = GetNpadColor(player.button_color_right), |
| 94 | .button = player.button_color_right, | ||
| 95 | }; | 99 | }; |
| 96 | 100 | ||
| 97 | controller.colors_state.fullkey = controller.colors_state.left; | ||
| 98 | |||
| 99 | // Other or debug controller should always be a pro controller | 101 | // Other or debug controller should always be a pro controller |
| 100 | if (npad_id_type != NpadIdType::Other) { | 102 | if (npad_id_type != NpadIdType::Other) { |
| 101 | SetNpadStyleIndex(MapSettingsTypeToNPad(player.controller_type)); | 103 | SetNpadStyleIndex(MapSettingsTypeToNPad(player.controller_type)); |
| @@ -949,6 +951,9 @@ bool EmulatedController::TestVibration(std::size_t device_index) { | |||
| 949 | // Send a slight vibration to test for rumble support | 951 | // Send a slight vibration to test for rumble support |
| 950 | output_devices[device_index]->SetVibration(test_vibration); | 952 | output_devices[device_index]->SetVibration(test_vibration); |
| 951 | 953 | ||
| 954 | // Wait for about 15ms to ensure the controller is ready for the stop command | ||
| 955 | std::this_thread::sleep_for(std::chrono::milliseconds(15)); | ||
| 956 | |||
| 952 | // Stop any vibration and return the result | 957 | // Stop any vibration and return the result |
| 953 | return output_devices[device_index]->SetVibration(zero_vibration) == | 958 | return output_devices[device_index]->SetVibration(zero_vibration) == |
| 954 | Common::Input::VibrationError::None; | 959 | Common::Input::VibrationError::None; |
| @@ -1310,6 +1315,15 @@ const CameraState& EmulatedController::GetCamera() const { | |||
| 1310 | return controller.camera_state; | 1315 | return controller.camera_state; |
| 1311 | } | 1316 | } |
| 1312 | 1317 | ||
| 1318 | NpadColor EmulatedController::GetNpadColor(u32 color) { | ||
| 1319 | return { | ||
| 1320 | .r = static_cast<u8>((color >> 16) & 0xFF), | ||
| 1321 | .g = static_cast<u8>((color >> 8) & 0xFF), | ||
| 1322 | .b = static_cast<u8>(color & 0xFF), | ||
| 1323 | .a = 0xff, | ||
| 1324 | }; | ||
| 1325 | } | ||
| 1326 | |||
| 1313 | void EmulatedController::TriggerOnChange(ControllerTriggerType type, bool is_npad_service_update) { | 1327 | void EmulatedController::TriggerOnChange(ControllerTriggerType type, bool is_npad_service_update) { |
| 1314 | std::scoped_lock lock{callback_mutex}; | 1328 | std::scoped_lock lock{callback_mutex}; |
| 1315 | for (const auto& poller_pair : callback_list) { | 1329 | for (const auto& poller_pair : callback_list) { |
diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index 823c1700c..cbd7c26d3 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h | |||
| @@ -425,6 +425,13 @@ private: | |||
| 425 | void SetCamera(const Common::Input::CallbackStatus& callback); | 425 | void SetCamera(const Common::Input::CallbackStatus& callback); |
| 426 | 426 | ||
| 427 | /** | 427 | /** |
| 428 | * Converts a color format from bgra to rgba | ||
| 429 | * @param color in bgra format | ||
| 430 | * @return NpadColor in rgba format | ||
| 431 | */ | ||
| 432 | NpadColor GetNpadColor(u32 color); | ||
| 433 | |||
| 434 | /** | ||
| 428 | * Triggers a callback that something has changed on the controller status | 435 | * Triggers a callback that something has changed on the controller status |
| 429 | * @param type Input type of the event to trigger | 436 | * @param type Input type of the event to trigger |
| 430 | * @param is_service_update indicates if this event should only be sent to HID services | 437 | * @param is_service_update indicates if this event should only be sent to HID services |
diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h index e49223016..e3b1cfbc6 100644 --- a/src/core/hid/hid_types.h +++ b/src/core/hid/hid_types.h | |||
| @@ -327,10 +327,18 @@ struct TouchState { | |||
| 327 | }; | 327 | }; |
| 328 | static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size"); | 328 | static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size"); |
| 329 | 329 | ||
| 330 | struct NpadColor { | ||
| 331 | u8 r{}; | ||
| 332 | u8 g{}; | ||
| 333 | u8 b{}; | ||
| 334 | u8 a{}; | ||
| 335 | }; | ||
| 336 | static_assert(sizeof(NpadColor) == 4, "NpadColor is an invalid size"); | ||
| 337 | |||
| 330 | // This is nn::hid::NpadControllerColor | 338 | // This is nn::hid::NpadControllerColor |
| 331 | struct NpadControllerColor { | 339 | struct NpadControllerColor { |
| 332 | u32 body{}; | 340 | NpadColor body{}; |
| 333 | u32 button{}; | 341 | NpadColor button{}; |
| 334 | }; | 342 | }; |
| 335 | static_assert(sizeof(NpadControllerColor) == 8, "NpadControllerColor is an invalid size"); | 343 | static_assert(sizeof(NpadControllerColor) == 8, "NpadControllerColor is an invalid size"); |
| 336 | 344 | ||
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 3c28dee76..cb29004e8 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp | |||
| @@ -163,28 +163,51 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { | |||
| 163 | } | 163 | } |
| 164 | LOG_DEBUG(Service_HID, "Npad connected {}", npad_id); | 164 | LOG_DEBUG(Service_HID, "Npad connected {}", npad_id); |
| 165 | const auto controller_type = controller.device->GetNpadStyleIndex(); | 165 | const auto controller_type = controller.device->GetNpadStyleIndex(); |
| 166 | const auto& body_colors = controller.device->GetColors(); | ||
| 167 | const auto& battery_level = controller.device->GetBattery(); | ||
| 166 | auto* shared_memory = controller.shared_memory; | 168 | auto* shared_memory = controller.shared_memory; |
| 167 | if (controller_type == Core::HID::NpadStyleIndex::None) { | 169 | if (controller_type == Core::HID::NpadStyleIndex::None) { |
| 168 | controller.styleset_changed_event->GetWritableEvent().Signal(); | 170 | controller.styleset_changed_event->GetWritableEvent().Signal(); |
| 169 | return; | 171 | return; |
| 170 | } | 172 | } |
| 173 | |||
| 174 | // Reset memory values | ||
| 171 | shared_memory->style_tag.raw = Core::HID::NpadStyleSet::None; | 175 | shared_memory->style_tag.raw = Core::HID::NpadStyleSet::None; |
| 172 | shared_memory->device_type.raw = 0; | 176 | shared_memory->device_type.raw = 0; |
| 173 | shared_memory->system_properties.raw = 0; | 177 | shared_memory->system_properties.raw = 0; |
| 178 | shared_memory->joycon_color.attribute = ColorAttribute::NoController; | ||
| 179 | shared_memory->joycon_color.attribute = ColorAttribute::NoController; | ||
| 180 | shared_memory->fullkey_color = {}; | ||
| 181 | shared_memory->joycon_color.left = {}; | ||
| 182 | shared_memory->joycon_color.right = {}; | ||
| 183 | shared_memory->battery_level_dual = {}; | ||
| 184 | shared_memory->battery_level_left = {}; | ||
| 185 | shared_memory->battery_level_right = {}; | ||
| 186 | |||
| 174 | switch (controller_type) { | 187 | switch (controller_type) { |
| 175 | case Core::HID::NpadStyleIndex::None: | 188 | case Core::HID::NpadStyleIndex::None: |
| 176 | ASSERT(false); | 189 | ASSERT(false); |
| 177 | break; | 190 | break; |
| 178 | case Core::HID::NpadStyleIndex::ProController: | 191 | case Core::HID::NpadStyleIndex::ProController: |
| 192 | shared_memory->fullkey_color.attribute = ColorAttribute::Ok; | ||
| 193 | shared_memory->fullkey_color.fullkey = body_colors.fullkey; | ||
| 194 | shared_memory->battery_level_dual = battery_level.dual.battery_level; | ||
| 179 | shared_memory->style_tag.fullkey.Assign(1); | 195 | shared_memory->style_tag.fullkey.Assign(1); |
| 180 | shared_memory->device_type.fullkey.Assign(1); | 196 | shared_memory->device_type.fullkey.Assign(1); |
| 181 | shared_memory->system_properties.is_vertical.Assign(1); | 197 | shared_memory->system_properties.is_vertical.Assign(1); |
| 182 | shared_memory->system_properties.use_plus.Assign(1); | 198 | shared_memory->system_properties.use_plus.Assign(1); |
| 183 | shared_memory->system_properties.use_minus.Assign(1); | 199 | shared_memory->system_properties.use_minus.Assign(1); |
| 200 | shared_memory->system_properties.is_charging_joy_dual.Assign( | ||
| 201 | battery_level.dual.is_charging); | ||
| 184 | shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::SwitchProController; | 202 | shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::SwitchProController; |
| 185 | shared_memory->sixaxis_fullkey_properties.is_newly_assigned.Assign(1); | 203 | shared_memory->sixaxis_fullkey_properties.is_newly_assigned.Assign(1); |
| 186 | break; | 204 | break; |
| 187 | case Core::HID::NpadStyleIndex::Handheld: | 205 | case Core::HID::NpadStyleIndex::Handheld: |
| 206 | shared_memory->fullkey_color.attribute = ColorAttribute::Ok; | ||
| 207 | shared_memory->joycon_color.attribute = ColorAttribute::Ok; | ||
| 208 | shared_memory->fullkey_color.fullkey = body_colors.fullkey; | ||
| 209 | shared_memory->joycon_color.left = body_colors.left; | ||
| 210 | shared_memory->joycon_color.right = body_colors.right; | ||
| 188 | shared_memory->style_tag.handheld.Assign(1); | 211 | shared_memory->style_tag.handheld.Assign(1); |
| 189 | shared_memory->device_type.handheld_left.Assign(1); | 212 | shared_memory->device_type.handheld_left.Assign(1); |
| 190 | shared_memory->device_type.handheld_right.Assign(1); | 213 | shared_memory->device_type.handheld_right.Assign(1); |
| @@ -192,47 +215,86 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { | |||
| 192 | shared_memory->system_properties.use_plus.Assign(1); | 215 | shared_memory->system_properties.use_plus.Assign(1); |
| 193 | shared_memory->system_properties.use_minus.Assign(1); | 216 | shared_memory->system_properties.use_minus.Assign(1); |
| 194 | shared_memory->system_properties.use_directional_buttons.Assign(1); | 217 | shared_memory->system_properties.use_directional_buttons.Assign(1); |
| 218 | shared_memory->system_properties.is_charging_joy_dual.Assign( | ||
| 219 | battery_level.left.is_charging); | ||
| 220 | shared_memory->system_properties.is_charging_joy_left.Assign( | ||
| 221 | battery_level.left.is_charging); | ||
| 222 | shared_memory->system_properties.is_charging_joy_right.Assign( | ||
| 223 | battery_level.right.is_charging); | ||
| 195 | shared_memory->assignment_mode = NpadJoyAssignmentMode::Dual; | 224 | shared_memory->assignment_mode = NpadJoyAssignmentMode::Dual; |
| 196 | shared_memory->applet_nfc_xcd.applet_footer.type = | 225 | shared_memory->applet_nfc_xcd.applet_footer.type = |
| 197 | AppletFooterUiType::HandheldJoyConLeftJoyConRight; | 226 | AppletFooterUiType::HandheldJoyConLeftJoyConRight; |
| 198 | shared_memory->sixaxis_handheld_properties.is_newly_assigned.Assign(1); | 227 | shared_memory->sixaxis_handheld_properties.is_newly_assigned.Assign(1); |
| 199 | break; | 228 | break; |
| 200 | case Core::HID::NpadStyleIndex::JoyconDual: | 229 | case Core::HID::NpadStyleIndex::JoyconDual: |
| 230 | shared_memory->fullkey_color.attribute = ColorAttribute::Ok; | ||
| 231 | shared_memory->joycon_color.attribute = ColorAttribute::Ok; | ||
| 201 | shared_memory->style_tag.joycon_dual.Assign(1); | 232 | shared_memory->style_tag.joycon_dual.Assign(1); |
| 202 | if (controller.is_dual_left_connected) { | 233 | if (controller.is_dual_left_connected) { |
| 234 | shared_memory->joycon_color.left = body_colors.left; | ||
| 235 | shared_memory->battery_level_left = battery_level.left.battery_level; | ||
| 203 | shared_memory->device_type.joycon_left.Assign(1); | 236 | shared_memory->device_type.joycon_left.Assign(1); |
| 204 | shared_memory->system_properties.use_minus.Assign(1); | 237 | shared_memory->system_properties.use_minus.Assign(1); |
| 238 | shared_memory->system_properties.is_charging_joy_left.Assign( | ||
| 239 | battery_level.left.is_charging); | ||
| 205 | shared_memory->sixaxis_dual_left_properties.is_newly_assigned.Assign(1); | 240 | shared_memory->sixaxis_dual_left_properties.is_newly_assigned.Assign(1); |
| 206 | } | 241 | } |
| 207 | if (controller.is_dual_right_connected) { | 242 | if (controller.is_dual_right_connected) { |
| 243 | shared_memory->joycon_color.right = body_colors.right; | ||
| 244 | shared_memory->battery_level_right = battery_level.right.battery_level; | ||
| 208 | shared_memory->device_type.joycon_right.Assign(1); | 245 | shared_memory->device_type.joycon_right.Assign(1); |
| 209 | shared_memory->system_properties.use_plus.Assign(1); | 246 | shared_memory->system_properties.use_plus.Assign(1); |
| 247 | shared_memory->system_properties.is_charging_joy_right.Assign( | ||
| 248 | battery_level.right.is_charging); | ||
| 210 | shared_memory->sixaxis_dual_right_properties.is_newly_assigned.Assign(1); | 249 | shared_memory->sixaxis_dual_right_properties.is_newly_assigned.Assign(1); |
| 211 | } | 250 | } |
| 212 | shared_memory->system_properties.use_directional_buttons.Assign(1); | 251 | shared_memory->system_properties.use_directional_buttons.Assign(1); |
| 213 | shared_memory->system_properties.is_vertical.Assign(1); | 252 | shared_memory->system_properties.is_vertical.Assign(1); |
| 214 | shared_memory->assignment_mode = NpadJoyAssignmentMode::Dual; | 253 | shared_memory->assignment_mode = NpadJoyAssignmentMode::Dual; |
| 254 | |||
| 215 | if (controller.is_dual_left_connected && controller.is_dual_right_connected) { | 255 | if (controller.is_dual_left_connected && controller.is_dual_right_connected) { |
| 216 | shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDual; | 256 | shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDual; |
| 257 | shared_memory->fullkey_color.fullkey = body_colors.left; | ||
| 258 | shared_memory->battery_level_dual = battery_level.left.battery_level; | ||
| 259 | shared_memory->system_properties.is_charging_joy_dual.Assign( | ||
| 260 | battery_level.left.is_charging); | ||
| 217 | } else if (controller.is_dual_left_connected) { | 261 | } else if (controller.is_dual_left_connected) { |
| 218 | shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDualLeftOnly; | 262 | shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDualLeftOnly; |
| 263 | shared_memory->fullkey_color.fullkey = body_colors.left; | ||
| 264 | shared_memory->battery_level_dual = battery_level.left.battery_level; | ||
| 265 | shared_memory->system_properties.is_charging_joy_dual.Assign( | ||
| 266 | battery_level.left.is_charging); | ||
| 219 | } else { | 267 | } else { |
| 220 | shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDualRightOnly; | 268 | shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDualRightOnly; |
| 269 | shared_memory->fullkey_color.fullkey = body_colors.right; | ||
| 270 | shared_memory->battery_level_dual = battery_level.right.battery_level; | ||
| 271 | shared_memory->system_properties.is_charging_joy_dual.Assign( | ||
| 272 | battery_level.right.is_charging); | ||
| 221 | } | 273 | } |
| 222 | break; | 274 | break; |
| 223 | case Core::HID::NpadStyleIndex::JoyconLeft: | 275 | case Core::HID::NpadStyleIndex::JoyconLeft: |
| 276 | shared_memory->joycon_color.attribute = ColorAttribute::Ok; | ||
| 277 | shared_memory->joycon_color.left = body_colors.left; | ||
| 278 | shared_memory->battery_level_dual = battery_level.left.battery_level; | ||
| 224 | shared_memory->style_tag.joycon_left.Assign(1); | 279 | shared_memory->style_tag.joycon_left.Assign(1); |
| 225 | shared_memory->device_type.joycon_left.Assign(1); | 280 | shared_memory->device_type.joycon_left.Assign(1); |
| 226 | shared_memory->system_properties.is_horizontal.Assign(1); | 281 | shared_memory->system_properties.is_horizontal.Assign(1); |
| 227 | shared_memory->system_properties.use_minus.Assign(1); | 282 | shared_memory->system_properties.use_minus.Assign(1); |
| 283 | shared_memory->system_properties.is_charging_joy_left.Assign( | ||
| 284 | battery_level.left.is_charging); | ||
| 228 | shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyLeftHorizontal; | 285 | shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyLeftHorizontal; |
| 229 | shared_memory->sixaxis_left_properties.is_newly_assigned.Assign(1); | 286 | shared_memory->sixaxis_left_properties.is_newly_assigned.Assign(1); |
| 230 | break; | 287 | break; |
| 231 | case Core::HID::NpadStyleIndex::JoyconRight: | 288 | case Core::HID::NpadStyleIndex::JoyconRight: |
| 289 | shared_memory->joycon_color.attribute = ColorAttribute::Ok; | ||
| 290 | shared_memory->joycon_color.right = body_colors.right; | ||
| 291 | shared_memory->battery_level_right = battery_level.right.battery_level; | ||
| 232 | shared_memory->style_tag.joycon_right.Assign(1); | 292 | shared_memory->style_tag.joycon_right.Assign(1); |
| 233 | shared_memory->device_type.joycon_right.Assign(1); | 293 | shared_memory->device_type.joycon_right.Assign(1); |
| 234 | shared_memory->system_properties.is_horizontal.Assign(1); | 294 | shared_memory->system_properties.is_horizontal.Assign(1); |
| 235 | shared_memory->system_properties.use_plus.Assign(1); | 295 | shared_memory->system_properties.use_plus.Assign(1); |
| 296 | shared_memory->system_properties.is_charging_joy_right.Assign( | ||
| 297 | battery_level.right.is_charging); | ||
| 236 | shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyRightHorizontal; | 298 | shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyRightHorizontal; |
| 237 | shared_memory->sixaxis_right_properties.is_newly_assigned.Assign(1); | 299 | shared_memory->sixaxis_right_properties.is_newly_assigned.Assign(1); |
| 238 | break; | 300 | break; |
| @@ -269,21 +331,6 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { | |||
| 269 | break; | 331 | break; |
| 270 | } | 332 | } |
| 271 | 333 | ||
| 272 | const auto& body_colors = controller.device->GetColors(); | ||
| 273 | |||
| 274 | shared_memory->fullkey_color.attribute = ColorAttribute::Ok; | ||
| 275 | shared_memory->fullkey_color.fullkey = body_colors.fullkey; | ||
| 276 | |||
| 277 | shared_memory->joycon_color.attribute = ColorAttribute::Ok; | ||
| 278 | shared_memory->joycon_color.left = body_colors.left; | ||
| 279 | shared_memory->joycon_color.right = body_colors.right; | ||
| 280 | |||
| 281 | // TODO: Investigate when we should report all batery types | ||
| 282 | const auto& battery_level = controller.device->GetBattery(); | ||
| 283 | shared_memory->battery_level_dual = battery_level.dual.battery_level; | ||
| 284 | shared_memory->battery_level_left = battery_level.left.battery_level; | ||
| 285 | shared_memory->battery_level_right = battery_level.right.battery_level; | ||
| 286 | |||
| 287 | controller.is_connected = true; | 334 | controller.is_connected = true; |
| 288 | controller.device->Connect(); | 335 | controller.device->Connect(); |
| 289 | SignalStyleSetChangedEvent(npad_id); | 336 | SignalStyleSetChangedEvent(npad_id); |
diff --git a/src/core/hle/service/ldn/errors.h b/src/core/hle/service/ldn/errors.h deleted file mode 100644 index 972a74806..000000000 --- a/src/core/hle/service/ldn/errors.h +++ /dev/null | |||
| @@ -1,12 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/result.h" | ||
| 7 | |||
| 8 | namespace Service::LDN { | ||
| 9 | |||
| 10 | constexpr Result ERROR_DISABLED{ErrorModule::LDN, 22}; | ||
| 11 | |||
| 12 | } // namespace Service::LDN | ||
diff --git a/src/core/hle/service/ldn/ldn.cpp b/src/core/hle/service/ldn/ldn.cpp index 125d4dc4c..c11daff54 100644 --- a/src/core/hle/service/ldn/ldn.cpp +++ b/src/core/hle/service/ldn/ldn.cpp | |||
| @@ -3,11 +3,15 @@ | |||
| 3 | 3 | ||
| 4 | #include <memory> | 4 | #include <memory> |
| 5 | 5 | ||
| 6 | #include "core/hle/ipc_helpers.h" | 6 | #include "core/core.h" |
| 7 | #include "core/hle/result.h" | ||
| 8 | #include "core/hle/service/ldn/errors.h" | ||
| 9 | #include "core/hle/service/ldn/ldn.h" | 7 | #include "core/hle/service/ldn/ldn.h" |
| 10 | #include "core/hle/service/sm/sm.h" | 8 | #include "core/hle/service/ldn/ldn_results.h" |
| 9 | #include "core/hle/service/ldn/ldn_types.h" | ||
| 10 | #include "core/internal_network/network.h" | ||
| 11 | #include "core/internal_network/network_interface.h" | ||
| 12 | |||
| 13 | // This is defined by synchapi.h and conflicts with ServiceContext::CreateEvent | ||
| 14 | #undef CreateEvent | ||
| 11 | 15 | ||
| 12 | namespace Service::LDN { | 16 | namespace Service::LDN { |
| 13 | 17 | ||
| @@ -100,74 +104,418 @@ class IUserLocalCommunicationService final | |||
| 100 | : public ServiceFramework<IUserLocalCommunicationService> { | 104 | : public ServiceFramework<IUserLocalCommunicationService> { |
| 101 | public: | 105 | public: |
| 102 | explicit IUserLocalCommunicationService(Core::System& system_) | 106 | explicit IUserLocalCommunicationService(Core::System& system_) |
| 103 | : ServiceFramework{system_, "IUserLocalCommunicationService"} { | 107 | : ServiceFramework{system_, "IUserLocalCommunicationService", ServiceThreadType::CreateNew}, |
| 108 | service_context{system, "IUserLocalCommunicationService"}, room_network{ | ||
| 109 | system_.GetRoomNetwork()} { | ||
| 104 | // clang-format off | 110 | // clang-format off |
| 105 | static const FunctionInfo functions[] = { | 111 | static const FunctionInfo functions[] = { |
| 106 | {0, &IUserLocalCommunicationService::GetState, "GetState"}, | 112 | {0, &IUserLocalCommunicationService::GetState, "GetState"}, |
| 107 | {1, nullptr, "GetNetworkInfo"}, | 113 | {1, &IUserLocalCommunicationService::GetNetworkInfo, "GetNetworkInfo"}, |
| 108 | {2, nullptr, "GetIpv4Address"}, | 114 | {2, nullptr, "GetIpv4Address"}, |
| 109 | {3, nullptr, "GetDisconnectReason"}, | 115 | {3, &IUserLocalCommunicationService::GetDisconnectReason, "GetDisconnectReason"}, |
| 110 | {4, nullptr, "GetSecurityParameter"}, | 116 | {4, &IUserLocalCommunicationService::GetSecurityParameter, "GetSecurityParameter"}, |
| 111 | {5, nullptr, "GetNetworkConfig"}, | 117 | {5, &IUserLocalCommunicationService::GetNetworkConfig, "GetNetworkConfig"}, |
| 112 | {100, nullptr, "AttachStateChangeEvent"}, | 118 | {100, &IUserLocalCommunicationService::AttachStateChangeEvent, "AttachStateChangeEvent"}, |
| 113 | {101, nullptr, "GetNetworkInfoLatestUpdate"}, | 119 | {101, &IUserLocalCommunicationService::GetNetworkInfoLatestUpdate, "GetNetworkInfoLatestUpdate"}, |
| 114 | {102, nullptr, "Scan"}, | 120 | {102, &IUserLocalCommunicationService::Scan, "Scan"}, |
| 115 | {103, nullptr, "ScanPrivate"}, | 121 | {103, &IUserLocalCommunicationService::ScanPrivate, "ScanPrivate"}, |
| 116 | {104, nullptr, "SetWirelessControllerRestriction"}, | 122 | {104, nullptr, "SetWirelessControllerRestriction"}, |
| 117 | {200, nullptr, "OpenAccessPoint"}, | 123 | {200, &IUserLocalCommunicationService::OpenAccessPoint, "OpenAccessPoint"}, |
| 118 | {201, nullptr, "CloseAccessPoint"}, | 124 | {201, &IUserLocalCommunicationService::CloseAccessPoint, "CloseAccessPoint"}, |
| 119 | {202, nullptr, "CreateNetwork"}, | 125 | {202, &IUserLocalCommunicationService::CreateNetwork, "CreateNetwork"}, |
| 120 | {203, nullptr, "CreateNetworkPrivate"}, | 126 | {203, &IUserLocalCommunicationService::CreateNetworkPrivate, "CreateNetworkPrivate"}, |
| 121 | {204, nullptr, "DestroyNetwork"}, | 127 | {204, &IUserLocalCommunicationService::DestroyNetwork, "DestroyNetwork"}, |
| 122 | {205, nullptr, "Reject"}, | 128 | {205, nullptr, "Reject"}, |
| 123 | {206, nullptr, "SetAdvertiseData"}, | 129 | {206, &IUserLocalCommunicationService::SetAdvertiseData, "SetAdvertiseData"}, |
| 124 | {207, nullptr, "SetStationAcceptPolicy"}, | 130 | {207, &IUserLocalCommunicationService::SetStationAcceptPolicy, "SetStationAcceptPolicy"}, |
| 125 | {208, nullptr, "AddAcceptFilterEntry"}, | 131 | {208, &IUserLocalCommunicationService::AddAcceptFilterEntry, "AddAcceptFilterEntry"}, |
| 126 | {209, nullptr, "ClearAcceptFilter"}, | 132 | {209, nullptr, "ClearAcceptFilter"}, |
| 127 | {300, nullptr, "OpenStation"}, | 133 | {300, &IUserLocalCommunicationService::OpenStation, "OpenStation"}, |
| 128 | {301, nullptr, "CloseStation"}, | 134 | {301, &IUserLocalCommunicationService::CloseStation, "CloseStation"}, |
| 129 | {302, nullptr, "Connect"}, | 135 | {302, &IUserLocalCommunicationService::Connect, "Connect"}, |
| 130 | {303, nullptr, "ConnectPrivate"}, | 136 | {303, nullptr, "ConnectPrivate"}, |
| 131 | {304, nullptr, "Disconnect"}, | 137 | {304, &IUserLocalCommunicationService::Disconnect, "Disconnect"}, |
| 132 | {400, nullptr, "Initialize"}, | 138 | {400, &IUserLocalCommunicationService::Initialize, "Initialize"}, |
| 133 | {401, nullptr, "Finalize"}, | 139 | {401, &IUserLocalCommunicationService::Finalize, "Finalize"}, |
| 134 | {402, &IUserLocalCommunicationService::Initialize2, "Initialize2"}, // 7.0.0+ | 140 | {402, &IUserLocalCommunicationService::Initialize2, "Initialize2"}, |
| 135 | }; | 141 | }; |
| 136 | // clang-format on | 142 | // clang-format on |
| 137 | 143 | ||
| 138 | RegisterHandlers(functions); | 144 | RegisterHandlers(functions); |
| 145 | |||
| 146 | state_change_event = | ||
| 147 | service_context.CreateEvent("IUserLocalCommunicationService:StateChangeEvent"); | ||
| 148 | } | ||
| 149 | |||
| 150 | ~IUserLocalCommunicationService() { | ||
| 151 | service_context.CloseEvent(state_change_event); | ||
| 152 | } | ||
| 153 | |||
| 154 | void OnEventFired() { | ||
| 155 | state_change_event->GetWritableEvent().Signal(); | ||
| 139 | } | 156 | } |
| 140 | 157 | ||
| 141 | void GetState(Kernel::HLERequestContext& ctx) { | 158 | void GetState(Kernel::HLERequestContext& ctx) { |
| 159 | State state = State::Error; | ||
| 160 | LOG_WARNING(Service_LDN, "(STUBBED) called, state = {}", state); | ||
| 161 | |||
| 162 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 163 | rb.Push(ResultSuccess); | ||
| 164 | rb.PushEnum(state); | ||
| 165 | } | ||
| 166 | |||
| 167 | void GetNetworkInfo(Kernel::HLERequestContext& ctx) { | ||
| 168 | const auto write_buffer_size = ctx.GetWriteBufferSize(); | ||
| 169 | |||
| 170 | if (write_buffer_size != sizeof(NetworkInfo)) { | ||
| 171 | LOG_ERROR(Service_LDN, "Invalid buffer size {}", write_buffer_size); | ||
| 172 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 173 | rb.Push(ResultBadInput); | ||
| 174 | return; | ||
| 175 | } | ||
| 176 | |||
| 177 | NetworkInfo network_info{}; | ||
| 178 | const auto rc = ResultSuccess; | ||
| 179 | if (rc.IsError()) { | ||
| 180 | LOG_ERROR(Service_LDN, "NetworkInfo is not valid {}", rc.raw); | ||
| 181 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 182 | rb.Push(rc); | ||
| 183 | return; | ||
| 184 | } | ||
| 185 | |||
| 186 | LOG_WARNING(Service_LDN, "(STUBBED) called, ssid='{}', nodes={}", | ||
| 187 | network_info.common.ssid.GetStringValue(), network_info.ldn.node_count); | ||
| 188 | |||
| 189 | ctx.WriteBuffer<NetworkInfo>(network_info); | ||
| 190 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 191 | rb.Push(rc); | ||
| 192 | } | ||
| 193 | |||
| 194 | void GetDisconnectReason(Kernel::HLERequestContext& ctx) { | ||
| 195 | const auto disconnect_reason = DisconnectReason::None; | ||
| 196 | |||
| 197 | LOG_WARNING(Service_LDN, "(STUBBED) called, disconnect_reason={}", disconnect_reason); | ||
| 198 | |||
| 199 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 200 | rb.Push(ResultSuccess); | ||
| 201 | rb.PushEnum(disconnect_reason); | ||
| 202 | } | ||
| 203 | |||
| 204 | void GetSecurityParameter(Kernel::HLERequestContext& ctx) { | ||
| 205 | SecurityParameter security_parameter{}; | ||
| 206 | NetworkInfo info{}; | ||
| 207 | const Result rc = ResultSuccess; | ||
| 208 | |||
| 209 | if (rc.IsError()) { | ||
| 210 | LOG_ERROR(Service_LDN, "NetworkInfo is not valid {}", rc.raw); | ||
| 211 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 212 | rb.Push(rc); | ||
| 213 | return; | ||
| 214 | } | ||
| 215 | |||
| 216 | security_parameter.session_id = info.network_id.session_id; | ||
| 217 | std::memcpy(security_parameter.data.data(), info.ldn.security_parameter.data(), | ||
| 218 | sizeof(SecurityParameter::data)); | ||
| 219 | |||
| 142 | LOG_WARNING(Service_LDN, "(STUBBED) called"); | 220 | LOG_WARNING(Service_LDN, "(STUBBED) called"); |
| 143 | 221 | ||
| 222 | IPC::ResponseBuilder rb{ctx, 10}; | ||
| 223 | rb.Push(rc); | ||
| 224 | rb.PushRaw<SecurityParameter>(security_parameter); | ||
| 225 | } | ||
| 226 | |||
| 227 | void GetNetworkConfig(Kernel::HLERequestContext& ctx) { | ||
| 228 | NetworkConfig config{}; | ||
| 229 | NetworkInfo info{}; | ||
| 230 | const Result rc = ResultSuccess; | ||
| 231 | |||
| 232 | if (rc.IsError()) { | ||
| 233 | LOG_ERROR(Service_LDN, "NetworkConfig is not valid {}", rc.raw); | ||
| 234 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 235 | rb.Push(rc); | ||
| 236 | return; | ||
| 237 | } | ||
| 238 | |||
| 239 | config.intent_id = info.network_id.intent_id; | ||
| 240 | config.channel = info.common.channel; | ||
| 241 | config.node_count_max = info.ldn.node_count_max; | ||
| 242 | config.local_communication_version = info.ldn.nodes[0].local_communication_version; | ||
| 243 | |||
| 244 | LOG_WARNING(Service_LDN, | ||
| 245 | "(STUBBED) called, intent_id={}/{}, channel={}, node_count_max={}, " | ||
| 246 | "local_communication_version={}", | ||
| 247 | config.intent_id.local_communication_id, config.intent_id.scene_id, | ||
| 248 | config.channel, config.node_count_max, config.local_communication_version); | ||
| 249 | |||
| 250 | IPC::ResponseBuilder rb{ctx, 10}; | ||
| 251 | rb.Push(rc); | ||
| 252 | rb.PushRaw<NetworkConfig>(config); | ||
| 253 | } | ||
| 254 | |||
| 255 | void AttachStateChangeEvent(Kernel::HLERequestContext& ctx) { | ||
| 256 | LOG_INFO(Service_LDN, "called"); | ||
| 257 | |||
| 258 | IPC::ResponseBuilder rb{ctx, 2, 1}; | ||
| 259 | rb.Push(ResultSuccess); | ||
| 260 | rb.PushCopyObjects(state_change_event->GetReadableEvent()); | ||
| 261 | } | ||
| 262 | |||
| 263 | void GetNetworkInfoLatestUpdate(Kernel::HLERequestContext& ctx) { | ||
| 264 | const std::size_t network_buffer_size = ctx.GetWriteBufferSize(0); | ||
| 265 | const std::size_t node_buffer_count = ctx.GetWriteBufferSize(1) / sizeof(NodeLatestUpdate); | ||
| 266 | |||
| 267 | if (node_buffer_count == 0 || network_buffer_size != sizeof(NetworkInfo)) { | ||
| 268 | LOG_ERROR(Service_LDN, "Invalid buffer size {}, {}", network_buffer_size, | ||
| 269 | node_buffer_count); | ||
| 270 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 271 | rb.Push(ResultBadInput); | ||
| 272 | return; | ||
| 273 | } | ||
| 274 | |||
| 275 | NetworkInfo info; | ||
| 276 | std::vector<NodeLatestUpdate> latest_update(node_buffer_count); | ||
| 277 | |||
| 278 | const auto rc = ResultSuccess; | ||
| 279 | if (rc.IsError()) { | ||
| 280 | LOG_ERROR(Service_LDN, "NetworkInfo is not valid {}", rc.raw); | ||
| 281 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 282 | rb.Push(rc); | ||
| 283 | return; | ||
| 284 | } | ||
| 285 | |||
| 286 | LOG_WARNING(Service_LDN, "(STUBBED) called, ssid='{}', nodes={}", | ||
| 287 | info.common.ssid.GetStringValue(), info.ldn.node_count); | ||
| 288 | |||
| 289 | ctx.WriteBuffer(info, 0); | ||
| 290 | ctx.WriteBuffer(latest_update, 1); | ||
| 291 | |||
| 292 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 293 | rb.Push(ResultSuccess); | ||
| 294 | } | ||
| 295 | |||
| 296 | void Scan(Kernel::HLERequestContext& ctx) { | ||
| 297 | ScanImpl(ctx); | ||
| 298 | } | ||
| 299 | |||
| 300 | void ScanPrivate(Kernel::HLERequestContext& ctx) { | ||
| 301 | ScanImpl(ctx, true); | ||
| 302 | } | ||
| 303 | |||
| 304 | void ScanImpl(Kernel::HLERequestContext& ctx, bool is_private = false) { | ||
| 305 | IPC::RequestParser rp{ctx}; | ||
| 306 | const auto channel{rp.PopEnum<WifiChannel>()}; | ||
| 307 | const auto scan_filter{rp.PopRaw<ScanFilter>()}; | ||
| 308 | |||
| 309 | const std::size_t network_info_size = ctx.GetWriteBufferSize() / sizeof(NetworkInfo); | ||
| 310 | |||
| 311 | if (network_info_size == 0) { | ||
| 312 | LOG_ERROR(Service_LDN, "Invalid buffer size {}", network_info_size); | ||
| 313 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 314 | rb.Push(ResultBadInput); | ||
| 315 | return; | ||
| 316 | } | ||
| 317 | |||
| 318 | u16 count = 0; | ||
| 319 | std::vector<NetworkInfo> network_infos(network_info_size); | ||
| 320 | |||
| 321 | LOG_WARNING(Service_LDN, | ||
| 322 | "(STUBBED) called, channel={}, filter_scan_flag={}, filter_network_type={}", | ||
| 323 | channel, scan_filter.flag, scan_filter.network_type); | ||
| 324 | |||
| 325 | ctx.WriteBuffer(network_infos); | ||
| 326 | |||
| 144 | IPC::ResponseBuilder rb{ctx, 3}; | 327 | IPC::ResponseBuilder rb{ctx, 3}; |
| 328 | rb.Push(ResultSuccess); | ||
| 329 | rb.Push<u32>(count); | ||
| 330 | } | ||
| 331 | |||
| 332 | void OpenAccessPoint(Kernel::HLERequestContext& ctx) { | ||
| 333 | LOG_WARNING(Service_LDN, "(STUBBED) called"); | ||
| 334 | |||
| 335 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 336 | rb.Push(ResultSuccess); | ||
| 337 | } | ||
| 338 | |||
| 339 | void CloseAccessPoint(Kernel::HLERequestContext& ctx) { | ||
| 340 | LOG_WARNING(Service_LDN, "(STUBBED) called"); | ||
| 341 | |||
| 342 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 343 | rb.Push(ResultSuccess); | ||
| 344 | } | ||
| 345 | |||
| 346 | void CreateNetwork(Kernel::HLERequestContext& ctx) { | ||
| 347 | IPC::RequestParser rp{ctx}; | ||
| 348 | struct Parameters { | ||
| 349 | SecurityConfig security_config; | ||
| 350 | UserConfig user_config; | ||
| 351 | INSERT_PADDING_WORDS_NOINIT(1); | ||
| 352 | NetworkConfig network_config; | ||
| 353 | }; | ||
| 354 | static_assert(sizeof(Parameters) == 0x98, "Parameters has incorrect size."); | ||
| 355 | |||
| 356 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 357 | |||
| 358 | LOG_WARNING(Service_LDN, | ||
| 359 | "(STUBBED) called, passphrase_size={}, security_mode={}, " | ||
| 360 | "local_communication_version={}", | ||
| 361 | parameters.security_config.passphrase_size, | ||
| 362 | parameters.security_config.security_mode, | ||
| 363 | parameters.network_config.local_communication_version); | ||
| 364 | |||
| 365 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 366 | rb.Push(ResultSuccess); | ||
| 367 | } | ||
| 368 | |||
| 369 | void CreateNetworkPrivate(Kernel::HLERequestContext& ctx) { | ||
| 370 | IPC::RequestParser rp{ctx}; | ||
| 371 | struct Parameters { | ||
| 372 | SecurityConfig security_config; | ||
| 373 | SecurityParameter security_parameter; | ||
| 374 | UserConfig user_config; | ||
| 375 | NetworkConfig network_config; | ||
| 376 | }; | ||
| 377 | static_assert(sizeof(Parameters) == 0xB8, "Parameters has incorrect size."); | ||
| 378 | |||
| 379 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 380 | |||
| 381 | LOG_WARNING(Service_LDN, | ||
| 382 | "(STUBBED) called, passphrase_size={}, security_mode={}, " | ||
| 383 | "local_communication_version={}", | ||
| 384 | parameters.security_config.passphrase_size, | ||
| 385 | parameters.security_config.security_mode, | ||
| 386 | parameters.network_config.local_communication_version); | ||
| 387 | |||
| 388 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 389 | rb.Push(ResultSuccess); | ||
| 390 | } | ||
| 391 | |||
| 392 | void DestroyNetwork(Kernel::HLERequestContext& ctx) { | ||
| 393 | LOG_WARNING(Service_LDN, "(STUBBED) called"); | ||
| 394 | |||
| 395 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 396 | rb.Push(ResultSuccess); | ||
| 397 | } | ||
| 398 | |||
| 399 | void SetAdvertiseData(Kernel::HLERequestContext& ctx) { | ||
| 400 | std::vector<u8> read_buffer = ctx.ReadBuffer(); | ||
| 401 | |||
| 402 | LOG_WARNING(Service_LDN, "(STUBBED) called, size {}", read_buffer.size()); | ||
| 403 | |||
| 404 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 405 | rb.Push(ResultSuccess); | ||
| 406 | } | ||
| 407 | |||
| 408 | void SetStationAcceptPolicy(Kernel::HLERequestContext& ctx) { | ||
| 409 | LOG_WARNING(Service_LDN, "(STUBBED) called"); | ||
| 410 | |||
| 411 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 412 | rb.Push(ResultSuccess); | ||
| 413 | } | ||
| 145 | 414 | ||
| 146 | // Indicate a network error, as we do not actually emulate LDN | 415 | void AddAcceptFilterEntry(Kernel::HLERequestContext& ctx) { |
| 147 | rb.Push(static_cast<u32>(State::Error)); | 416 | LOG_WARNING(Service_LDN, "(STUBBED) called"); |
| 148 | 417 | ||
| 418 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 419 | rb.Push(ResultSuccess); | ||
| 420 | } | ||
| 421 | |||
| 422 | void OpenStation(Kernel::HLERequestContext& ctx) { | ||
| 423 | LOG_WARNING(Service_LDN, "(STUBBED) called"); | ||
| 424 | |||
| 425 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 426 | rb.Push(ResultSuccess); | ||
| 427 | } | ||
| 428 | |||
| 429 | void CloseStation(Kernel::HLERequestContext& ctx) { | ||
| 430 | LOG_WARNING(Service_LDN, "(STUBBED) called"); | ||
| 431 | |||
| 432 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 433 | rb.Push(ResultSuccess); | ||
| 434 | } | ||
| 435 | |||
| 436 | void Connect(Kernel::HLERequestContext& ctx) { | ||
| 437 | IPC::RequestParser rp{ctx}; | ||
| 438 | struct Parameters { | ||
| 439 | SecurityConfig security_config; | ||
| 440 | UserConfig user_config; | ||
| 441 | u32 local_communication_version; | ||
| 442 | u32 option; | ||
| 443 | }; | ||
| 444 | static_assert(sizeof(Parameters) == 0x7C, "Parameters has incorrect size."); | ||
| 445 | |||
| 446 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 447 | |||
| 448 | LOG_WARNING(Service_LDN, | ||
| 449 | "(STUBBED) called, passphrase_size={}, security_mode={}, " | ||
| 450 | "local_communication_version={}", | ||
| 451 | parameters.security_config.passphrase_size, | ||
| 452 | parameters.security_config.security_mode, | ||
| 453 | parameters.local_communication_version); | ||
| 454 | |||
| 455 | const std::vector<u8> read_buffer = ctx.ReadBuffer(); | ||
| 456 | NetworkInfo network_info{}; | ||
| 457 | |||
| 458 | if (read_buffer.size() != sizeof(NetworkInfo)) { | ||
| 459 | LOG_ERROR(Frontend, "NetworkInfo doesn't match read_buffer size!"); | ||
| 460 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 461 | rb.Push(ResultBadInput); | ||
| 462 | return; | ||
| 463 | } | ||
| 464 | |||
| 465 | std::memcpy(&network_info, read_buffer.data(), read_buffer.size()); | ||
| 466 | |||
| 467 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 468 | rb.Push(ResultSuccess); | ||
| 469 | } | ||
| 470 | |||
| 471 | void Disconnect(Kernel::HLERequestContext& ctx) { | ||
| 472 | LOG_WARNING(Service_LDN, "(STUBBED) called"); | ||
| 473 | |||
| 474 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 475 | rb.Push(ResultSuccess); | ||
| 476 | } | ||
| 477 | void Initialize(Kernel::HLERequestContext& ctx) { | ||
| 478 | LOG_WARNING(Service_LDN, "(STUBBED) called"); | ||
| 479 | |||
| 480 | const auto rc = InitializeImpl(ctx); | ||
| 481 | |||
| 482 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 483 | rb.Push(rc); | ||
| 484 | } | ||
| 485 | |||
| 486 | void Finalize(Kernel::HLERequestContext& ctx) { | ||
| 487 | LOG_WARNING(Service_LDN, "(STUBBED) called"); | ||
| 488 | |||
| 489 | is_initialized = false; | ||
| 490 | |||
| 491 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 149 | rb.Push(ResultSuccess); | 492 | rb.Push(ResultSuccess); |
| 150 | } | 493 | } |
| 151 | 494 | ||
| 152 | void Initialize2(Kernel::HLERequestContext& ctx) { | 495 | void Initialize2(Kernel::HLERequestContext& ctx) { |
| 153 | LOG_DEBUG(Service_LDN, "called"); | 496 | LOG_WARNING(Service_LDN, "(STUBBED) called"); |
| 154 | 497 | ||
| 155 | is_initialized = true; | 498 | const auto rc = InitializeImpl(ctx); |
| 156 | 499 | ||
| 157 | IPC::ResponseBuilder rb{ctx, 2}; | 500 | IPC::ResponseBuilder rb{ctx, 2}; |
| 158 | rb.Push(ERROR_DISABLED); | 501 | rb.Push(rc); |
| 502 | } | ||
| 503 | |||
| 504 | Result InitializeImpl(Kernel::HLERequestContext& ctx) { | ||
| 505 | const auto network_interface = Network::GetSelectedNetworkInterface(); | ||
| 506 | if (!network_interface) { | ||
| 507 | LOG_ERROR(Service_LDN, "No network interface is set"); | ||
| 508 | return ResultAirplaneModeEnabled; | ||
| 509 | } | ||
| 510 | |||
| 511 | is_initialized = true; | ||
| 512 | // TODO (flTobi): Change this to ResultSuccess when LDN is fully implemented | ||
| 513 | return ResultAirplaneModeEnabled; | ||
| 159 | } | 514 | } |
| 160 | 515 | ||
| 161 | private: | 516 | KernelHelpers::ServiceContext service_context; |
| 162 | enum class State { | 517 | Kernel::KEvent* state_change_event; |
| 163 | None, | 518 | Network::RoomNetwork& room_network; |
| 164 | Initialized, | ||
| 165 | AccessPointOpened, | ||
| 166 | AccessPointCreated, | ||
| 167 | StationOpened, | ||
| 168 | StationConnected, | ||
| 169 | Error, | ||
| 170 | }; | ||
| 171 | 519 | ||
| 172 | bool is_initialized{}; | 520 | bool is_initialized{}; |
| 173 | }; | 521 | }; |
| @@ -273,7 +621,7 @@ public: | |||
| 273 | LOG_WARNING(Service_LDN, "(STUBBED) called"); | 621 | LOG_WARNING(Service_LDN, "(STUBBED) called"); |
| 274 | 622 | ||
| 275 | IPC::ResponseBuilder rb{ctx, 2}; | 623 | IPC::ResponseBuilder rb{ctx, 2}; |
| 276 | rb.Push(ERROR_DISABLED); | 624 | rb.Push(ResultDisabled); |
| 277 | } | 625 | } |
| 278 | }; | 626 | }; |
| 279 | 627 | ||
diff --git a/src/core/hle/service/ldn/ldn.h b/src/core/hle/service/ldn/ldn.h index a0031ac71..6afe2ea6f 100644 --- a/src/core/hle/service/ldn/ldn.h +++ b/src/core/hle/service/ldn/ldn.h | |||
| @@ -3,6 +3,12 @@ | |||
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include "core/hle/ipc_helpers.h" | ||
| 7 | #include "core/hle/kernel/k_event.h" | ||
| 8 | #include "core/hle/result.h" | ||
| 9 | #include "core/hle/service/kernel_helpers.h" | ||
| 10 | #include "core/hle/service/sm/sm.h" | ||
| 11 | |||
| 6 | namespace Core { | 12 | namespace Core { |
| 7 | class System; | 13 | class System; |
| 8 | } | 14 | } |
diff --git a/src/core/hle/service/ldn/ldn_results.h b/src/core/hle/service/ldn/ldn_results.h new file mode 100644 index 000000000..f340bda42 --- /dev/null +++ b/src/core/hle/service/ldn/ldn_results.h | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "core/hle/result.h" | ||
| 7 | |||
| 8 | namespace Service::LDN { | ||
| 9 | |||
| 10 | constexpr Result ResultAdvertiseDataTooLarge{ErrorModule::LDN, 10}; | ||
| 11 | constexpr Result ResultAuthenticationFailed{ErrorModule::LDN, 20}; | ||
| 12 | constexpr Result ResultDisabled{ErrorModule::LDN, 22}; | ||
| 13 | constexpr Result ResultAirplaneModeEnabled{ErrorModule::LDN, 23}; | ||
| 14 | constexpr Result ResultInvalidNodeCount{ErrorModule::LDN, 30}; | ||
| 15 | constexpr Result ResultConnectionFailed{ErrorModule::LDN, 31}; | ||
| 16 | constexpr Result ResultBadState{ErrorModule::LDN, 32}; | ||
| 17 | constexpr Result ResultNoIpAddress{ErrorModule::LDN, 33}; | ||
| 18 | constexpr Result ResultInvalidBufferCount{ErrorModule::LDN, 50}; | ||
| 19 | constexpr Result ResultAccessPointConnectionFailed{ErrorModule::LDN, 65}; | ||
| 20 | constexpr Result ResultAuthenticationTimeout{ErrorModule::LDN, 66}; | ||
| 21 | constexpr Result ResultMaximumNodeCount{ErrorModule::LDN, 67}; | ||
| 22 | constexpr Result ResultBadInput{ErrorModule::LDN, 96}; | ||
| 23 | constexpr Result ResultLocalCommunicationIdNotFound{ErrorModule::LDN, 97}; | ||
| 24 | constexpr Result ResultLocalCommunicationVersionTooLow{ErrorModule::LDN, 113}; | ||
| 25 | constexpr Result ResultLocalCommunicationVersionTooHigh{ErrorModule::LDN, 114}; | ||
| 26 | |||
| 27 | } // namespace Service::LDN | ||
diff --git a/src/core/hle/service/ldn/ldn_types.h b/src/core/hle/service/ldn/ldn_types.h new file mode 100644 index 000000000..0c07a7397 --- /dev/null +++ b/src/core/hle/service/ldn/ldn_types.h | |||
| @@ -0,0 +1,284 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <fmt/format.h> | ||
| 7 | |||
| 8 | #include "common/common_funcs.h" | ||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "network/network.h" | ||
| 11 | |||
| 12 | namespace Service::LDN { | ||
| 13 | |||
| 14 | constexpr size_t SsidLengthMax = 32; | ||
| 15 | constexpr size_t AdvertiseDataSizeMax = 384; | ||
| 16 | constexpr size_t UserNameBytesMax = 32; | ||
| 17 | constexpr int NodeCountMax = 8; | ||
| 18 | constexpr int StationCountMax = NodeCountMax - 1; | ||
| 19 | constexpr size_t PassphraseLengthMax = 64; | ||
| 20 | |||
| 21 | enum class SecurityMode : u16 { | ||
| 22 | All, | ||
| 23 | Retail, | ||
| 24 | Debug, | ||
| 25 | }; | ||
| 26 | |||
| 27 | enum class NodeStateChange : u8 { | ||
| 28 | None, | ||
| 29 | Connect, | ||
| 30 | Disconnect, | ||
| 31 | DisconnectAndConnect, | ||
| 32 | }; | ||
| 33 | |||
| 34 | enum class ScanFilterFlag : u32 { | ||
| 35 | None = 0, | ||
| 36 | LocalCommunicationId = 1 << 0, | ||
| 37 | SessionId = 1 << 1, | ||
| 38 | NetworkType = 1 << 2, | ||
| 39 | Ssid = 1 << 4, | ||
| 40 | SceneId = 1 << 5, | ||
| 41 | IntentId = LocalCommunicationId | SceneId, | ||
| 42 | NetworkId = IntentId | SessionId, | ||
| 43 | }; | ||
| 44 | |||
| 45 | enum class NetworkType : u32 { | ||
| 46 | None, | ||
| 47 | General, | ||
| 48 | Ldn, | ||
| 49 | All, | ||
| 50 | }; | ||
| 51 | |||
| 52 | enum class PackedNetworkType : u8 { | ||
| 53 | None, | ||
| 54 | General, | ||
| 55 | Ldn, | ||
| 56 | All, | ||
| 57 | }; | ||
| 58 | |||
| 59 | enum class State : u32 { | ||
| 60 | None, | ||
| 61 | Initialized, | ||
| 62 | AccessPointOpened, | ||
| 63 | AccessPointCreated, | ||
| 64 | StationOpened, | ||
| 65 | StationConnected, | ||
| 66 | Error, | ||
| 67 | }; | ||
| 68 | |||
| 69 | enum class DisconnectReason : s16 { | ||
| 70 | Unknown = -1, | ||
| 71 | None, | ||
| 72 | DisconnectedByUser, | ||
| 73 | DisconnectedBySystem, | ||
| 74 | DestroyedByUser, | ||
| 75 | DestroyedBySystem, | ||
| 76 | Rejected, | ||
| 77 | SignalLost, | ||
| 78 | }; | ||
| 79 | |||
| 80 | enum class NetworkError { | ||
| 81 | Unknown = -1, | ||
| 82 | None = 0, | ||
| 83 | PortUnreachable, | ||
| 84 | TooManyPlayers, | ||
| 85 | VersionTooLow, | ||
| 86 | VersionTooHigh, | ||
| 87 | ConnectFailure, | ||
| 88 | ConnectNotFound, | ||
| 89 | ConnectTimeout, | ||
| 90 | ConnectRejected, | ||
| 91 | RejectFailed, | ||
| 92 | }; | ||
| 93 | |||
| 94 | enum class AcceptPolicy : u8 { | ||
| 95 | AcceptAll, | ||
| 96 | RejectAll, | ||
| 97 | BlackList, | ||
| 98 | WhiteList, | ||
| 99 | }; | ||
| 100 | |||
| 101 | enum class WifiChannel : s16 { | ||
| 102 | Default = 0, | ||
| 103 | wifi24_1 = 1, | ||
| 104 | wifi24_6 = 6, | ||
| 105 | wifi24_11 = 11, | ||
| 106 | wifi50_36 = 36, | ||
| 107 | wifi50_40 = 40, | ||
| 108 | wifi50_44 = 44, | ||
| 109 | wifi50_48 = 48, | ||
| 110 | }; | ||
| 111 | |||
| 112 | enum class LinkLevel : s8 { | ||
| 113 | Bad, | ||
| 114 | Low, | ||
| 115 | Good, | ||
| 116 | Excelent, | ||
| 117 | }; | ||
| 118 | |||
| 119 | struct NodeLatestUpdate { | ||
| 120 | NodeStateChange state_change; | ||
| 121 | INSERT_PADDING_BYTES(0x7); // Unknown | ||
| 122 | }; | ||
| 123 | static_assert(sizeof(NodeLatestUpdate) == 0x8, "NodeLatestUpdate is an invalid size"); | ||
| 124 | |||
| 125 | struct SessionId { | ||
| 126 | u64 high; | ||
| 127 | u64 low; | ||
| 128 | |||
| 129 | bool operator==(const SessionId&) const = default; | ||
| 130 | }; | ||
| 131 | static_assert(sizeof(SessionId) == 0x10, "SessionId is an invalid size"); | ||
| 132 | |||
| 133 | struct IntentId { | ||
| 134 | u64 local_communication_id; | ||
| 135 | INSERT_PADDING_BYTES(0x2); // Reserved | ||
| 136 | u16 scene_id; | ||
| 137 | INSERT_PADDING_BYTES(0x4); // Reserved | ||
| 138 | }; | ||
| 139 | static_assert(sizeof(IntentId) == 0x10, "IntentId is an invalid size"); | ||
| 140 | |||
| 141 | struct NetworkId { | ||
| 142 | IntentId intent_id; | ||
| 143 | SessionId session_id; | ||
| 144 | }; | ||
| 145 | static_assert(sizeof(NetworkId) == 0x20, "NetworkId is an invalid size"); | ||
| 146 | |||
| 147 | struct Ssid { | ||
| 148 | u8 length; | ||
| 149 | std::array<char, SsidLengthMax + 1> raw; | ||
| 150 | |||
| 151 | std::string GetStringValue() const { | ||
| 152 | return std::string(raw.data(), length); | ||
| 153 | } | ||
| 154 | }; | ||
| 155 | static_assert(sizeof(Ssid) == 0x22, "Ssid is an invalid size"); | ||
| 156 | |||
| 157 | struct Ipv4Address { | ||
| 158 | union { | ||
| 159 | u32 raw{}; | ||
| 160 | std::array<u8, 4> bytes; | ||
| 161 | }; | ||
| 162 | |||
| 163 | std::string GetStringValue() const { | ||
| 164 | return fmt::format("{}.{}.{}.{}", bytes[3], bytes[2], bytes[1], bytes[0]); | ||
| 165 | } | ||
| 166 | }; | ||
| 167 | static_assert(sizeof(Ipv4Address) == 0x4, "Ipv4Address is an invalid size"); | ||
| 168 | |||
| 169 | struct MacAddress { | ||
| 170 | std::array<u8, 6> raw{}; | ||
| 171 | |||
| 172 | friend bool operator==(const MacAddress& lhs, const MacAddress& rhs) = default; | ||
| 173 | }; | ||
| 174 | static_assert(sizeof(MacAddress) == 0x6, "MacAddress is an invalid size"); | ||
| 175 | |||
| 176 | struct ScanFilter { | ||
| 177 | NetworkId network_id; | ||
| 178 | NetworkType network_type; | ||
| 179 | MacAddress mac_address; | ||
| 180 | Ssid ssid; | ||
| 181 | INSERT_PADDING_BYTES(0x10); | ||
| 182 | ScanFilterFlag flag; | ||
| 183 | }; | ||
| 184 | static_assert(sizeof(ScanFilter) == 0x60, "ScanFilter is an invalid size"); | ||
| 185 | |||
| 186 | struct CommonNetworkInfo { | ||
| 187 | MacAddress bssid; | ||
| 188 | Ssid ssid; | ||
| 189 | WifiChannel channel; | ||
| 190 | LinkLevel link_level; | ||
| 191 | PackedNetworkType network_type; | ||
| 192 | INSERT_PADDING_BYTES(0x4); | ||
| 193 | }; | ||
| 194 | static_assert(sizeof(CommonNetworkInfo) == 0x30, "CommonNetworkInfo is an invalid size"); | ||
| 195 | |||
| 196 | struct NodeInfo { | ||
| 197 | Ipv4Address ipv4_address; | ||
| 198 | MacAddress mac_address; | ||
| 199 | s8 node_id; | ||
| 200 | u8 is_connected; | ||
| 201 | std::array<u8, UserNameBytesMax + 1> user_name; | ||
| 202 | INSERT_PADDING_BYTES(0x1); // Reserved | ||
| 203 | s16 local_communication_version; | ||
| 204 | INSERT_PADDING_BYTES(0x10); // Reserved | ||
| 205 | }; | ||
| 206 | static_assert(sizeof(NodeInfo) == 0x40, "NodeInfo is an invalid size"); | ||
| 207 | |||
| 208 | struct LdnNetworkInfo { | ||
| 209 | std::array<u8, 0x10> security_parameter; | ||
| 210 | SecurityMode security_mode; | ||
| 211 | AcceptPolicy station_accept_policy; | ||
| 212 | u8 has_action_frame; | ||
| 213 | INSERT_PADDING_BYTES(0x2); // Padding | ||
| 214 | u8 node_count_max; | ||
| 215 | u8 node_count; | ||
| 216 | std::array<NodeInfo, NodeCountMax> nodes; | ||
| 217 | INSERT_PADDING_BYTES(0x2); // Reserved | ||
| 218 | u16 advertise_data_size; | ||
| 219 | std::array<u8, AdvertiseDataSizeMax> advertise_data; | ||
| 220 | INSERT_PADDING_BYTES(0x8C); // Reserved | ||
| 221 | u64 random_authentication_id; | ||
| 222 | }; | ||
| 223 | static_assert(sizeof(LdnNetworkInfo) == 0x430, "LdnNetworkInfo is an invalid size"); | ||
| 224 | |||
| 225 | struct NetworkInfo { | ||
| 226 | NetworkId network_id; | ||
| 227 | CommonNetworkInfo common; | ||
| 228 | LdnNetworkInfo ldn; | ||
| 229 | }; | ||
| 230 | static_assert(sizeof(NetworkInfo) == 0x480, "NetworkInfo is an invalid size"); | ||
| 231 | |||
| 232 | struct SecurityConfig { | ||
| 233 | SecurityMode security_mode; | ||
| 234 | u16 passphrase_size; | ||
| 235 | std::array<u8, PassphraseLengthMax> passphrase; | ||
| 236 | }; | ||
| 237 | static_assert(sizeof(SecurityConfig) == 0x44, "SecurityConfig is an invalid size"); | ||
| 238 | |||
| 239 | struct UserConfig { | ||
| 240 | std::array<u8, UserNameBytesMax + 1> user_name; | ||
| 241 | INSERT_PADDING_BYTES(0xF); // Reserved | ||
| 242 | }; | ||
| 243 | static_assert(sizeof(UserConfig) == 0x30, "UserConfig is an invalid size"); | ||
| 244 | |||
| 245 | #pragma pack(push, 4) | ||
| 246 | struct ConnectRequest { | ||
| 247 | SecurityConfig security_config; | ||
| 248 | UserConfig user_config; | ||
| 249 | u32 local_communication_version; | ||
| 250 | u32 option_unknown; | ||
| 251 | NetworkInfo network_info; | ||
| 252 | }; | ||
| 253 | static_assert(sizeof(ConnectRequest) == 0x4FC, "ConnectRequest is an invalid size"); | ||
| 254 | #pragma pack(pop) | ||
| 255 | |||
| 256 | struct SecurityParameter { | ||
| 257 | std::array<u8, 0x10> data; // Data, used with the same key derivation as SecurityConfig | ||
| 258 | SessionId session_id; | ||
| 259 | }; | ||
| 260 | static_assert(sizeof(SecurityParameter) == 0x20, "SecurityParameter is an invalid size"); | ||
| 261 | |||
| 262 | struct NetworkConfig { | ||
| 263 | IntentId intent_id; | ||
| 264 | WifiChannel channel; | ||
| 265 | u8 node_count_max; | ||
| 266 | INSERT_PADDING_BYTES(0x1); // Reserved | ||
| 267 | u16 local_communication_version; | ||
| 268 | INSERT_PADDING_BYTES(0xA); // Reserved | ||
| 269 | }; | ||
| 270 | static_assert(sizeof(NetworkConfig) == 0x20, "NetworkConfig is an invalid size"); | ||
| 271 | |||
| 272 | struct AddressEntry { | ||
| 273 | Ipv4Address ipv4_address; | ||
| 274 | MacAddress mac_address; | ||
| 275 | INSERT_PADDING_BYTES(0x2); // Reserved | ||
| 276 | }; | ||
| 277 | static_assert(sizeof(AddressEntry) == 0xC, "AddressEntry is an invalid size"); | ||
| 278 | |||
| 279 | struct AddressList { | ||
| 280 | std::array<AddressEntry, 0x8> addresses; | ||
| 281 | }; | ||
| 282 | static_assert(sizeof(AddressList) == 0x60, "AddressList is an invalid size"); | ||
| 283 | |||
| 284 | } // namespace Service::LDN | ||
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp index fa8efd22e..a69ae7725 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.cpp +++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp | |||
| @@ -33,9 +33,10 @@ VkSurfaceFormatKHR ChooseSwapSurfaceFormat(vk::Span<VkSurfaceFormatKHR> formats) | |||
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | VkPresentModeKHR ChooseSwapPresentMode(vk::Span<VkPresentModeKHR> modes) { | 35 | VkPresentModeKHR ChooseSwapPresentMode(vk::Span<VkPresentModeKHR> modes) { |
| 36 | // Mailbox doesn't lock the application like fifo (vsync), prefer it | 36 | // Mailbox (triple buffering) doesn't lock the application like fifo (vsync), |
| 37 | // prefer it if vsync option is not selected | ||
| 37 | const auto found_mailbox = std::find(modes.begin(), modes.end(), VK_PRESENT_MODE_MAILBOX_KHR); | 38 | const auto found_mailbox = std::find(modes.begin(), modes.end(), VK_PRESENT_MODE_MAILBOX_KHR); |
| 38 | if (found_mailbox != modes.end()) { | 39 | if (found_mailbox != modes.end() && !Settings::values.use_vsync.GetValue()) { |
| 39 | return VK_PRESENT_MODE_MAILBOX_KHR; | 40 | return VK_PRESENT_MODE_MAILBOX_KHR; |
| 40 | } | 41 | } |
| 41 | if (!Settings::values.use_speed_limit.GetValue()) { | 42 | if (!Settings::values.use_speed_limit.GetValue()) { |
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index f6b389ede..50007338f 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt | |||
| @@ -221,6 +221,9 @@ if (ENABLE_QT_TRANSLATION) | |||
| 221 | # Update source TS file if enabled | 221 | # Update source TS file if enabled |
| 222 | if (GENERATE_QT_TRANSLATION) | 222 | if (GENERATE_QT_TRANSLATION) |
| 223 | get_target_property(SRCS yuzu SOURCES) | 223 | get_target_property(SRCS yuzu SOURCES) |
| 224 | # these calls to qt_create_translation also creates a rule to generate en.qm which conflicts with providing english plurals | ||
| 225 | # so we have to set a OUTPUT_LOCATION so that we don't have multiple rules to generate en.qm | ||
| 226 | set_source_files_properties(${YUZU_QT_LANGUAGES}/en.ts PROPERTIES OUTPUT_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/translations") | ||
| 224 | qt_create_translation(QM_FILES | 227 | qt_create_translation(QM_FILES |
| 225 | ${SRCS} | 228 | ${SRCS} |
| 226 | ${UIS} | 229 | ${UIS} |
| @@ -229,7 +232,13 @@ if (ENABLE_QT_TRANSLATION) | |||
| 229 | -source-language en_US | 232 | -source-language en_US |
| 230 | -target-language en_US | 233 | -target-language en_US |
| 231 | ) | 234 | ) |
| 232 | add_custom_target(translation ALL DEPENDS ${YUZU_QT_LANGUAGES}/en.ts) | 235 | |
| 236 | # Generate plurals into dist/english_plurals/generated_en.ts so it can be used to revise dist/english_plurals/en.ts | ||
| 237 | set(GENERATED_PLURALS_FILE ${PROJECT_SOURCE_DIR}/dist/english_plurals/generated_en.ts) | ||
| 238 | set_source_files_properties(${GENERATED_PLURALS_FILE} PROPERTIES OUTPUT_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/plurals") | ||
| 239 | qt_create_translation(QM_FILES ${SRCS} ${UIS} ${GENERATED_PLURALS_FILE} OPTIONS -pluralonly -source-language en_US -target-language en_US) | ||
| 240 | |||
| 241 | add_custom_target(translation ALL DEPENDS ${YUZU_QT_LANGUAGES}/en.ts ${GENERATED_PLURALS_FILE}) | ||
| 233 | endif() | 242 | endif() |
| 234 | 243 | ||
| 235 | # Find all TS files except en.ts | 244 | # Find all TS files except en.ts |
| @@ -239,6 +248,9 @@ if (ENABLE_QT_TRANSLATION) | |||
| 239 | # Compile TS files to QM files | 248 | # Compile TS files to QM files |
| 240 | qt_add_translation(LANGUAGES_QM ${LANGUAGES_TS}) | 249 | qt_add_translation(LANGUAGES_QM ${LANGUAGES_TS}) |
| 241 | 250 | ||
| 251 | # Compile english plurals TS file to en.qm | ||
| 252 | qt_add_translation(LANGUAGES_QM ${PROJECT_SOURCE_DIR}/dist/english_plurals/en.ts) | ||
| 253 | |||
| 242 | # Build a QRC file from the QM file list | 254 | # Build a QRC file from the QM file list |
| 243 | set(LANGUAGES_QRC ${CMAKE_CURRENT_BINARY_DIR}/languages.qrc) | 255 | set(LANGUAGES_QRC ${CMAKE_CURRENT_BINARY_DIR}/languages.qrc) |
| 244 | file(WRITE ${LANGUAGES_QRC} "<RCC><qresource prefix=\"languages\">\n") | 256 | file(WRITE ${LANGUAGES_QRC} "<RCC><qresource prefix=\"languages\">\n") |
diff --git a/src/yuzu/aboutdialog.ui b/src/yuzu/aboutdialog.ui index c4ffb293e..aea82809d 100644 --- a/src/yuzu/aboutdialog.ui +++ b/src/yuzu/aboutdialog.ui | |||
| @@ -7,7 +7,7 @@ | |||
| 7 | <x>0</x> | 7 | <x>0</x> |
| 8 | <y>0</y> | 8 | <y>0</y> |
| 9 | <width>616</width> | 9 | <width>616</width> |
| 10 | <height>261</height> | 10 | <height>294</height> |
| 11 | </rect> | 11 | </rect> |
| 12 | </property> | 12 | </property> |
| 13 | <property name="windowTitle"> | 13 | <property name="windowTitle"> |
| @@ -165,6 +165,7 @@ p, li { white-space: pre-wrap; } | |||
| 165 | </widget> | 165 | </widget> |
| 166 | <resources> | 166 | <resources> |
| 167 | <include location="../../dist/qt_themes_default/default/default.qrc"/> | 167 | <include location="../../dist/qt_themes_default/default/default.qrc"/> |
| 168 | <include location="../../dist/qt_themes/default/default.qrc"/> | ||
| 168 | </resources> | 169 | </resources> |
| 169 | <connections> | 170 | <connections> |
| 170 | <connection> | 171 | <connection> |
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 58f1239bf..da6e5aa88 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp | |||
| @@ -73,7 +73,7 @@ const std::array<int, 2> Config::default_ringcon_analogs{{ | |||
| 73 | const std::array<UISettings::Shortcut, 22> Config::default_hotkeys{{ | 73 | const std::array<UISettings::Shortcut, 22> Config::default_hotkeys{{ |
| 74 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Mute/Unmute")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+M"), QStringLiteral("Home+Dpad_Right"), Qt::WindowShortcut}}, | 74 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Mute/Unmute")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+M"), QStringLiteral("Home+Dpad_Right"), Qt::WindowShortcut}}, |
| 75 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Down")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("-"), QStringLiteral("Home+Dpad_Down"), Qt::ApplicationShortcut}}, | 75 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Down")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("-"), QStringLiteral("Home+Dpad_Down"), Qt::ApplicationShortcut}}, |
| 76 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Up")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("+"), QStringLiteral("Home+Dpad_Up"), Qt::ApplicationShortcut}}, | 76 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Up")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("="), QStringLiteral("Home+Dpad_Up"), Qt::ApplicationShortcut}}, |
| 77 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Capture Screenshot")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+P"), QStringLiteral("Screenshot"), Qt::WidgetWithChildrenShortcut}}, | 77 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Capture Screenshot")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+P"), QStringLiteral("Screenshot"), Qt::WidgetWithChildrenShortcut}}, |
| 78 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Adapting Filter")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F8"), QStringLiteral("Home+L"), Qt::ApplicationShortcut}}, | 78 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Adapting Filter")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F8"), QStringLiteral("Home+L"), Qt::ApplicationShortcut}}, |
| 79 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Docked Mode")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F10"), QStringLiteral("Home+X"), Qt::ApplicationShortcut}}, | 79 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Docked Mode")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F10"), QStringLiteral("Home+X"), Qt::ApplicationShortcut}}, |
diff --git a/src/yuzu/configuration/configure_audio.ui b/src/yuzu/configuration/configure_audio.ui index a5bcee415..6034d8581 100644 --- a/src/yuzu/configuration/configure_audio.ui +++ b/src/yuzu/configuration/configure_audio.ui | |||
| @@ -120,10 +120,10 @@ | |||
| 120 | </sizepolicy> | 120 | </sizepolicy> |
| 121 | </property> | 121 | </property> |
| 122 | <property name="maximum"> | 122 | <property name="maximum"> |
| 123 | <number>100</number> | 123 | <number>200</number> |
| 124 | </property> | 124 | </property> |
| 125 | <property name="pageStep"> | 125 | <property name="pageStep"> |
| 126 | <number>10</number> | 126 | <number>5</number> |
| 127 | </property> | 127 | </property> |
| 128 | <property name="orientation"> | 128 | <property name="orientation"> |
| 129 | <enum>Qt::Horizontal</enum> | 129 | <enum>Qt::Horizontal</enum> |
diff --git a/src/yuzu/configuration/configure_graphics_advanced.ui b/src/yuzu/configuration/configure_graphics_advanced.ui index 96de0b3d1..d6d819364 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.ui +++ b/src/yuzu/configuration/configure_graphics_advanced.ui | |||
| @@ -75,7 +75,7 @@ | |||
| 75 | <string>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference.</string> | 75 | <string>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference.</string> |
| 76 | </property> | 76 | </property> |
| 77 | <property name="text"> | 77 | <property name="text"> |
| 78 | <string>Use VSync (OpenGL only)</string> | 78 | <string>Use VSync</string> |
| 79 | </property> | 79 | </property> |
| 80 | </widget> | 80 | </widget> |
| 81 | </item> | 81 | </item> |
diff --git a/src/yuzu/configuration/configure_ui.cpp b/src/yuzu/configuration/configure_ui.cpp index 2e98ede8e..48f71b53c 100644 --- a/src/yuzu/configuration/configure_ui.cpp +++ b/src/yuzu/configuration/configure_ui.cpp | |||
| @@ -219,6 +219,7 @@ void ConfigureUi::InitializeLanguageComboBox() { | |||
| 219 | for (const auto& lang : languages) { | 219 | for (const auto& lang : languages) { |
| 220 | if (QString::fromLatin1(lang.id) == QStringLiteral("en")) { | 220 | if (QString::fromLatin1(lang.id) == QStringLiteral("en")) { |
| 221 | ui->language_combobox->addItem(lang.name, QStringLiteral("en")); | 221 | ui->language_combobox->addItem(lang.name, QStringLiteral("en")); |
| 222 | language_files.removeOne(QStringLiteral("en.qm")); | ||
| 222 | continue; | 223 | continue; |
| 223 | } | 224 | } |
| 224 | for (int i = 0; i < language_files.size(); ++i) { | 225 | for (int i = 0; i < language_files.size(); ++i) { |
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 041e6ac11..c4b1f65bd 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp | |||
| @@ -286,7 +286,7 @@ void GameList::OnUpdateThemedIcons() { | |||
| 286 | } | 286 | } |
| 287 | case GameListItemType::AddDir: | 287 | case GameListItemType::AddDir: |
| 288 | child->setData( | 288 | child->setData( |
| 289 | QIcon::fromTheme(QStringLiteral("plus")) | 289 | QIcon::fromTheme(QStringLiteral("list-add")) |
| 290 | .pixmap(icon_size) | 290 | .pixmap(icon_size) |
| 291 | .scaled(icon_size, icon_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), | 291 | .scaled(icon_size, icon_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), |
| 292 | Qt::DecorationRole); | 292 | Qt::DecorationRole); |
diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h index e7667cf60..0e19be22d 100644 --- a/src/yuzu/game_list_p.h +++ b/src/yuzu/game_list_p.h | |||
| @@ -294,7 +294,7 @@ public: | |||
| 294 | 294 | ||
| 295 | const int icon_size = UISettings::values.folder_icon_size.GetValue(); | 295 | const int icon_size = UISettings::values.folder_icon_size.GetValue(); |
| 296 | 296 | ||
| 297 | setData(QIcon::fromTheme(QStringLiteral("plus")) | 297 | setData(QIcon::fromTheme(QStringLiteral("list-add")) |
| 298 | .pixmap(icon_size) | 298 | .pixmap(icon_size) |
| 299 | .scaled(icon_size, icon_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), | 299 | .scaled(icon_size, icon_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), |
| 300 | Qt::DecorationRole); | 300 | Qt::DecorationRole); |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 653280642..8bd1f92f7 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -257,6 +257,18 @@ static QString PrettyProductName() { | |||
| 257 | return QSysInfo::prettyProductName(); | 257 | return QSysInfo::prettyProductName(); |
| 258 | } | 258 | } |
| 259 | 259 | ||
| 260 | bool GMainWindow::CheckDarkMode() { | ||
| 261 | #ifdef __linux__ | ||
| 262 | const QPalette test_palette(qApp->palette()); | ||
| 263 | const QColor text_color = test_palette.color(QPalette::Active, QPalette::Text); | ||
| 264 | const QColor window_color = test_palette.color(QPalette::Active, QPalette::Window); | ||
| 265 | return (text_color.value() > window_color.value()); | ||
| 266 | #else | ||
| 267 | // TODO: Windows | ||
| 268 | return false; | ||
| 269 | #endif // __linux__ | ||
| 270 | } | ||
| 271 | |||
| 260 | GMainWindow::GMainWindow(bool has_broken_vulkan) | 272 | GMainWindow::GMainWindow(bool has_broken_vulkan) |
| 261 | : ui{std::make_unique<Ui::MainWindow>()}, system{std::make_unique<Core::System>()}, | 273 | : ui{std::make_unique<Ui::MainWindow>()}, system{std::make_unique<Core::System>()}, |
| 262 | input_subsystem{std::make_shared<InputCommon::InputSubsystem>()}, | 274 | input_subsystem{std::make_shared<InputCommon::InputSubsystem>()}, |
| @@ -274,6 +286,13 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) | |||
| 274 | ui->setupUi(this); | 286 | ui->setupUi(this); |
| 275 | statusBar()->hide(); | 287 | statusBar()->hide(); |
| 276 | 288 | ||
| 289 | // Check dark mode before a theme is loaded | ||
| 290 | os_dark_mode = CheckDarkMode(); | ||
| 291 | startup_icon_theme = QIcon::themeName(); | ||
| 292 | // fallback can only be set once, colorful theme icons are okay on both light/dark | ||
| 293 | QIcon::setFallbackThemeName(QStringLiteral("colorful")); | ||
| 294 | QIcon::setFallbackSearchPaths(QStringList(QStringLiteral(":/icons"))); | ||
| 295 | |||
| 277 | default_theme_paths = QIcon::themeSearchPaths(); | 296 | default_theme_paths = QIcon::themeSearchPaths(); |
| 278 | UpdateUITheme(); | 297 | UpdateUITheme(); |
| 279 | 298 | ||
| @@ -1075,7 +1094,7 @@ void GMainWindow::InitializeHotkeys() { | |||
| 1075 | connect_shortcut(QStringLiteral("Audio Mute/Unmute"), | 1094 | connect_shortcut(QStringLiteral("Audio Mute/Unmute"), |
| 1076 | [] { Settings::values.audio_muted = !Settings::values.audio_muted; }); | 1095 | [] { Settings::values.audio_muted = !Settings::values.audio_muted; }); |
| 1077 | connect_shortcut(QStringLiteral("Audio Volume Down"), [] { | 1096 | connect_shortcut(QStringLiteral("Audio Volume Down"), [] { |
| 1078 | const auto current_volume = static_cast<int>(Settings::values.volume.GetValue()); | 1097 | const auto current_volume = static_cast<s32>(Settings::values.volume.GetValue()); |
| 1079 | int step = 5; | 1098 | int step = 5; |
| 1080 | if (current_volume <= 30) { | 1099 | if (current_volume <= 30) { |
| 1081 | step = 2; | 1100 | step = 2; |
| @@ -1083,11 +1102,10 @@ void GMainWindow::InitializeHotkeys() { | |||
| 1083 | if (current_volume <= 6) { | 1102 | if (current_volume <= 6) { |
| 1084 | step = 1; | 1103 | step = 1; |
| 1085 | } | 1104 | } |
| 1086 | const auto new_volume = std::max(current_volume - step, 0); | 1105 | Settings::values.volume.SetValue(std::max(current_volume - step, 0)); |
| 1087 | Settings::values.volume.SetValue(static_cast<u8>(new_volume)); | ||
| 1088 | }); | 1106 | }); |
| 1089 | connect_shortcut(QStringLiteral("Audio Volume Up"), [] { | 1107 | connect_shortcut(QStringLiteral("Audio Volume Up"), [] { |
| 1090 | const auto current_volume = static_cast<int>(Settings::values.volume.GetValue()); | 1108 | const auto current_volume = static_cast<s32>(Settings::values.volume.GetValue()); |
| 1091 | int step = 5; | 1109 | int step = 5; |
| 1092 | if (current_volume < 30) { | 1110 | if (current_volume < 30) { |
| 1093 | step = 2; | 1111 | step = 2; |
| @@ -1095,8 +1113,7 @@ void GMainWindow::InitializeHotkeys() { | |||
| 1095 | if (current_volume < 6) { | 1113 | if (current_volume < 6) { |
| 1096 | step = 1; | 1114 | step = 1; |
| 1097 | } | 1115 | } |
| 1098 | const auto new_volume = std::min(current_volume + step, 100); | 1116 | Settings::values.volume.SetValue(current_volume + step); |
| 1099 | Settings::values.volume.SetValue(static_cast<u8>(new_volume)); | ||
| 1100 | }); | 1117 | }); |
| 1101 | connect_shortcut(QStringLiteral("Toggle Framerate Limit"), [] { | 1118 | connect_shortcut(QStringLiteral("Toggle Framerate Limit"), [] { |
| 1102 | Settings::values.use_speed_limit.SetValue(!Settings::values.use_speed_limit.GetValue()); | 1119 | Settings::values.use_speed_limit.SetValue(!Settings::values.use_speed_limit.GetValue()); |
| @@ -3935,8 +3952,21 @@ void GMainWindow::filterBarSetChecked(bool state) { | |||
| 3935 | emit(OnToggleFilterBar()); | 3952 | emit(OnToggleFilterBar()); |
| 3936 | } | 3953 | } |
| 3937 | 3954 | ||
| 3955 | static void AdjustLinkColor() { | ||
| 3956 | QPalette new_pal(qApp->palette()); | ||
| 3957 | if (UISettings::IsDarkTheme()) { | ||
| 3958 | new_pal.setColor(QPalette::Link, QColor(0, 190, 255, 255)); | ||
| 3959 | } else { | ||
| 3960 | new_pal.setColor(QPalette::Link, QColor(0, 140, 200, 255)); | ||
| 3961 | } | ||
| 3962 | if (qApp->palette().color(QPalette::Link) != new_pal.color(QPalette::Link)) { | ||
| 3963 | qApp->setPalette(new_pal); | ||
| 3964 | } | ||
| 3965 | } | ||
| 3966 | |||
| 3938 | void GMainWindow::UpdateUITheme() { | 3967 | void GMainWindow::UpdateUITheme() { |
| 3939 | const QString default_theme = QStringLiteral("default"); | 3968 | const QString default_theme = |
| 3969 | QString::fromUtf8(UISettings::themes[static_cast<size_t>(Config::default_theme)].second); | ||
| 3940 | QString current_theme = UISettings::values.theme; | 3970 | QString current_theme = UISettings::values.theme; |
| 3941 | QStringList theme_paths(default_theme_paths); | 3971 | QStringList theme_paths(default_theme_paths); |
| 3942 | 3972 | ||
| @@ -3944,6 +3974,23 @@ void GMainWindow::UpdateUITheme() { | |||
| 3944 | current_theme = default_theme; | 3974 | current_theme = default_theme; |
| 3945 | } | 3975 | } |
| 3946 | 3976 | ||
| 3977 | #ifdef _WIN32 | ||
| 3978 | QIcon::setThemeName(current_theme); | ||
| 3979 | AdjustLinkColor(); | ||
| 3980 | #else | ||
| 3981 | if (current_theme == QStringLiteral("default") || current_theme == QStringLiteral("colorful")) { | ||
| 3982 | QIcon::setThemeName(current_theme == QStringLiteral("colorful") ? current_theme | ||
| 3983 | : startup_icon_theme); | ||
| 3984 | QIcon::setThemeSearchPaths(theme_paths); | ||
| 3985 | if (CheckDarkMode()) { | ||
| 3986 | current_theme = QStringLiteral("default_dark"); | ||
| 3987 | } | ||
| 3988 | } else { | ||
| 3989 | QIcon::setThemeName(current_theme); | ||
| 3990 | QIcon::setThemeSearchPaths(QStringList(QStringLiteral(":/icons"))); | ||
| 3991 | AdjustLinkColor(); | ||
| 3992 | } | ||
| 3993 | #endif | ||
| 3947 | if (current_theme != default_theme) { | 3994 | if (current_theme != default_theme) { |
| 3948 | QString theme_uri{QStringLiteral(":%1/style.qss").arg(current_theme)}; | 3995 | QString theme_uri{QStringLiteral(":%1/style.qss").arg(current_theme)}; |
| 3949 | QFile f(theme_uri); | 3996 | QFile f(theme_uri); |
| @@ -3966,25 +4013,9 @@ void GMainWindow::UpdateUITheme() { | |||
| 3966 | qApp->setStyleSheet({}); | 4013 | qApp->setStyleSheet({}); |
| 3967 | setStyleSheet({}); | 4014 | setStyleSheet({}); |
| 3968 | } | 4015 | } |
| 3969 | |||
| 3970 | QPalette new_pal(qApp->palette()); | ||
| 3971 | if (UISettings::IsDarkTheme()) { | ||
| 3972 | new_pal.setColor(QPalette::Link, QColor(0, 190, 255, 255)); | ||
| 3973 | } else { | ||
| 3974 | new_pal.setColor(QPalette::Link, QColor(0, 140, 200, 255)); | ||
| 3975 | } | ||
| 3976 | qApp->setPalette(new_pal); | ||
| 3977 | |||
| 3978 | QIcon::setThemeName(current_theme); | ||
| 3979 | QIcon::setThemeSearchPaths(theme_paths); | ||
| 3980 | } | 4016 | } |
| 3981 | 4017 | ||
| 3982 | void GMainWindow::LoadTranslation() { | 4018 | void GMainWindow::LoadTranslation() { |
| 3983 | // If the selected language is English, no need to install any translation | ||
| 3984 | if (UISettings::values.language == QStringLiteral("en")) { | ||
| 3985 | return; | ||
| 3986 | } | ||
| 3987 | |||
| 3988 | bool loaded; | 4019 | bool loaded; |
| 3989 | 4020 | ||
| 3990 | if (UISettings::values.language.isEmpty()) { | 4021 | if (UISettings::values.language.isEmpty()) { |
| @@ -4027,6 +4058,26 @@ void GMainWindow::SetDiscordEnabled([[maybe_unused]] bool state) { | |||
| 4027 | discord_rpc->Update(); | 4058 | discord_rpc->Update(); |
| 4028 | } | 4059 | } |
| 4029 | 4060 | ||
| 4061 | void GMainWindow::changeEvent(QEvent* event) { | ||
| 4062 | #ifdef __linux__ | ||
| 4063 | // PaletteChange event appears to only reach so far into the GUI, explicitly asking to | ||
| 4064 | // UpdateUITheme is a decent work around | ||
| 4065 | if (event->type() == QEvent::PaletteChange) { | ||
| 4066 | const QPalette test_palette(qApp->palette()); | ||
| 4067 | const QString current_theme = UISettings::values.theme; | ||
| 4068 | // Keeping eye on QPalette::Window to avoid looping. QPalette::Text might be useful too | ||
| 4069 | static QColor last_window_color; | ||
| 4070 | const QColor window_color = test_palette.color(QPalette::Active, QPalette::Window); | ||
| 4071 | if (last_window_color != window_color && (current_theme == QStringLiteral("default") || | ||
| 4072 | current_theme == QStringLiteral("colorful"))) { | ||
| 4073 | UpdateUITheme(); | ||
| 4074 | } | ||
| 4075 | last_window_color = window_color; | ||
| 4076 | } | ||
| 4077 | #endif // __linux__ | ||
| 4078 | QWidget::changeEvent(event); | ||
| 4079 | } | ||
| 4080 | |||
| 4030 | #ifdef main | 4081 | #ifdef main |
| 4031 | #undef main | 4082 | #undef main |
| 4032 | #endif | 4083 | #endif |
| @@ -4072,6 +4123,15 @@ int main(int argc, char* argv[]) { | |||
| 4072 | QCoreApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity); | 4123 | QCoreApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity); |
| 4073 | QApplication app(argc, argv); | 4124 | QApplication app(argc, argv); |
| 4074 | 4125 | ||
| 4126 | // Workaround for QTBUG-85409, for Suzhou numerals the number 1 is actually \u3021 | ||
| 4127 | // so we can see if we get \u3008 instead | ||
| 4128 | // TL;DR all other number formats are consecutive in unicode code points | ||
| 4129 | // This bug is fixed in Qt6, specifically 6.0.0-alpha1 | ||
| 4130 | const QLocale locale = QLocale::system(); | ||
| 4131 | if (QStringLiteral("\u3008") == locale.toString(1)) { | ||
| 4132 | QLocale::setDefault(QLocale::system().name()); | ||
| 4133 | } | ||
| 4134 | |||
| 4075 | // Qt changes the locale and causes issues in float conversion using std::to_string() when | 4135 | // Qt changes the locale and causes issues in float conversion using std::to_string() when |
| 4076 | // generating shaders | 4136 | // generating shaders |
| 4077 | setlocale(LC_ALL, "C"); | 4137 | setlocale(LC_ALL, "C"); |
diff --git a/src/yuzu/main.h b/src/yuzu/main.h index e13b38b24..1ae2b93d9 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h | |||
| @@ -251,6 +251,7 @@ private: | |||
| 251 | bool ConfirmForceLockedExit(); | 251 | bool ConfirmForceLockedExit(); |
| 252 | void RequestGameExit(); | 252 | void RequestGameExit(); |
| 253 | void RequestGameResume(); | 253 | void RequestGameResume(); |
| 254 | void changeEvent(QEvent* event) override; | ||
| 254 | void closeEvent(QCloseEvent* event) override; | 255 | void closeEvent(QCloseEvent* event) override; |
| 255 | 256 | ||
| 256 | #ifdef __linux__ | 257 | #ifdef __linux__ |
| @@ -347,6 +348,7 @@ private: | |||
| 347 | void OpenURL(const QUrl& url); | 348 | void OpenURL(const QUrl& url); |
| 348 | void LoadTranslation(); | 349 | void LoadTranslation(); |
| 349 | void OpenPerGameConfiguration(u64 title_id, const std::string& file_name); | 350 | void OpenPerGameConfiguration(u64 title_id, const std::string& file_name); |
| 351 | bool CheckDarkMode(); | ||
| 350 | 352 | ||
| 351 | QString GetTasStateDescription() const; | 353 | QString GetTasStateDescription() const; |
| 352 | 354 | ||
| @@ -392,6 +394,9 @@ private: | |||
| 392 | QTimer mouse_hide_timer; | 394 | QTimer mouse_hide_timer; |
| 393 | QTimer mouse_center_timer; | 395 | QTimer mouse_center_timer; |
| 394 | 396 | ||
| 397 | QString startup_icon_theme; | ||
| 398 | bool os_dark_mode = false; | ||
| 399 | |||
| 395 | // FS | 400 | // FS |
| 396 | std::shared_ptr<FileSys::VfsFilesystem> vfs; | 401 | std::shared_ptr<FileSys::VfsFilesystem> vfs; |
| 397 | std::unique_ptr<FileSys::ManualContentProvider> provider; | 402 | std::unique_ptr<FileSys::ManualContentProvider> provider; |
diff --git a/src/yuzu/multiplayer/direct_connect.ui b/src/yuzu/multiplayer/direct_connect.ui index 681b6bf69..57d6ec25a 100644 --- a/src/yuzu/multiplayer/direct_connect.ui +++ b/src/yuzu/multiplayer/direct_connect.ui | |||
| @@ -83,7 +83,7 @@ | |||
| 83 | <number>5</number> | 83 | <number>5</number> |
| 84 | </property> | 84 | </property> |
| 85 | <property name="placeholderText"> | 85 | <property name="placeholderText"> |
| 86 | <string>24872</string> | 86 | <string notr="true" extracomment="placeholder string that tells user default port">24872</string> |
| 87 | </property> | 87 | </property> |
| 88 | </widget> | 88 | </widget> |
| 89 | </item> | 89 | </item> |