diff options
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/file_sys/romfs.cpp | 44 | ||||
-rw-r--r-- | src/core/file_sys/romfs.h | 9 | ||||
-rw-r--r-- | src/core/hid/emulated_controller.cpp | 14 | ||||
-rw-r--r-- | src/core/hid/hid_types.h | 15 | ||||
-rw-r--r-- | src/core/hle/service/am/am.cpp | 92 | ||||
-rw-r--r-- | src/core/hle/service/am/am.h | 3 | ||||
-rw-r--r-- | src/core/hle/service/am/applets/applet_web_browser.cpp | 3 | ||||
-rw-r--r-- | src/core/hle/service/caps/caps_manager.cpp | 16 | ||||
-rw-r--r-- | src/core/hle/service/caps/caps_manager.h | 9 | ||||
-rw-r--r-- | src/core/hle/service/caps/caps_ss.cpp | 10 | ||||
-rw-r--r-- | src/core/hle/service/caps/caps_su.cpp | 42 | ||||
-rw-r--r-- | src/core/hle/service/caps/caps_su.h | 9 | ||||
-rw-r--r-- | src/core/hle/service/hid/controllers/npad.cpp | 6 |
13 files changed, 199 insertions, 73 deletions
diff --git a/src/core/file_sys/romfs.cpp b/src/core/file_sys/romfs.cpp index 1c580de57..1eb1f439a 100644 --- a/src/core/file_sys/romfs.cpp +++ b/src/core/file_sys/romfs.cpp @@ -35,13 +35,14 @@ struct RomFSHeader { static_assert(sizeof(RomFSHeader) == 0x50, "RomFSHeader has incorrect size."); struct DirectoryEntry { + u32_le parent; u32_le sibling; u32_le child_dir; u32_le child_file; u32_le hash; u32_le name_length; }; -static_assert(sizeof(DirectoryEntry) == 0x14, "DirectoryEntry has incorrect size."); +static_assert(sizeof(DirectoryEntry) == 0x18, "DirectoryEntry has incorrect size."); struct FileEntry { u32_le parent; @@ -64,25 +65,22 @@ std::pair<Entry, std::string> GetEntry(const VirtualFile& file, std::size_t offs return {entry, string}; } -void ProcessFile(VirtualFile file, std::size_t file_offset, std::size_t data_offset, - u32 this_file_offset, std::shared_ptr<VectorVfsDirectory> parent) { - while (true) { +void ProcessFile(const VirtualFile& file, std::size_t file_offset, std::size_t data_offset, + u32 this_file_offset, std::shared_ptr<VectorVfsDirectory>& parent) { + while (this_file_offset != ROMFS_ENTRY_EMPTY) { auto entry = GetEntry<FileEntry>(file, file_offset + this_file_offset); parent->AddFile(std::make_shared<OffsetVfsFile>( file, entry.first.size, entry.first.offset + data_offset, entry.second)); - if (entry.first.sibling == ROMFS_ENTRY_EMPTY) - break; - this_file_offset = entry.first.sibling; } } -void ProcessDirectory(VirtualFile file, std::size_t dir_offset, std::size_t file_offset, +void ProcessDirectory(const VirtualFile& file, std::size_t dir_offset, std::size_t file_offset, std::size_t data_offset, u32 this_dir_offset, - std::shared_ptr<VectorVfsDirectory> parent) { - while (true) { + std::shared_ptr<VectorVfsDirectory>& parent) { + while (this_dir_offset != ROMFS_ENTRY_EMPTY) { auto entry = GetEntry<DirectoryEntry>(file, dir_offset + this_dir_offset); auto current = std::make_shared<VectorVfsDirectory>( std::vector<VirtualFile>{}, std::vector<VirtualDir>{}, entry.second); @@ -97,14 +95,12 @@ void ProcessDirectory(VirtualFile file, std::size_t dir_offset, std::size_t file } parent->AddDirectory(current); - if (entry.first.sibling == ROMFS_ENTRY_EMPTY) - break; this_dir_offset = entry.first.sibling; } } } // Anonymous namespace -VirtualDir ExtractRomFS(VirtualFile file, RomFSExtractionType type) { +VirtualDir ExtractRomFS(VirtualFile file) { RomFSHeader header{}; if (file->ReadObject(&header) != sizeof(RomFSHeader)) return nullptr; @@ -113,27 +109,17 @@ VirtualDir ExtractRomFS(VirtualFile file, RomFSExtractionType type) { return nullptr; const u64 file_offset = header.file_meta.offset; - const u64 dir_offset = header.directory_meta.offset + 4; - - auto root = - std::make_shared<VectorVfsDirectory>(std::vector<VirtualFile>{}, std::vector<VirtualDir>{}, - file->GetName(), file->GetContainingDirectory()); - - ProcessDirectory(file, dir_offset, file_offset, header.data_offset, 0, root); + const u64 dir_offset = header.directory_meta.offset; - VirtualDir out = std::move(root); + auto root_container = std::make_shared<VectorVfsDirectory>(); - if (type == RomFSExtractionType::SingleDiscard) - return out->GetSubdirectories().front(); + ProcessDirectory(file, dir_offset, file_offset, header.data_offset, 0, root_container); - while (out->GetSubdirectories().size() == 1 && out->GetFiles().empty()) { - if (Common::ToLower(out->GetSubdirectories().front()->GetName()) == "data" && - type == RomFSExtractionType::Truncated) - break; - out = out->GetSubdirectories().front(); + if (auto root = root_container->GetSubdirectory(""); root) { + return std::make_shared<CachedVfsDirectory>(std::move(root)); } - return std::make_shared<CachedVfsDirectory>(std::move(out)); + return nullptr; } VirtualFile CreateRomFS(VirtualDir dir, VirtualDir ext) { diff --git a/src/core/file_sys/romfs.h b/src/core/file_sys/romfs.h index 5d7f0c2a8..b75ff1aad 100644 --- a/src/core/file_sys/romfs.h +++ b/src/core/file_sys/romfs.h @@ -7,16 +7,9 @@ namespace FileSys { -enum class RomFSExtractionType { - Full, // Includes data directory - Truncated, // Traverses into data directory - SingleDiscard, // Traverses into the first subdirectory of root -}; - // Converts a RomFS binary blob to VFS Filesystem // Returns nullptr on failure -VirtualDir ExtractRomFS(VirtualFile file, - RomFSExtractionType type = RomFSExtractionType::Truncated); +VirtualDir ExtractRomFS(VirtualFile file); // Converts a VFS filesystem into a RomFS binary // Returns nullptr on failure diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 2af3f06fc..8e2894449 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -1091,30 +1091,30 @@ void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callbac bool is_charging = false; bool is_powered = false; - NpadBatteryLevel battery_level = 0; + NpadBatteryLevel battery_level = NpadBatteryLevel::Empty; switch (controller.battery_values[index]) { case Common::Input::BatteryLevel::Charging: is_charging = true; is_powered = true; - battery_level = 6; + battery_level = NpadBatteryLevel::Full; break; case Common::Input::BatteryLevel::Medium: - battery_level = 6; + battery_level = NpadBatteryLevel::High; break; case Common::Input::BatteryLevel::Low: - battery_level = 4; + battery_level = NpadBatteryLevel::Low; break; case Common::Input::BatteryLevel::Critical: - battery_level = 2; + battery_level = NpadBatteryLevel::Critical; break; case Common::Input::BatteryLevel::Empty: - battery_level = 0; + battery_level = NpadBatteryLevel::Empty; break; case Common::Input::BatteryLevel::None: case Common::Input::BatteryLevel::Full: default: is_powered = true; - battery_level = 8; + battery_level = NpadBatteryLevel::Full; break; } diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h index 00beb40dd..7ba75a50c 100644 --- a/src/core/hid/hid_types.h +++ b/src/core/hid/hid_types.h @@ -302,6 +302,15 @@ enum class TouchScreenModeForNx : u8 { Heat2, }; +// This is nn::hid::system::NpadBatteryLevel +enum class NpadBatteryLevel : u32 { + Empty, + Critical, + Low, + High, + Full, +}; + // This is nn::hid::NpadStyleTag struct NpadStyleTag { union { @@ -385,16 +394,12 @@ struct NpadGcTriggerState { }; static_assert(sizeof(NpadGcTriggerState) == 0x10, "NpadGcTriggerState is an invalid size"); -// This is nn::hid::system::NpadBatteryLevel -using NpadBatteryLevel = u32; -static_assert(sizeof(NpadBatteryLevel) == 0x4, "NpadBatteryLevel is an invalid size"); - // This is nn::hid::system::NpadPowerInfo struct NpadPowerInfo { bool is_powered{}; bool is_charging{}; INSERT_PADDING_BYTES(0x6); - NpadBatteryLevel battery_level{8}; + NpadBatteryLevel battery_level{NpadBatteryLevel::Full}; }; static_assert(sizeof(NpadPowerInfo) == 0xC, "NpadPowerInfo is an invalid size"); diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index ff067c8d9..cc643ea09 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -23,6 +23,7 @@ #include "core/hle/service/am/applets/applet_cabinet.h" #include "core/hle/service/am/applets/applet_mii_edit_types.h" #include "core/hle/service/am/applets/applet_profile_select.h" +#include "core/hle/service/am/applets/applet_software_keyboard_types.h" #include "core/hle/service/am/applets/applet_web_browser.h" #include "core/hle/service/am/applets/applets.h" #include "core/hle/service/am/idle.h" @@ -31,6 +32,7 @@ #include "core/hle/service/apm/apm_controller.h" #include "core/hle/service/apm/apm_interface.h" #include "core/hle/service/bcat/backend/backend.h" +#include "core/hle/service/caps/caps_su.h" #include "core/hle/service/caps/caps_types.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/ipc_helpers.h" @@ -702,9 +704,17 @@ void ISelfController::SetAlbumImageTakenNotificationEnabled(HLERequestContext& c void ISelfController::SaveCurrentScreenshot(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto album_report_option = rp.PopEnum<Capture::AlbumReportOption>(); + const auto report_option = rp.PopEnum<Capture::AlbumReportOption>(); - LOG_WARNING(Service_AM, "(STUBBED) called. album_report_option={}", album_report_option); + LOG_INFO(Service_AM, "called, report_option={}", report_option); + + const auto screenshot_service = + system.ServiceManager().GetService<Service::Capture::IScreenShotApplicationService>( + "caps:su"); + + if (screenshot_service) { + screenshot_service->CaptureAndSaveScreenshot(report_option); + } IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -1562,7 +1572,7 @@ ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_) {16, nullptr, "GetMainAppletStorageId"}, {17, nullptr, "GetCallerAppletIdentityInfoStack"}, {18, nullptr, "GetNextReturnDestinationAppletIdentityInfo"}, - {19, nullptr, "GetDesirableKeyboardLayout"}, + {19, &ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout, "GetDesirableKeyboardLayout"}, {20, nullptr, "PopExtraStorage"}, {25, nullptr, "GetPopExtraStorageEvent"}, {30, nullptr, "UnpopInData"}, @@ -1581,7 +1591,7 @@ ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_) {120, nullptr, "GetLaunchStorageInfoForDebug"}, {130, nullptr, "GetGpuErrorDetectedSystemEvent"}, {140, nullptr, "SetApplicationMemoryReservation"}, - {150, nullptr, "ShouldSetGpuTimeSliceManually"}, + {150, &ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually, "ShouldSetGpuTimeSliceManually"}, }; // clang-format on RegisterHandlers(functions); @@ -1596,6 +1606,9 @@ ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_) case Applets::AppletId::PhotoViewer: PushInShowAlbum(); break; + case Applets::AppletId::SoftwareKeyboard: + PushInShowSoftwareKeyboard(); + break; default: break; } @@ -1672,6 +1685,14 @@ void ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo(HLERequestContext& rb.PushRaw(applet_info); } +void ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push<u32>(0); +} + void ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers(HLERequestContext& ctx) { const Service::Account::ProfileManager manager{}; bool is_empty{true}; @@ -1691,6 +1712,14 @@ void ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers(HLERequestContext& rb.Push(user_count); } +void ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + rb.Push<u8>(0); +} + void ILibraryAppletSelfAccessor::PushInShowAlbum() { const Applets::CommonArguments arguments{ .arguments_version = Applets::CommonArgumentVersion::Version3, @@ -1759,6 +1788,61 @@ void ILibraryAppletSelfAccessor::PushInShowMiiEditData() { queue_data.emplace_back(std::move(argument_data)); } +void ILibraryAppletSelfAccessor::PushInShowSoftwareKeyboard() { + const Applets::CommonArguments arguments{ + .arguments_version = Applets::CommonArgumentVersion::Version3, + .size = Applets::CommonArgumentSize::Version3, + .library_version = static_cast<u32>(Applets::SwkbdAppletVersion::Version524301), + .theme_color = Applets::ThemeColor::BasicBlack, + .play_startup_sound = true, + .system_tick = system.CoreTiming().GetClockTicks(), + }; + + std::vector<char16_t> initial_string(0); + + const Applets::SwkbdConfigCommon swkbd_config{ + .type = Applets::SwkbdType::Qwerty, + .ok_text{}, + .left_optional_symbol_key{}, + .right_optional_symbol_key{}, + .use_prediction = false, + .key_disable_flags{}, + .initial_cursor_position = Applets::SwkbdInitialCursorPosition::Start, + .header_text{}, + .sub_text{}, + .guide_text{}, + .max_text_length = 500, + .min_text_length = 0, + .password_mode = Applets::SwkbdPasswordMode::Disabled, + .text_draw_type = Applets::SwkbdTextDrawType::Box, + .enable_return_button = true, + .use_utf8 = false, + .use_blur_background = true, + .initial_string_offset{}, + .initial_string_length = static_cast<u32>(initial_string.size()), + .user_dictionary_offset{}, + .user_dictionary_entries{}, + .use_text_check = false, + }; + + Applets::SwkbdConfigNew swkbd_config_new{}; + + std::vector<u8> argument_data(sizeof(arguments)); + std::vector<u8> swkbd_data(sizeof(swkbd_config) + sizeof(swkbd_config_new)); + std::vector<u8> work_buffer(swkbd_config.initial_string_length * sizeof(char16_t)); + + std::memcpy(argument_data.data(), &arguments, sizeof(arguments)); + std::memcpy(swkbd_data.data(), &swkbd_config, sizeof(swkbd_config)); + std::memcpy(swkbd_data.data() + sizeof(swkbd_config), &swkbd_config_new, + sizeof(Applets::SwkbdConfigNew)); + std::memcpy(work_buffer.data(), initial_string.data(), + swkbd_config.initial_string_length * sizeof(char16_t)); + + queue_data.emplace_back(std::move(argument_data)); + queue_data.emplace_back(std::move(swkbd_data)); + queue_data.emplace_back(std::move(work_buffer)); +} + IAppletCommonFunctions::IAppletCommonFunctions(Core::System& system_) : ServiceFramework{system_, "IAppletCommonFunctions"} { // clang-format off diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 64b3f3fe2..8f8cb8a9e 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -347,11 +347,14 @@ private: void GetLibraryAppletInfo(HLERequestContext& ctx); void ExitProcessAndReturn(HLERequestContext& ctx); void GetCallerAppletIdentityInfo(HLERequestContext& ctx); + void GetDesirableKeyboardLayout(HLERequestContext& ctx); void GetMainAppletAvailableUsers(HLERequestContext& ctx); + void ShouldSetGpuTimeSliceManually(HLERequestContext& ctx); void PushInShowAlbum(); void PushInShowCabinetData(); void PushInShowMiiEditData(); + void PushInShowSoftwareKeyboard(); std::deque<std::vector<u8>> queue_data; }; diff --git a/src/core/hle/service/am/applets/applet_web_browser.cpp b/src/core/hle/service/am/applets/applet_web_browser.cpp index 1c9a1dc29..b0ea2b381 100644 --- a/src/core/hle/service/am/applets/applet_web_browser.cpp +++ b/src/core/hle/service/am/applets/applet_web_browser.cpp @@ -330,8 +330,7 @@ void WebBrowser::ExtractOfflineRomFS() { LOG_DEBUG(Service_AM, "Extracting RomFS to {}", Common::FS::PathToUTF8String(offline_cache_dir)); - const auto extracted_romfs_dir = - FileSys::ExtractRomFS(offline_romfs, FileSys::RomFSExtractionType::SingleDiscard); + const auto extracted_romfs_dir = FileSys::ExtractRomFS(offline_romfs); const auto temp_dir = system.GetFilesystem()->CreateDirectory( Common::FS::PathToUTF8String(offline_cache_dir), FileSys::Mode::ReadWrite); diff --git a/src/core/hle/service/caps/caps_manager.cpp b/src/core/hle/service/caps/caps_manager.cpp index 7d733eb54..96b225d5f 100644 --- a/src/core/hle/service/caps/caps_manager.cpp +++ b/src/core/hle/service/caps/caps_manager.cpp @@ -228,12 +228,14 @@ Result AlbumManager::LoadAlbumScreenShotThumbnail( Result AlbumManager::SaveScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute, - std::span<const u8> image_data, u64 aruid) { - return SaveScreenShot(out_entry, attribute, {}, image_data, aruid); + AlbumReportOption report_option, std::span<const u8> image_data, + u64 aruid) { + return SaveScreenShot(out_entry, attribute, report_option, {}, image_data, aruid); } Result AlbumManager::SaveScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute, + AlbumReportOption report_option, const ApplicationData& app_data, std::span<const u8> image_data, u64 aruid) { const u64 title_id = system.GetApplicationProcessProgramID(); @@ -407,10 +409,14 @@ Result AlbumManager::LoadImage(std::span<u8> out_image, const std::filesystem::p return ResultSuccess; } -static void PNGToMemory(void* context, void* png, int len) { +void AlbumManager::FlipVerticallyOnWrite(bool flip) { + stbi_flip_vertically_on_write(flip); +} + +static void PNGToMemory(void* context, void* data, int len) { std::vector<u8>* png_image = static_cast<std::vector<u8>*>(context); - png_image->reserve(len); - std::memcpy(png_image->data(), png, len); + unsigned char* png = static_cast<unsigned char*>(data); + png_image->insert(png_image->end(), png, png + len); } Result AlbumManager::SaveImage(ApplicationAlbumEntry& out_entry, std::span<const u8> image, diff --git a/src/core/hle/service/caps/caps_manager.h b/src/core/hle/service/caps/caps_manager.h index 44d85117f..e20c70c7b 100644 --- a/src/core/hle/service/caps/caps_manager.h +++ b/src/core/hle/service/caps/caps_manager.h @@ -59,14 +59,17 @@ public: const ScreenShotDecodeOption& decoder_options) const; Result SaveScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute, - std::span<const u8> image_data, u64 aruid); - Result SaveScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute, - const ApplicationData& app_data, std::span<const u8> image_data, + AlbumReportOption report_option, std::span<const u8> image_data, u64 aruid); + Result SaveScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute, + AlbumReportOption report_option, const ApplicationData& app_data, + std::span<const u8> image_data, u64 aruid); Result SaveEditedScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute, const AlbumFileId& file_id, std::span<const u8> image_data); + void FlipVerticallyOnWrite(bool flip); + private: static constexpr std::size_t NandAlbumFileLimit = 1000; static constexpr std::size_t SdAlbumFileLimit = 10000; diff --git a/src/core/hle/service/caps/caps_ss.cpp b/src/core/hle/service/caps/caps_ss.cpp index 1ba2b7972..eab023568 100644 --- a/src/core/hle/service/caps/caps_ss.cpp +++ b/src/core/hle/service/caps/caps_ss.cpp @@ -34,7 +34,7 @@ void IScreenShotService::SaveScreenShotEx0(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { ScreenShotAttribute attribute{}; - u32 report_option{}; + AlbumReportOption report_option{}; INSERT_PADDING_BYTES(0x4); u64 applet_resource_user_id{}; }; @@ -49,13 +49,16 @@ void IScreenShotService::SaveScreenShotEx0(HLERequestContext& ctx) { parameters.applet_resource_user_id); ApplicationAlbumEntry entry{}; - const auto result = manager->SaveScreenShot(entry, parameters.attribute, image_data_buffer, - parameters.applet_resource_user_id); + manager->FlipVerticallyOnWrite(false); + const auto result = + manager->SaveScreenShot(entry, parameters.attribute, parameters.report_option, + image_data_buffer, parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 10}; rb.Push(result); rb.PushRaw(entry); } + void IScreenShotService::SaveEditedScreenShotEx1(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { @@ -83,6 +86,7 @@ void IScreenShotService::SaveEditedScreenShotEx1(HLERequestContext& ctx) { image_data_buffer.size(), thumbnail_image_data_buffer.size()); ApplicationAlbumEntry entry{}; + manager->FlipVerticallyOnWrite(false); const auto result = manager->SaveEditedScreenShot(entry, parameters.attribute, parameters.file_id, image_data_buffer); diff --git a/src/core/hle/service/caps/caps_su.cpp b/src/core/hle/service/caps/caps_su.cpp index e85625ee4..296b07b00 100644 --- a/src/core/hle/service/caps/caps_su.cpp +++ b/src/core/hle/service/caps/caps_su.cpp @@ -2,10 +2,12 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "common/logging/log.h" +#include "core/core.h" #include "core/hle/service/caps/caps_manager.h" #include "core/hle/service/caps/caps_su.h" #include "core/hle/service/caps/caps_types.h" #include "core/hle/service/ipc_helpers.h" +#include "video_core/renderer_base.h" namespace Service::Capture { @@ -58,8 +60,10 @@ void IScreenShotApplicationService::SaveScreenShotEx0(HLERequestContext& ctx) { parameters.applet_resource_user_id); ApplicationAlbumEntry entry{}; - const auto result = manager->SaveScreenShot(entry, parameters.attribute, image_data_buffer, - parameters.applet_resource_user_id); + manager->FlipVerticallyOnWrite(false); + const auto result = + manager->SaveScreenShot(entry, parameters.attribute, parameters.report_option, + image_data_buffer, parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 10}; rb.Push(result); @@ -88,13 +92,43 @@ void IScreenShotApplicationService::SaveScreenShotEx1(HLERequestContext& ctx) { ApplicationAlbumEntry entry{}; ApplicationData app_data{}; std::memcpy(&app_data, app_data_buffer.data(), sizeof(ApplicationData)); + manager->FlipVerticallyOnWrite(false); const auto result = - manager->SaveScreenShot(entry, parameters.attribute, app_data, image_data_buffer, - parameters.applet_resource_user_id); + manager->SaveScreenShot(entry, parameters.attribute, parameters.report_option, app_data, + image_data_buffer, parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 10}; rb.Push(result); rb.PushRaw(entry); } +void IScreenShotApplicationService::CaptureAndSaveScreenshot(AlbumReportOption report_option) { + auto& renderer = system.Renderer(); + Layout::FramebufferLayout layout = + Layout::DefaultFrameLayout(screenshot_width, screenshot_height); + + const Capture::ScreenShotAttribute attribute{ + .unknown_0{}, + .orientation = Capture::AlbumImageOrientation::None, + .unknown_1{}, + .unknown_2{}, + }; + + renderer.RequestScreenshot( + image_data.data(), + [attribute, report_option, this](bool invert_y) { + // Convert from BGRA to RGBA + for (std::size_t i = 0; i < image_data.size(); i += bytes_per_pixel) { + const u8 temp = image_data[i]; + image_data[i] = image_data[i + 2]; + image_data[i + 2] = temp; + } + + Capture::ApplicationAlbumEntry entry{}; + manager->FlipVerticallyOnWrite(invert_y); + manager->SaveScreenShot(entry, attribute, report_option, image_data, {}); + }, + layout); +} + } // namespace Service::Capture diff --git a/src/core/hle/service/caps/caps_su.h b/src/core/hle/service/caps/caps_su.h index 89e71f506..21912e95f 100644 --- a/src/core/hle/service/caps/caps_su.h +++ b/src/core/hle/service/caps/caps_su.h @@ -10,6 +10,7 @@ class System; } namespace Service::Capture { +enum class AlbumReportOption : s32; class AlbumManager; class IScreenShotApplicationService final : public ServiceFramework<IScreenShotApplicationService> { @@ -18,11 +19,19 @@ public: std::shared_ptr<AlbumManager> album_manager); ~IScreenShotApplicationService() override; + void CaptureAndSaveScreenshot(AlbumReportOption report_option); + private: + static constexpr std::size_t screenshot_width = 1280; + static constexpr std::size_t screenshot_height = 720; + static constexpr std::size_t bytes_per_pixel = 4; + void SetShimLibraryVersion(HLERequestContext& ctx); void SaveScreenShotEx0(HLERequestContext& ctx); void SaveScreenShotEx1(HLERequestContext& ctx); + std::array<u8, screenshot_width * screenshot_height * bytes_per_pixel> image_data; + std::shared_ptr<AlbumManager> manager; }; diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index bc822f19e..21695bda2 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -1108,9 +1108,9 @@ Result Controller_NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) { shared_memory->sixaxis_dual_right_properties.raw = 0; shared_memory->sixaxis_left_properties.raw = 0; shared_memory->sixaxis_right_properties.raw = 0; - shared_memory->battery_level_dual = 0; - shared_memory->battery_level_left = 0; - shared_memory->battery_level_right = 0; + shared_memory->battery_level_dual = Core::HID::NpadBatteryLevel::Empty; + shared_memory->battery_level_left = Core::HID::NpadBatteryLevel::Empty; + shared_memory->battery_level_right = Core::HID::NpadBatteryLevel::Empty; shared_memory->fullkey_color = { .attribute = ColorAttribute::NoController, .fullkey = {}, |