Compare commits

..

58 Commits

Author SHA1 Message Date
Lioncash c09ff382a4 yuzu/configuration: Make all widgets and dialogs aware of language changes
To prepare for translation support, this makes all of the widgets
cognizant of the language change event that occurs whenever
installTranslator() is called and automatically retranslates their text
where necessary.

This is important as calling the backing UI's retranslateUi() is often
not enough, particularly in cases where we add our own strings that
aren't controlled by it. In that case we need to manually refresh the
strings ourselves.
2019-06-05 21:57:21 -04:00
bunnei 8d7a012297 Merge pull request #2521 from lioncash/naming
yuzu/configuration: Make function naming consistent
2019-06-05 18:03:05 -04:00
bunnei 0bcc305797 Merge pull request #2512 from ReinUsesLisp/comp-indexing
gl_shader_decompiler: Pessimize uniform buffer access on AMD's prorpietary driver
2019-06-05 18:02:30 -04:00
Zach Hilman 799302bc9d Merge pull request #2526 from lioncash/global
core/telemetry_session: Remove usages of the global system accessor
2019-06-05 15:57:48 -04:00
Zach Hilman 81e09bb121 Merge pull request #2545 from lioncash/timing
core/core_timing_util: Use std::chrono types for specifying time units
2019-06-05 15:52:37 -04:00
Zach Hilman 6aff1005ef Merge pull request #2541 from lioncash/input
input_common/sdl/sdl_impl: Minor cleanup
2019-06-05 15:51:03 -04:00
Lioncash e1d755bdda yuzu/configuration: Make function naming consistent 2019-06-05 15:40:33 -04:00
Zach Hilman 2beaaa35c5 Merge pull request #2510 from SciresM/desired_language
Implement/Fix IApplicationFunctions::GetDesiredLanguage
2019-06-05 15:39:33 -04:00
Zach Hilman 1eb979221f Merge pull request #2527 from lioncash/index
yuzu/{profile_select, software_keyboard}: Tidy up interface
2019-06-05 15:30:51 -04:00
Zach Hilman dd4fe0dab1 Merge pull request #2534 from ReinUsesLisp/shader-cleanup
gl_shader_cache: Minor style changes
2019-06-05 15:28:34 -04:00
Zach Hilman 433ca686a8 Merge pull request #2531 from ReinUsesLisp/qt-warnings
qt: Silence name collision warnings
2019-06-05 15:27:12 -04:00
Zach Hilman 6ce5f3e1bf Merge pull request #2515 from lioncash/narrowing
yuzu/configuration/configure_graphics: Eliminate type narrowing in a connect call
2019-06-05 15:26:13 -04:00
Zach Hilman dfc40a3f9e Merge pull request #2532 from ShalokShalom/patch-2
Remove outdated info about compability
2019-06-05 15:04:57 -04:00
Zach Hilman 4f7a1f6c8c Merge pull request #2536 from lioncash/cache
game_list_worker: Use QFile over our own IOFile instance or std streams for the game list cache
2019-06-05 15:03:59 -04:00
Rodrigo Locatti 2ba4aa8a3b Merge pull request #2529 from lioncash/boot
yuzu/bootmanager: Minor interface tidying
2019-06-04 21:35:56 -03:00
Lioncash 5ccf2a7b82 input_common/sdl/sdl_impl: Correct logging string in SDLState constructor
If this path was ever taken, a runtime exception would occur due to the
lack of a formatting specifier to insert the error code into the format
string.
2019-06-03 16:56:47 -04:00
Lioncash cfac942e63 input_common/sdl/sdl_impl: Move documentation comments to header where applicable
Places the documentation comments with the rest of SDLState's member
function documentation.
2019-06-03 16:56:47 -04:00
Lioncash b9b23c98ff input_common/sdl/sdl_impl: Amend names for axes for SDLAnalogPoller
Adds another underscore to clearly indicate the axis names.
2019-06-03 16:56:47 -04:00
Lioncash 50048d9f5a input_common/sdl/sdl_impl: Mark variables const where applicable
Make it explicit that these aren't modified elsewhere (either through
functions by reference, or by other operations).
2019-06-03 16:56:47 -04:00
Lioncash ca7ca2919c input_common/sdl/sdl_impl: Mark SDLEventToButtonParamPackage() as static
Its prototype declared at the top of the translation unit contains the
static qualifier, so the function itself should also contain it to make
it a proper internally linked function.
2019-06-03 16:56:47 -04:00
Lioncash b73ea457cc input_common/sdl/sdl_impl: Convert reinterpret_cast into a static_cast
It's valid to static_cast a void pointer back into its proper type.
2019-06-03 16:56:46 -04:00
Lioncash 2c679cda51 input_common/sdl/sdl_impl: Use insert_or_assign() where applicable
Same behavior, but without a potential need to unnecessarily default
construct a value.
2019-06-03 16:56:46 -04:00
Lioncash b46e615551 input_common/sdl/sdl_impl: Simplify SDL_Joystick deleter handling
The deleter can just be set in the constructor and maintained throughout
the lifetime of the object.

If a contained pointer is null, then the deleter won't execute, so this
is safe to do. We don't need to swap it out with a version of a deleter
that does nothing.
2019-06-03 16:56:46 -04:00
Lioncash 7ea07c6063 input_common/sdl/sdl_impl: Resolve two sign conversion warnings
Silences the final two warnings in SDL code.
2019-06-03 16:56:46 -04:00
Lioncash cf0d01a5d7 input_common/sdl: Remove unused header includes and forward declarations
Gets rid of a few unnecessary inclusion dependencies. It also uncovered
a few indirect inclusion dependencies being relied upon.
2019-06-03 16:56:42 -04:00
Lioncash 00f0827a26 input_common/sdl/sdl_impl: Use nested namespace specifiers where applicable 2019-06-03 15:49:04 -04:00
Lioncash 77ce85f51d yuzu/bootmanager: Log out screenshot destination path
We can make this message more meaningful by indicating the location the
screenshot has been saved to. We can also log out whenever a screenshot
could not be saved (e.g. due to filesystem permissions or some other
reason).
2019-06-03 15:34:32 -04:00
Lioncash e32bf646cf yuzu/bootmanager: Treat the resolution factor as a u32
Treating it as a u16 can result in a sign-conversion warning when
performing arithmetic with it, as u16 promotes to an int when aritmetic
is performed on it, not unsigned int.

This also makes the interface more uniform, as the layout interface now
operates on u32 across the board.
2019-06-03 15:34:31 -04:00
Lioncash 536c9cf006 yuzu/bootmanager: Default EmuThread's destructor in the cpp file
This class contains non-trivial members, so we should default the
destructor's definition within the cpp file.
2019-06-03 15:34:31 -04:00
Lioncash 0a650ec99e yuzu/bootmanager: unsigned -> u32
Same thing (for platforms we support), less reading.
2019-06-03 15:34:31 -04:00
Lioncash 2575403acf yuzu/bootmanager: Change false literal to 0 for setSwapInterval()
This function is defined as taking an int, not a bool.
2019-06-03 15:31:52 -04:00
Lioncash cfb59aad3f yuzu/bootmanager: Remove pointer downcast in GRenderWindow's constructor
We can just pass a pointer to GMainWindow directly and make it a
requirement of the interface. This makes the interface a little safer,
since this would technically otherwise allow any random QWidget to be
the parent of a render window, downcasting it to GMainWindow (which is
undefined behavior).
2019-06-03 15:31:52 -04:00
Lioncash 49e3a6e924 yuzu/bootmanager: Remove unnecessary pointer casts
We can just invoke these functions by qualifying the object name before
the function.
2019-06-03 15:31:51 -04:00
Lioncash d0d97de1e4 game_list_worker: Use QFile over our own IOFile instance or std streams
Stays consistent in our code with using Qt's provided mechanisms, and
also properly handles Unicode paths (which file streams on Windows don't
do very well).
2019-05-30 22:15:13 -04:00
Lioncash de2533d389 game_list_worker: Remove template specializations
This is equivalent to specifying two separate functions, so we can just
do that.
2019-05-30 18:56:06 -04:00
ReinUsesLisp e72b9044a0 gl_shader_cache: Store a system class and drop global accessors 2019-05-30 14:01:40 -03:00
ReinUsesLisp ad321564ed gl_shader_cache: Add commentaries explaining the intention in shaders creation 2019-05-30 13:58:38 -03:00
ReinUsesLisp 838b6d2ff8 gl_shader_cache: Flip if condition in GetStageProgram to reduce indentation 2019-05-30 13:56:03 -03:00
ShalokShalom e9772a2539 Remove outdated info about compability 2019-05-30 05:38:27 +02:00
ReinUsesLisp 3f11d1c821 qt: Silence name collision warnings 2019-05-29 21:35:05 -03:00
Lioncash cfc9d92b38 yuzu/software_keyboard: Remove unnecessary GetStatus() member function
Like with the profile selection dialog, we can just use the result of
QDialog's exec() function to determine whether or not a dialog was
accepted.
2019-05-29 00:56:45 -04:00
Lioncash 802dd3cc95 profile_select: Remove unnecessary GetStatus() member function
This behavior is already provided by the built-in exec() function. We
just need to check the return value of it.
2019-05-29 00:56:41 -04:00
Lioncash 139301c5a1 profile_select: Return int instead of u32 for GetIndex()
Qt uses a signed value to represent indices. We should follow this
convention where applicable to avoid unnecessary sign-conversion
warnings, as well as making it easier to interoperate with other aspects
of Qt.

While we're at it, we can also make a sign-conversion explicit.
2019-05-29 00:29:09 -04:00
Lioncash 8bbe930fac core/core: Remove unnecessary includes
The contents of these includes aren't used anywhere in this translation
unit.
2019-05-29 00:00:27 -04:00
Lioncash c6f05b586f yuzu_cmd/yuzu: Correct formatting specifier
Amends the formatting specifier to obey libfmt. Prevents the application
from terminating due to a formatting issue in the error case.
2019-05-28 22:28:46 -04:00
Lioncash 84a8fb9264 core/loader: Remove LoadKernelSystemMode
This is a hold-over from Citra and doesn't apply to yuzu.
2019-05-28 22:28:44 -04:00
Lioncash b1a4ab2ccc core/telemetry_session: Remove unnecessary web service nulling out in destructor
This will automatically occur when the backend instance goes out of
scope at the end of the destructor's execution.
2019-05-28 22:28:18 -04:00
Lioncash 215fd82738 core/telemetry_session: Remove usages of the global system accessor
Makes the dependency explicit in the TelemetrySession's interface
instead of making it a hidden dependency.

This also revealed a hidden issue with the way the telemetry session was
being initialized. It was attempting to retrieve the app loader and log
out title-specific information. However, this isn't always guaranteed to
be possible.

During the initialization phase, everything is being constructed. It
doesn't mean an actual title has been selected. This is what the Load()
function is for. This potentially results in dead code paths involving
the app loader. Instead, we explicitly add this information when we know
the app loader instance is available.
2019-05-28 22:28:15 -04:00
Lioncash 05af9d915c core/telemetry_session: Explicitly delete copy and move constructors
NonCopyable is misleading here. It also makes the class non-moveable as
well, so we can be explicit about this.
2019-05-28 21:07:38 -04:00
Lioncash 2fb3b9b951 core/telemetry_session: Remove unused include 2019-05-28 20:56:22 -04:00
Lioncash d623e38d18 yuzu/configuration/configure_graphics: Eliminate type narrowing in a connect call
A checkbox is able to be tri-state, giving it three possible activity
types, so in the connect call here, it would actually be truncating an
int into a bool.

Instead, we can just listen on the toggled() signal, which passes along
a bool, not an int.
2019-05-24 22:24:40 -04:00
ReinUsesLisp d8827b07b5 gl_shader_decompiler: Use an if based cbuf indexing for broken drivers
The following code is broken on AMD's proprietary GLSL compiler:
```glsl
uint idx = ...;
vec4 values = ...;
float some_value = values[idx & 3];
```

It index the wrong components, to fix this the following pessimized code
is emitted when that bug is present:
```glsl
uint idx = ...;
vec4 values = ...;
float some_value;
if ((idx & 3) == 0) some_value = values.x;
if ((idx & 3) == 1) some_value = values.y;
if ((idx & 3) == 2) some_value = values.z;
if ((idx & 3) == 3) some_value = values.w;
```
2019-05-24 02:47:56 -03:00
ReinUsesLisp 46177901b8 gl_device: Add test to detect broken component indexing
Component indexing on AMD's proprietary driver is broken. This commit adds
a test to detect when we are on a driver that can't successfully manage
component indexing.

It dispatches a dummy draw with just one vertex shader that writes to an
indexed SSBO from the GPU with data sent through uniforms, it then reads
that data from the CPU and compares the expected output.
2019-05-24 02:47:56 -03:00
Michael Scire 016f2eab73 Fix bitmask logic inversion 2019-05-23 02:37:13 -07:00
Michael Scire 2ed896075e fix introduced clang-format errors 2019-05-23 01:39:22 -07:00
Michael Scire d81b58f320 Address review comments 2019-05-23 01:28:27 -07:00
Michael Scire 7fba9c7224 clang-format fixes 2019-05-23 01:14:11 -07:00
Michael Scire 7dbf4c1ae5 Implement IApplicationFunctions::GetDesiredLanguage 2019-05-23 00:55:56 -07:00
72 changed files with 2043 additions and 984 deletions
+1 -1
View File
@@ -7,7 +7,7 @@ yuzu is an experimental open-source emulator for the Nintendo Switch from the cr
It is written in C++ with portability in mind, with builds actively maintained for Windows, Linux and macOS. The emulator is currently only useful for homebrew development and research purposes.
yuzu only emulates a subset of Switch hardware and therefore is generally only useful for running/debugging homebrew applications. At this time, yuzu cannot play any commercial games without major problems. yuzu can boot some games, to varying degrees of success.
yuzu only emulates a subset of Switch hardware and therefore is generally only useful for running/debugging homebrew applications. yuzu can boot some games, to varying degrees of success.
yuzu is licensed under the GPLv2 (or any later version). Refer to the license.txt file included.
+3
View File
@@ -328,6 +328,9 @@ add_library(core STATIC
hle/service/nim/nim.h
hle/service/npns/npns.cpp
hle/service/npns/npns.h
hle/service/ns/errors.h
hle/service/ns/language.cpp
hle/service/ns/language.h
hle/service/ns/ns.cpp
hle/service/ns/ns.h
hle/service/ns/pl_u.cpp
+1 -18
View File
@@ -18,11 +18,6 @@
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/vfs_concat.h"
#include "core/file_sys/vfs_real.h"
#include "core/frontend/applets/error.h"
#include "core/frontend/applets/general_frontend.h"
#include "core/frontend/applets/profile_select.h"
#include "core/frontend/applets/software_keyboard.h"
#include "core/frontend/applets/web_browser.h"
#include "core/gdbstub/gdbstub.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/kernel.h"
@@ -37,9 +32,6 @@
#include "core/settings.h"
#include "core/telemetry_session.h"
#include "file_sys/cheat_engine.h"
#include "frontend/applets/profile_select.h"
#include "frontend/applets/software_keyboard.h"
#include "frontend/applets/web_browser.h"
#include "video_core/debug_utils/debug_utils.h"
#include "video_core/renderer_base.h"
#include "video_core/video_core.h"
@@ -144,20 +136,10 @@ struct System::Impl {
ResultStatus Load(System& system, Frontend::EmuWindow& emu_window,
const std::string& filepath) {
app_loader = Loader::GetLoader(GetGameFileFromPath(virtual_filesystem, filepath));
if (!app_loader) {
LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);
return ResultStatus::ErrorGetLoader;
}
std::pair<std::optional<u32>, Loader::ResultStatus> system_mode =
app_loader->LoadKernelSystemMode();
if (system_mode.second != Loader::ResultStatus::Success) {
LOG_CRITICAL(Core, "Failed to determine system mode (Error {})!",
static_cast<int>(system_mode.second));
return ResultStatus::ErrorSystemMode;
}
ResultStatus init_result{Init(system, emu_window)};
if (init_result != ResultStatus::Success) {
@@ -167,6 +149,7 @@ struct System::Impl {
return init_result;
}
telemetry_session->AddInitialInfo(*app_loader);
auto main_process = Kernel::Process::Create(system, "main");
const auto [load_result, load_parameters] = app_loader->Load(*main_process);
if (load_result != Loader::ResultStatus::Success) {
-1
View File
@@ -98,7 +98,6 @@ public:
Success, ///< Succeeded
ErrorNotInitialized, ///< Error trying to use core prior to initialization
ErrorGetLoader, ///< Error finding the correct application loader
ErrorSystemMode, ///< Error determining the system mode
ErrorSystemFiles, ///< Error in finding system files
ErrorSharedFont, ///< Error in finding shared font
ErrorVideoCore, ///< Error in the video core
+4
View File
@@ -87,6 +87,10 @@ u64 NACP::GetDefaultJournalSaveSize() const {
return raw.user_account_save_data_journal_size;
}
u32 NACP::GetSupportedLanguages() const {
return raw.supported_languages;
}
std::vector<u8> NACP::GetRawBytes() const {
std::vector<u8> out(sizeof(RawNACP));
std::memcpy(out.data(), &raw, sizeof(RawNACP));
+1
View File
@@ -109,6 +109,7 @@ public:
std::string GetVersionString() const;
u64 GetDefaultNormalSaveSize() const;
u64 GetDefaultJournalSaveSize() const;
u32 GetSupportedLanguages() const;
std::vector<u8> GetRawBytes() const;
private:
+7 -6
View File
@@ -20,7 +20,7 @@ static Common::Rectangle<T> MaxRectangle(Common::Rectangle<T> window_area,
static_cast<T>(std::round(scale * screen_aspect_ratio))};
}
FramebufferLayout DefaultFrameLayout(unsigned width, unsigned height) {
FramebufferLayout DefaultFrameLayout(u32 width, u32 height) {
ASSERT(width > 0);
ASSERT(height > 0);
// The drawing code needs at least somewhat valid values for both screens
@@ -29,22 +29,23 @@ FramebufferLayout DefaultFrameLayout(unsigned width, unsigned height) {
const float emulation_aspect_ratio{static_cast<float>(ScreenUndocked::Height) /
ScreenUndocked::Width};
Common::Rectangle<unsigned> screen_window_area{0, 0, width, height};
Common::Rectangle<unsigned> screen = MaxRectangle(screen_window_area, emulation_aspect_ratio);
const auto window_aspect_ratio = static_cast<float>(height) / width;
float window_aspect_ratio = static_cast<float>(height) / width;
const Common::Rectangle<u32> screen_window_area{0, 0, width, height};
Common::Rectangle<u32> screen = MaxRectangle(screen_window_area, emulation_aspect_ratio);
if (window_aspect_ratio < emulation_aspect_ratio) {
screen = screen.TranslateX((screen_window_area.GetWidth() - screen.GetWidth()) / 2);
} else {
screen = screen.TranslateY((height - screen.GetHeight()) / 2);
}
res.screen = screen;
return res;
}
FramebufferLayout FrameLayoutFromResolutionScale(u16 res_scale) {
int width, height;
FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale) {
u32 width, height;
if (Settings::values.use_docked_mode) {
width = ScreenDocked::WidthDocked * res_scale;
+14 -7
View File
@@ -8,15 +8,22 @@
namespace Layout {
enum ScreenUndocked : unsigned { Width = 1280, Height = 720 };
enum ScreenDocked : unsigned { WidthDocked = 1920, HeightDocked = 1080 };
enum ScreenUndocked : u32 {
Width = 1280,
Height = 720,
};
enum ScreenDocked : u32 {
WidthDocked = 1920,
HeightDocked = 1080,
};
/// Describes the layout of the window framebuffer
struct FramebufferLayout {
unsigned width{ScreenUndocked::Width};
unsigned height{ScreenUndocked::Height};
u32 width{ScreenUndocked::Width};
u32 height{ScreenUndocked::Height};
Common::Rectangle<unsigned> screen;
Common::Rectangle<u32> screen;
/**
* Returns the ration of pixel size of the screen, compared to the native size of the undocked
@@ -33,12 +40,12 @@ struct FramebufferLayout {
* @param height Window framebuffer height in pixels
* @return Newly created FramebufferLayout object with default screen regions initialized
*/
FramebufferLayout DefaultFrameLayout(unsigned width, unsigned height);
FramebufferLayout DefaultFrameLayout(u32 width, u32 height);
/**
* Convenience method to get frame layout by resolution scale
* @param res_scale resolution scale factor
*/
FramebufferLayout FrameLayoutFromResolutionScale(u16 res_scale);
FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale);
} // namespace Layout
+38 -2
View File
@@ -8,6 +8,8 @@
#include <cstring>
#include "audio_core/audio_renderer.h"
#include "core/core.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/savedata_factory.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/kernel.h"
@@ -29,9 +31,11 @@
#include "core/hle/service/am/tcap.h"
#include "core/hle/service/apm/apm.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/ns/ns.h"
#include "core/hle/service/nvflinger/nvflinger.h"
#include "core/hle/service/pm/pm.h"
#include "core/hle/service/set/set.h"
#include "core/hle/service/sm/sm.h"
#include "core/hle/service/vi/vi.h"
#include "core/settings.h"
@@ -1100,10 +1104,42 @@ void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) {
// TODO(bunnei): This should be configurable
LOG_DEBUG(Service_AM, "called");
// Get supported languages from NACP, if possible
// Default to 0 (all languages supported)
u32 supported_languages = 0;
FileSys::PatchManager pm{Core::System::GetInstance().CurrentProcess()->GetTitleID()};
const auto res = pm.GetControlMetadata();
if (res.first != nullptr) {
supported_languages = res.first->GetSupportedLanguages();
}
// Call IApplicationManagerInterface implementation.
auto& service_manager = Core::System::GetInstance().ServiceManager();
auto ns_am2 = service_manager.GetService<Service::NS::NS>("ns:am2");
auto app_man = ns_am2->GetApplicationManagerInterface();
// Get desired application language
const auto res_lang = app_man->GetApplicationDesiredLanguage(supported_languages);
if (res_lang.Failed()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res_lang.Code());
return;
}
// Convert to settings language code.
const auto res_code = app_man->ConvertApplicationLanguageToLanguageCode(*res_lang);
if (res_code.Failed()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res_code.Code());
return;
}
LOG_DEBUG(Service_AM, "got desired_language={:016X}", *res_code);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push(
static_cast<u64>(Service::Set::GetLanguageCodeFromIndex(Settings::values.language_index)));
rb.Push(*res_code);
}
void IApplicationFunctions::InitializeGamePlayRecording(Kernel::HLERequestContext& ctx) {
@@ -121,6 +121,21 @@ void Applet::Initialize() {
initialized = true;
}
AppletFrontendSet::AppletFrontendSet() = default;
AppletFrontendSet::AppletFrontendSet(ErrorApplet error, PhotoViewer photo_viewer,
ProfileSelect profile_select,
SoftwareKeyboard software_keyboard, WebBrowser web_browser)
: error{std::move(error)}, photo_viewer{std::move(photo_viewer)}, profile_select{std::move(
profile_select)},
software_keyboard{std::move(software_keyboard)}, web_browser{std::move(web_browser)} {}
AppletFrontendSet::~AppletFrontendSet() = default;
AppletFrontendSet::AppletFrontendSet(AppletFrontendSet&&) noexcept = default;
AppletFrontendSet& AppletFrontendSet::operator=(AppletFrontendSet&&) noexcept = default;
AppletManager::AppletManager() = default;
AppletManager::~AppletManager() = default;
+22 -5
View File
@@ -137,11 +137,28 @@ protected:
};
struct AppletFrontendSet {
std::unique_ptr<Core::Frontend::ErrorApplet> error;
std::unique_ptr<Core::Frontend::PhotoViewerApplet> photo_viewer;
std::unique_ptr<Core::Frontend::ProfileSelectApplet> profile_select;
std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> software_keyboard;
std::unique_ptr<Core::Frontend::WebBrowserApplet> web_browser;
using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>;
using PhotoViewer = std::unique_ptr<Core::Frontend::PhotoViewerApplet>;
using ProfileSelect = std::unique_ptr<Core::Frontend::ProfileSelectApplet>;
using SoftwareKeyboard = std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet>;
using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>;
AppletFrontendSet();
AppletFrontendSet(ErrorApplet error, PhotoViewer photo_viewer, ProfileSelect profile_select,
SoftwareKeyboard software_keyboard, WebBrowser web_browser);
~AppletFrontendSet();
AppletFrontendSet(const AppletFrontendSet&) = delete;
AppletFrontendSet& operator=(const AppletFrontendSet&) = delete;
AppletFrontendSet(AppletFrontendSet&&) noexcept;
AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept;
ErrorApplet error;
PhotoViewer photo_viewer;
ProfileSelect profile_select;
SoftwareKeyboard software_keyboard;
WebBrowser web_browser;
};
class AppletManager {
+12
View File
@@ -0,0 +1,12 @@
// Copyright 2019 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "core/hle/result.h"
namespace Service::NS {
constexpr ResultCode ERR_APPLICATION_LANGUAGE_NOT_FOUND{ErrorModule::NS, 300};
}
+392
View File
@@ -0,0 +1,392 @@
// Copyright 2019 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "core/hle/service/ns/language.h"
#include "core/hle/service/set/set.h"
namespace Service::NS {
constexpr ApplicationLanguagePriorityList priority_list_american_english = {{
ApplicationLanguage::AmericanEnglish,
ApplicationLanguage::BritishEnglish,
ApplicationLanguage::LatinAmericanSpanish,
ApplicationLanguage::CanadianFrench,
ApplicationLanguage::French,
ApplicationLanguage::German,
ApplicationLanguage::Spanish,
ApplicationLanguage::Italian,
ApplicationLanguage::Dutch,
ApplicationLanguage::Portuguese,
ApplicationLanguage::Russian,
ApplicationLanguage::Japanese,
ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::Korean,
}};
constexpr ApplicationLanguagePriorityList priority_list_british_english = {{
ApplicationLanguage::BritishEnglish,
ApplicationLanguage::AmericanEnglish,
ApplicationLanguage::French,
ApplicationLanguage::German,
ApplicationLanguage::Spanish,
ApplicationLanguage::Italian,
ApplicationLanguage::Dutch,
ApplicationLanguage::Portuguese,
ApplicationLanguage::Russian,
ApplicationLanguage::LatinAmericanSpanish,
ApplicationLanguage::CanadianFrench,
ApplicationLanguage::Japanese,
ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::Korean,
}};
constexpr ApplicationLanguagePriorityList priority_list_japanese = {{
ApplicationLanguage::Japanese,
ApplicationLanguage::AmericanEnglish,
ApplicationLanguage::BritishEnglish,
ApplicationLanguage::LatinAmericanSpanish,
ApplicationLanguage::CanadianFrench,
ApplicationLanguage::French,
ApplicationLanguage::German,
ApplicationLanguage::Spanish,
ApplicationLanguage::Italian,
ApplicationLanguage::Dutch,
ApplicationLanguage::Portuguese,
ApplicationLanguage::Russian,
ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::Korean,
}};
constexpr ApplicationLanguagePriorityList priority_list_french = {{
ApplicationLanguage::French,
ApplicationLanguage::CanadianFrench,
ApplicationLanguage::BritishEnglish,
ApplicationLanguage::AmericanEnglish,
ApplicationLanguage::German,
ApplicationLanguage::Spanish,
ApplicationLanguage::Italian,
ApplicationLanguage::Dutch,
ApplicationLanguage::Portuguese,
ApplicationLanguage::Russian,
ApplicationLanguage::LatinAmericanSpanish,
ApplicationLanguage::Japanese,
ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::Korean,
}};
constexpr ApplicationLanguagePriorityList priority_list_german = {{
ApplicationLanguage::German,
ApplicationLanguage::BritishEnglish,
ApplicationLanguage::AmericanEnglish,
ApplicationLanguage::French,
ApplicationLanguage::Spanish,
ApplicationLanguage::Italian,
ApplicationLanguage::Dutch,
ApplicationLanguage::Portuguese,
ApplicationLanguage::Russian,
ApplicationLanguage::LatinAmericanSpanish,
ApplicationLanguage::CanadianFrench,
ApplicationLanguage::Japanese,
ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::Korean,
}};
constexpr ApplicationLanguagePriorityList priority_list_latin_american_spanish = {{
ApplicationLanguage::LatinAmericanSpanish,
ApplicationLanguage::Spanish,
ApplicationLanguage::AmericanEnglish,
ApplicationLanguage::BritishEnglish,
ApplicationLanguage::Portuguese,
ApplicationLanguage::CanadianFrench,
ApplicationLanguage::French,
ApplicationLanguage::Italian,
ApplicationLanguage::German,
ApplicationLanguage::Dutch,
ApplicationLanguage::Russian,
ApplicationLanguage::Japanese,
ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::Korean,
}};
constexpr ApplicationLanguagePriorityList priority_list_spanish = {{
ApplicationLanguage::Spanish,
ApplicationLanguage::LatinAmericanSpanish,
ApplicationLanguage::BritishEnglish,
ApplicationLanguage::AmericanEnglish,
ApplicationLanguage::French,
ApplicationLanguage::German,
ApplicationLanguage::Italian,
ApplicationLanguage::Dutch,
ApplicationLanguage::Portuguese,
ApplicationLanguage::Russian,
ApplicationLanguage::CanadianFrench,
ApplicationLanguage::Japanese,
ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::Korean,
}};
constexpr ApplicationLanguagePriorityList priority_list_italian = {{
ApplicationLanguage::Italian,
ApplicationLanguage::BritishEnglish,
ApplicationLanguage::AmericanEnglish,
ApplicationLanguage::French,
ApplicationLanguage::German,
ApplicationLanguage::Spanish,
ApplicationLanguage::Dutch,
ApplicationLanguage::Portuguese,
ApplicationLanguage::Russian,
ApplicationLanguage::LatinAmericanSpanish,
ApplicationLanguage::CanadianFrench,
ApplicationLanguage::Japanese,
ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::Korean,
}};
constexpr ApplicationLanguagePriorityList priority_list_dutch = {{
ApplicationLanguage::Dutch,
ApplicationLanguage::BritishEnglish,
ApplicationLanguage::AmericanEnglish,
ApplicationLanguage::French,
ApplicationLanguage::German,
ApplicationLanguage::Spanish,
ApplicationLanguage::Italian,
ApplicationLanguage::Portuguese,
ApplicationLanguage::Russian,
ApplicationLanguage::LatinAmericanSpanish,
ApplicationLanguage::CanadianFrench,
ApplicationLanguage::Japanese,
ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::Korean,
}};
constexpr ApplicationLanguagePriorityList priority_list_canadian_french = {{
ApplicationLanguage::CanadianFrench,
ApplicationLanguage::French,
ApplicationLanguage::AmericanEnglish,
ApplicationLanguage::BritishEnglish,
ApplicationLanguage::LatinAmericanSpanish,
ApplicationLanguage::Spanish,
ApplicationLanguage::German,
ApplicationLanguage::Italian,
ApplicationLanguage::Dutch,
ApplicationLanguage::Portuguese,
ApplicationLanguage::Russian,
ApplicationLanguage::Japanese,
ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::Korean,
}};
constexpr ApplicationLanguagePriorityList priority_list_portuguese = {{
ApplicationLanguage::Portuguese,
ApplicationLanguage::BritishEnglish,
ApplicationLanguage::AmericanEnglish,
ApplicationLanguage::French,
ApplicationLanguage::German,
ApplicationLanguage::Spanish,
ApplicationLanguage::Italian,
ApplicationLanguage::Dutch,
ApplicationLanguage::Russian,
ApplicationLanguage::LatinAmericanSpanish,
ApplicationLanguage::CanadianFrench,
ApplicationLanguage::Japanese,
ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::Korean,
}};
constexpr ApplicationLanguagePriorityList priority_list_russian = {{
ApplicationLanguage::Russian,
ApplicationLanguage::BritishEnglish,
ApplicationLanguage::AmericanEnglish,
ApplicationLanguage::French,
ApplicationLanguage::German,
ApplicationLanguage::Spanish,
ApplicationLanguage::Italian,
ApplicationLanguage::Dutch,
ApplicationLanguage::Portuguese,
ApplicationLanguage::LatinAmericanSpanish,
ApplicationLanguage::CanadianFrench,
ApplicationLanguage::Japanese,
ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::Korean,
}};
constexpr ApplicationLanguagePriorityList priority_list_korean = {{
ApplicationLanguage::Korean,
ApplicationLanguage::AmericanEnglish,
ApplicationLanguage::BritishEnglish,
ApplicationLanguage::LatinAmericanSpanish,
ApplicationLanguage::CanadianFrench,
ApplicationLanguage::French,
ApplicationLanguage::German,
ApplicationLanguage::Spanish,
ApplicationLanguage::Italian,
ApplicationLanguage::Dutch,
ApplicationLanguage::Portuguese,
ApplicationLanguage::Russian,
ApplicationLanguage::Japanese,
ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese,
}};
constexpr ApplicationLanguagePriorityList priority_list_traditional_chinese = {{
ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::AmericanEnglish,
ApplicationLanguage::BritishEnglish,
ApplicationLanguage::Japanese,
ApplicationLanguage::LatinAmericanSpanish,
ApplicationLanguage::CanadianFrench,
ApplicationLanguage::French,
ApplicationLanguage::German,
ApplicationLanguage::Spanish,
ApplicationLanguage::Italian,
ApplicationLanguage::Dutch,
ApplicationLanguage::Portuguese,
ApplicationLanguage::Russian,
ApplicationLanguage::Korean,
}};
constexpr ApplicationLanguagePriorityList priority_list_simplified_chinese = {{
ApplicationLanguage::SimplifiedChinese,
ApplicationLanguage::TraditionalChinese,
ApplicationLanguage::AmericanEnglish,
ApplicationLanguage::BritishEnglish,
ApplicationLanguage::Japanese,
ApplicationLanguage::LatinAmericanSpanish,
ApplicationLanguage::CanadianFrench,
ApplicationLanguage::French,
ApplicationLanguage::German,
ApplicationLanguage::Spanish,
ApplicationLanguage::Italian,
ApplicationLanguage::Dutch,
ApplicationLanguage::Portuguese,
ApplicationLanguage::Russian,
ApplicationLanguage::Korean,
}};
const ApplicationLanguagePriorityList* GetApplicationLanguagePriorityList(
const ApplicationLanguage lang) {
switch (lang) {
case ApplicationLanguage::AmericanEnglish:
return &priority_list_american_english;
case ApplicationLanguage::BritishEnglish:
return &priority_list_british_english;
case ApplicationLanguage::Japanese:
return &priority_list_japanese;
case ApplicationLanguage::French:
return &priority_list_french;
case ApplicationLanguage::German:
return &priority_list_german;
case ApplicationLanguage::LatinAmericanSpanish:
return &priority_list_latin_american_spanish;
case ApplicationLanguage::Spanish:
return &priority_list_spanish;
case ApplicationLanguage::Italian:
return &priority_list_italian;
case ApplicationLanguage::Dutch:
return &priority_list_dutch;
case ApplicationLanguage::CanadianFrench:
return &priority_list_canadian_french;
case ApplicationLanguage::Portuguese:
return &priority_list_portuguese;
case ApplicationLanguage::Russian:
return &priority_list_russian;
case ApplicationLanguage::Korean:
return &priority_list_korean;
case ApplicationLanguage::TraditionalChinese:
return &priority_list_traditional_chinese;
case ApplicationLanguage::SimplifiedChinese:
return &priority_list_simplified_chinese;
default:
return nullptr;
}
}
std::optional<ApplicationLanguage> ConvertToApplicationLanguage(
const Set::LanguageCode language_code) {
switch (language_code) {
case Set::LanguageCode::EN_US:
return ApplicationLanguage::AmericanEnglish;
case Set::LanguageCode::EN_GB:
return ApplicationLanguage::BritishEnglish;
case Set::LanguageCode::JA:
return ApplicationLanguage::Japanese;
case Set::LanguageCode::FR:
return ApplicationLanguage::French;
case Set::LanguageCode::DE:
return ApplicationLanguage::German;
case Set::LanguageCode::ES_419:
return ApplicationLanguage::LatinAmericanSpanish;
case Set::LanguageCode::ES:
return ApplicationLanguage::Spanish;
case Set::LanguageCode::IT:
return ApplicationLanguage::Italian;
case Set::LanguageCode::NL:
return ApplicationLanguage::Dutch;
case Set::LanguageCode::FR_CA:
return ApplicationLanguage::CanadianFrench;
case Set::LanguageCode::PT:
return ApplicationLanguage::Portuguese;
case Set::LanguageCode::RU:
return ApplicationLanguage::Russian;
case Set::LanguageCode::KO:
return ApplicationLanguage::Korean;
case Set::LanguageCode::ZH_HANT:
return ApplicationLanguage::TraditionalChinese;
case Set::LanguageCode::ZH_HANS:
return ApplicationLanguage::SimplifiedChinese;
default:
return std::nullopt;
}
}
std::optional<Set::LanguageCode> ConvertToLanguageCode(const ApplicationLanguage lang) {
switch (lang) {
case ApplicationLanguage::AmericanEnglish:
return Set::LanguageCode::EN_US;
case ApplicationLanguage::BritishEnglish:
return Set::LanguageCode::EN_GB;
case ApplicationLanguage::Japanese:
return Set::LanguageCode::JA;
case ApplicationLanguage::French:
return Set::LanguageCode::FR;
case ApplicationLanguage::German:
return Set::LanguageCode::DE;
case ApplicationLanguage::LatinAmericanSpanish:
return Set::LanguageCode::ES_419;
case ApplicationLanguage::Spanish:
return Set::LanguageCode::ES;
case ApplicationLanguage::Italian:
return Set::LanguageCode::IT;
case ApplicationLanguage::Dutch:
return Set::LanguageCode::NL;
case ApplicationLanguage::CanadianFrench:
return Set::LanguageCode::FR_CA;
case ApplicationLanguage::Portuguese:
return Set::LanguageCode::PT;
case ApplicationLanguage::Russian:
return Set::LanguageCode::RU;
case ApplicationLanguage::Korean:
return Set::LanguageCode::KO;
case ApplicationLanguage::TraditionalChinese:
return Set::LanguageCode::ZH_HANT;
case ApplicationLanguage::SimplifiedChinese:
return Set::LanguageCode::ZH_HANS;
default:
return std::nullopt;
}
}
} // namespace Service::NS
+45
View File
@@ -0,0 +1,45 @@
// Copyright 2019 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <optional>
#include <string>
#include "common/common_types.h"
namespace Service::Set {
enum class LanguageCode : u64;
}
namespace Service::NS {
/// This is nn::ns::detail::ApplicationLanguage
enum class ApplicationLanguage : u8 {
AmericanEnglish = 0,
BritishEnglish,
Japanese,
French,
German,
LatinAmericanSpanish,
Spanish,
Italian,
Dutch,
CanadianFrench,
Portuguese,
Russian,
Korean,
TraditionalChinese,
SimplifiedChinese,
Count
};
using ApplicationLanguagePriorityList =
const std::array<ApplicationLanguage, static_cast<std::size_t>(ApplicationLanguage::Count)>;
constexpr u32 GetSupportedLanguageFlag(const ApplicationLanguage lang) {
return 1U << static_cast<u32>(lang);
}
const ApplicationLanguagePriorityList* GetApplicationLanguagePriorityList(ApplicationLanguage lang);
std::optional<ApplicationLanguage> ConvertToApplicationLanguage(Set::LanguageCode language_code);
std::optional<Set::LanguageCode> ConvertToLanguageCode(ApplicationLanguage lang);
} // namespace Service::NS
+455 -393
View File
@@ -7,445 +7,507 @@
#include "core/file_sys/patch_manager.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/service/ns/errors.h"
#include "core/hle/service/ns/language.h"
#include "core/hle/service/ns/ns.h"
#include "core/hle/service/ns/pl_u.h"
#include "core/hle/service/set/set.h"
#include "core/settings.h"
namespace Service::NS {
class IAccountProxyInterface final : public ServiceFramework<IAccountProxyInterface> {
public:
explicit IAccountProxyInterface() : ServiceFramework{"IAccountProxyInterface"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "CreateUserAccount"},
};
// clang-format on
IAccountProxyInterface::IAccountProxyInterface() : ServiceFramework{"IAccountProxyInterface"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "CreateUserAccount"},
};
// clang-format on
RegisterHandlers(functions);
}
};
RegisterHandlers(functions);
}
class IApplicationManagerInterface final : public ServiceFramework<IApplicationManagerInterface> {
public:
explicit IApplicationManagerInterface() : ServiceFramework{"IApplicationManagerInterface"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "ListApplicationRecord"},
{1, nullptr, "GenerateApplicationRecordCount"},
{2, nullptr, "GetApplicationRecordUpdateSystemEvent"},
{3, nullptr, "GetApplicationViewDeprecated"},
{4, nullptr, "DeleteApplicationEntity"},
{5, nullptr, "DeleteApplicationCompletely"},
{6, nullptr, "IsAnyApplicationEntityRedundant"},
{7, nullptr, "DeleteRedundantApplicationEntity"},
{8, nullptr, "IsApplicationEntityMovable"},
{9, nullptr, "MoveApplicationEntity"},
{11, nullptr, "CalculateApplicationOccupiedSize"},
{16, nullptr, "PushApplicationRecord"},
{17, nullptr, "ListApplicationRecordContentMeta"},
{19, nullptr, "LaunchApplicationOld"},
{21, nullptr, "GetApplicationContentPath"},
{22, nullptr, "TerminateApplication"},
{23, nullptr, "ResolveApplicationContentPath"},
{26, nullptr, "BeginInstallApplication"},
{27, nullptr, "DeleteApplicationRecord"},
{30, nullptr, "RequestApplicationUpdateInfo"},
{32, nullptr, "CancelApplicationDownload"},
{33, nullptr, "ResumeApplicationDownload"},
{35, nullptr, "UpdateVersionList"},
{36, nullptr, "PushLaunchVersion"},
{37, nullptr, "ListRequiredVersion"},
{38, nullptr, "CheckApplicationLaunchVersion"},
{39, nullptr, "CheckApplicationLaunchRights"},
{40, nullptr, "GetApplicationLogoData"},
{41, nullptr, "CalculateApplicationDownloadRequiredSize"},
{42, nullptr, "CleanupSdCard"},
{43, nullptr, "CheckSdCardMountStatus"},
{44, nullptr, "GetSdCardMountStatusChangedEvent"},
{45, nullptr, "GetGameCardAttachmentEvent"},
{46, nullptr, "GetGameCardAttachmentInfo"},
{47, nullptr, "GetTotalSpaceSize"},
{48, nullptr, "GetFreeSpaceSize"},
{49, nullptr, "GetSdCardRemovedEvent"},
{52, nullptr, "GetGameCardUpdateDetectionEvent"},
{53, nullptr, "DisableApplicationAutoDelete"},
{54, nullptr, "EnableApplicationAutoDelete"},
{55, nullptr, "GetApplicationDesiredLanguage"},
{56, nullptr, "SetApplicationTerminateResult"},
{57, nullptr, "ClearApplicationTerminateResult"},
{58, nullptr, "GetLastSdCardMountUnexpectedResult"},
{59, nullptr, "ConvertApplicationLanguageToLanguageCode"},
{60, nullptr, "ConvertLanguageCodeToApplicationLanguage"},
{61, nullptr, "GetBackgroundDownloadStressTaskInfo"},
{62, nullptr, "GetGameCardStopper"},
{63, nullptr, "IsSystemProgramInstalled"},
{64, nullptr, "StartApplyDeltaTask"},
{65, nullptr, "GetRequestServerStopper"},
{66, nullptr, "GetBackgroundApplyDeltaStressTaskInfo"},
{67, nullptr, "CancelApplicationApplyDelta"},
{68, nullptr, "ResumeApplicationApplyDelta"},
{69, nullptr, "CalculateApplicationApplyDeltaRequiredSize"},
{70, nullptr, "ResumeAll"},
{71, nullptr, "GetStorageSize"},
{80, nullptr, "RequestDownloadApplication"},
{81, nullptr, "RequestDownloadAddOnContent"},
{82, nullptr, "DownloadApplication"},
{83, nullptr, "CheckApplicationResumeRights"},
{84, nullptr, "GetDynamicCommitEvent"},
{85, nullptr, "RequestUpdateApplication2"},
{86, nullptr, "EnableApplicationCrashReport"},
{87, nullptr, "IsApplicationCrashReportEnabled"},
{90, nullptr, "BoostSystemMemoryResourceLimit"},
{91, nullptr, "DeprecatedLaunchApplication"},
{92, nullptr, "GetRunningApplicationProgramId"},
{93, nullptr, "GetMainApplicationProgramIndex"},
{94, nullptr, "LaunchApplication"},
{95, nullptr, "GetApplicationLaunchInfo"},
{96, nullptr, "AcquireApplicationLaunchInfo"},
{97, nullptr, "GetMainApplicationProgramIndex2"},
{98, nullptr, "EnableApplicationAllThreadDumpOnCrash"},
{100, nullptr, "ResetToFactorySettings"},
{101, nullptr, "ResetToFactorySettingsWithoutUserSaveData"},
{102, nullptr, "ResetToFactorySettingsForRefurbishment"},
{200, nullptr, "CalculateUserSaveDataStatistics"},
{201, nullptr, "DeleteUserSaveDataAll"},
{210, nullptr, "DeleteUserSystemSaveData"},
{211, nullptr, "DeleteSaveData"},
{220, nullptr, "UnregisterNetworkServiceAccount"},
{221, nullptr, "UnregisterNetworkServiceAccountWithUserSaveDataDeletion"},
{300, nullptr, "GetApplicationShellEvent"},
{301, nullptr, "PopApplicationShellEventInfo"},
{302, nullptr, "LaunchLibraryApplet"},
{303, nullptr, "TerminateLibraryApplet"},
{304, nullptr, "LaunchSystemApplet"},
{305, nullptr, "TerminateSystemApplet"},
{306, nullptr, "LaunchOverlayApplet"},
{307, nullptr, "TerminateOverlayApplet"},
{400, &IApplicationManagerInterface::GetApplicationControlData, "GetApplicationControlData"},
{401, nullptr, "InvalidateAllApplicationControlCache"},
{402, nullptr, "RequestDownloadApplicationControlData"},
{403, nullptr, "GetMaxApplicationControlCacheCount"},
{404, nullptr, "InvalidateApplicationControlCache"},
{405, nullptr, "ListApplicationControlCacheEntryInfo"},
{406, nullptr, "GetApplicationControlProperty"},
{502, nullptr, "RequestCheckGameCardRegistration"},
{503, nullptr, "RequestGameCardRegistrationGoldPoint"},
{504, nullptr, "RequestRegisterGameCard"},
{505, nullptr, "GetGameCardMountFailureEvent"},
{506, nullptr, "IsGameCardInserted"},
{507, nullptr, "EnsureGameCardAccess"},
{508, nullptr, "GetLastGameCardMountFailureResult"},
{509, nullptr, "ListApplicationIdOnGameCard"},
{600, nullptr, "CountApplicationContentMeta"},
{601, nullptr, "ListApplicationContentMetaStatus"},
{602, nullptr, "ListAvailableAddOnContent"},
{603, nullptr, "GetOwnedApplicationContentMetaStatus"},
{604, nullptr, "RegisterContentsExternalKey"},
{605, nullptr, "ListApplicationContentMetaStatusWithRightsCheck"},
{606, nullptr, "GetContentMetaStorage"},
{607, nullptr, "ListAvailableAddOnContent"},
{700, nullptr, "PushDownloadTaskList"},
{701, nullptr, "ClearTaskStatusList"},
{702, nullptr, "RequestDownloadTaskList"},
{703, nullptr, "RequestEnsureDownloadTask"},
{704, nullptr, "ListDownloadTaskStatus"},
{705, nullptr, "RequestDownloadTaskListData"},
{800, nullptr, "RequestVersionList"},
{801, nullptr, "ListVersionList"},
{802, nullptr, "RequestVersionListData"},
{900, nullptr, "GetApplicationRecord"},
{901, nullptr, "GetApplicationRecordProperty"},
{902, nullptr, "EnableApplicationAutoUpdate"},
{903, nullptr, "DisableApplicationAutoUpdate"},
{904, nullptr, "TouchApplication"},
{905, nullptr, "RequestApplicationUpdate"},
{906, nullptr, "IsApplicationUpdateRequested"},
{907, nullptr, "WithdrawApplicationUpdateRequest"},
{908, nullptr, "ListApplicationRecordInstalledContentMeta"},
{909, nullptr, "WithdrawCleanupAddOnContentsWithNoRightsRecommendation"},
{910, nullptr, "HasApplicationRecord"},
{911, nullptr, "SetPreInstalledApplication"},
{912, nullptr, "ClearPreInstalledApplicationFlag"},
{1000, nullptr, "RequestVerifyApplicationDeprecated"},
{1001, nullptr, "CorruptApplicationForDebug"},
{1002, nullptr, "RequestVerifyAddOnContentsRights"},
{1003, nullptr, "RequestVerifyApplication"},
{1004, nullptr, "CorruptContentForDebug"},
{1200, nullptr, "NeedsUpdateVulnerability"},
{1300, nullptr, "IsAnyApplicationEntityInstalled"},
{1301, nullptr, "DeleteApplicationContentEntities"},
{1302, nullptr, "CleanupUnrecordedApplicationEntity"},
{1303, nullptr, "CleanupAddOnContentsWithNoRights"},
{1304, nullptr, "DeleteApplicationContentEntity"},
{1305, nullptr, "TryDeleteRunningApplicationEntity"},
{1306, nullptr, "TryDeleteRunningApplicationCompletely"},
{1307, nullptr, "TryDeleteRunningApplicationContentEntities"},
{1308, nullptr, "DeleteApplicationCompletelyForDebug"},
{1309, nullptr, "CleanupUnavailableAddOnContents"},
{1400, nullptr, "PrepareShutdown"},
{1500, nullptr, "FormatSdCard"},
{1501, nullptr, "NeedsSystemUpdateToFormatSdCard"},
{1502, nullptr, "GetLastSdCardFormatUnexpectedResult"},
{1504, nullptr, "InsertSdCard"},
{1505, nullptr, "RemoveSdCard"},
{1600, nullptr, "GetSystemSeedForPseudoDeviceId"},
{1601, nullptr, "ResetSystemSeedForPseudoDeviceId"},
{1700, nullptr, "ListApplicationDownloadingContentMeta"},
{1701, nullptr, "GetApplicationView"},
{1702, nullptr, "GetApplicationDownloadTaskStatus"},
{1703, nullptr, "GetApplicationViewDownloadErrorContext"},
{1800, nullptr, "IsNotificationSetupCompleted"},
{1801, nullptr, "GetLastNotificationInfoCount"},
{1802, nullptr, "ListLastNotificationInfo"},
{1803, nullptr, "ListNotificationTask"},
{1900, nullptr, "IsActiveAccount"},
{1901, nullptr, "RequestDownloadApplicationPrepurchasedRights"},
{1902, nullptr, "GetApplicationTicketInfo"},
{2000, nullptr, "GetSystemDeliveryInfo"},
{2001, nullptr, "SelectLatestSystemDeliveryInfo"},
{2002, nullptr, "VerifyDeliveryProtocolVersion"},
{2003, nullptr, "GetApplicationDeliveryInfo"},
{2004, nullptr, "HasAllContentsToDeliver"},
{2005, nullptr, "CompareApplicationDeliveryInfo"},
{2006, nullptr, "CanDeliverApplication"},
{2007, nullptr, "ListContentMetaKeyToDeliverApplication"},
{2008, nullptr, "NeedsSystemUpdateToDeliverApplication"},
{2009, nullptr, "EstimateRequiredSize"},
{2010, nullptr, "RequestReceiveApplication"},
{2011, nullptr, "CommitReceiveApplication"},
{2012, nullptr, "GetReceiveApplicationProgress"},
{2013, nullptr, "RequestSendApplication"},
{2014, nullptr, "GetSendApplicationProgress"},
{2015, nullptr, "CompareSystemDeliveryInfo"},
{2016, nullptr, "ListNotCommittedContentMeta"},
{2017, nullptr, "CreateDownloadTask"},
{2018, nullptr, "GetApplicationDeliveryInfoHash"},
{2050, nullptr, "GetApplicationRightsOnClient"},
{2100, nullptr, "GetApplicationTerminateResult"},
{2101, nullptr, "GetRawApplicationTerminateResult"},
{2150, nullptr, "CreateRightsEnvironment"},
{2151, nullptr, "DestroyRightsEnvironment"},
{2152, nullptr, "ActivateRightsEnvironment"},
{2153, nullptr, "DeactivateRightsEnvironment"},
{2154, nullptr, "ForceActivateRightsContextForExit"},
{2160, nullptr, "AddTargetApplicationToRightsEnvironment"},
{2161, nullptr, "SetUsersToRightsEnvironment"},
{2170, nullptr, "GetRightsEnvironmentStatus"},
{2171, nullptr, "GetRightsEnvironmentStatusChangedEvent"},
{2180, nullptr, "RequestExtendRightsInRightsEnvironment"},
{2181, nullptr, "GetLastResultOfExtendRightsInRightsEnvironment"},
{2182, nullptr, "SetActiveRightsContextUsingStateToRightsEnvironment"},
{2190, nullptr, "GetRightsEnvironmentHandleForApplication"},
{2199, nullptr, "GetRightsEnvironmentCountForDebug"},
{2200, nullptr, "GetGameCardApplicationCopyIdentifier"},
{2201, nullptr, "GetInstalledApplicationCopyIdentifier"},
{2250, nullptr, "RequestReportActiveELicence"},
{2300, nullptr, "ListEventLog"},
};
// clang-format on
IAccountProxyInterface::~IAccountProxyInterface() = default;
RegisterHandlers(functions);
}
IApplicationManagerInterface::IApplicationManagerInterface()
: ServiceFramework{"IApplicationManagerInterface"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "ListApplicationRecord"},
{1, nullptr, "GenerateApplicationRecordCount"},
{2, nullptr, "GetApplicationRecordUpdateSystemEvent"},
{3, nullptr, "GetApplicationViewDeprecated"},
{4, nullptr, "DeleteApplicationEntity"},
{5, nullptr, "DeleteApplicationCompletely"},
{6, nullptr, "IsAnyApplicationEntityRedundant"},
{7, nullptr, "DeleteRedundantApplicationEntity"},
{8, nullptr, "IsApplicationEntityMovable"},
{9, nullptr, "MoveApplicationEntity"},
{11, nullptr, "CalculateApplicationOccupiedSize"},
{16, nullptr, "PushApplicationRecord"},
{17, nullptr, "ListApplicationRecordContentMeta"},
{19, nullptr, "LaunchApplicationOld"},
{21, nullptr, "GetApplicationContentPath"},
{22, nullptr, "TerminateApplication"},
{23, nullptr, "ResolveApplicationContentPath"},
{26, nullptr, "BeginInstallApplication"},
{27, nullptr, "DeleteApplicationRecord"},
{30, nullptr, "RequestApplicationUpdateInfo"},
{32, nullptr, "CancelApplicationDownload"},
{33, nullptr, "ResumeApplicationDownload"},
{35, nullptr, "UpdateVersionList"},
{36, nullptr, "PushLaunchVersion"},
{37, nullptr, "ListRequiredVersion"},
{38, nullptr, "CheckApplicationLaunchVersion"},
{39, nullptr, "CheckApplicationLaunchRights"},
{40, nullptr, "GetApplicationLogoData"},
{41, nullptr, "CalculateApplicationDownloadRequiredSize"},
{42, nullptr, "CleanupSdCard"},
{43, nullptr, "CheckSdCardMountStatus"},
{44, nullptr, "GetSdCardMountStatusChangedEvent"},
{45, nullptr, "GetGameCardAttachmentEvent"},
{46, nullptr, "GetGameCardAttachmentInfo"},
{47, nullptr, "GetTotalSpaceSize"},
{48, nullptr, "GetFreeSpaceSize"},
{49, nullptr, "GetSdCardRemovedEvent"},
{52, nullptr, "GetGameCardUpdateDetectionEvent"},
{53, nullptr, "DisableApplicationAutoDelete"},
{54, nullptr, "EnableApplicationAutoDelete"},
{55, &IApplicationManagerInterface::GetApplicationDesiredLanguage, "GetApplicationDesiredLanguage"},
{56, nullptr, "SetApplicationTerminateResult"},
{57, nullptr, "ClearApplicationTerminateResult"},
{58, nullptr, "GetLastSdCardMountUnexpectedResult"},
{59, &IApplicationManagerInterface::ConvertApplicationLanguageToLanguageCode, "ConvertApplicationLanguageToLanguageCode"},
{60, nullptr, "ConvertLanguageCodeToApplicationLanguage"},
{61, nullptr, "GetBackgroundDownloadStressTaskInfo"},
{62, nullptr, "GetGameCardStopper"},
{63, nullptr, "IsSystemProgramInstalled"},
{64, nullptr, "StartApplyDeltaTask"},
{65, nullptr, "GetRequestServerStopper"},
{66, nullptr, "GetBackgroundApplyDeltaStressTaskInfo"},
{67, nullptr, "CancelApplicationApplyDelta"},
{68, nullptr, "ResumeApplicationApplyDelta"},
{69, nullptr, "CalculateApplicationApplyDeltaRequiredSize"},
{70, nullptr, "ResumeAll"},
{71, nullptr, "GetStorageSize"},
{80, nullptr, "RequestDownloadApplication"},
{81, nullptr, "RequestDownloadAddOnContent"},
{82, nullptr, "DownloadApplication"},
{83, nullptr, "CheckApplicationResumeRights"},
{84, nullptr, "GetDynamicCommitEvent"},
{85, nullptr, "RequestUpdateApplication2"},
{86, nullptr, "EnableApplicationCrashReport"},
{87, nullptr, "IsApplicationCrashReportEnabled"},
{90, nullptr, "BoostSystemMemoryResourceLimit"},
{91, nullptr, "DeprecatedLaunchApplication"},
{92, nullptr, "GetRunningApplicationProgramId"},
{93, nullptr, "GetMainApplicationProgramIndex"},
{94, nullptr, "LaunchApplication"},
{95, nullptr, "GetApplicationLaunchInfo"},
{96, nullptr, "AcquireApplicationLaunchInfo"},
{97, nullptr, "GetMainApplicationProgramIndex2"},
{98, nullptr, "EnableApplicationAllThreadDumpOnCrash"},
{100, nullptr, "ResetToFactorySettings"},
{101, nullptr, "ResetToFactorySettingsWithoutUserSaveData"},
{102, nullptr, "ResetToFactorySettingsForRefurbishment"},
{200, nullptr, "CalculateUserSaveDataStatistics"},
{201, nullptr, "DeleteUserSaveDataAll"},
{210, nullptr, "DeleteUserSystemSaveData"},
{211, nullptr, "DeleteSaveData"},
{220, nullptr, "UnregisterNetworkServiceAccount"},
{221, nullptr, "UnregisterNetworkServiceAccountWithUserSaveDataDeletion"},
{300, nullptr, "GetApplicationShellEvent"},
{301, nullptr, "PopApplicationShellEventInfo"},
{302, nullptr, "LaunchLibraryApplet"},
{303, nullptr, "TerminateLibraryApplet"},
{304, nullptr, "LaunchSystemApplet"},
{305, nullptr, "TerminateSystemApplet"},
{306, nullptr, "LaunchOverlayApplet"},
{307, nullptr, "TerminateOverlayApplet"},
{400, &IApplicationManagerInterface::GetApplicationControlData, "GetApplicationControlData"},
{401, nullptr, "InvalidateAllApplicationControlCache"},
{402, nullptr, "RequestDownloadApplicationControlData"},
{403, nullptr, "GetMaxApplicationControlCacheCount"},
{404, nullptr, "InvalidateApplicationControlCache"},
{405, nullptr, "ListApplicationControlCacheEntryInfo"},
{406, nullptr, "GetApplicationControlProperty"},
{502, nullptr, "RequestCheckGameCardRegistration"},
{503, nullptr, "RequestGameCardRegistrationGoldPoint"},
{504, nullptr, "RequestRegisterGameCard"},
{505, nullptr, "GetGameCardMountFailureEvent"},
{506, nullptr, "IsGameCardInserted"},
{507, nullptr, "EnsureGameCardAccess"},
{508, nullptr, "GetLastGameCardMountFailureResult"},
{509, nullptr, "ListApplicationIdOnGameCard"},
{600, nullptr, "CountApplicationContentMeta"},
{601, nullptr, "ListApplicationContentMetaStatus"},
{602, nullptr, "ListAvailableAddOnContent"},
{603, nullptr, "GetOwnedApplicationContentMetaStatus"},
{604, nullptr, "RegisterContentsExternalKey"},
{605, nullptr, "ListApplicationContentMetaStatusWithRightsCheck"},
{606, nullptr, "GetContentMetaStorage"},
{607, nullptr, "ListAvailableAddOnContent"},
{700, nullptr, "PushDownloadTaskList"},
{701, nullptr, "ClearTaskStatusList"},
{702, nullptr, "RequestDownloadTaskList"},
{703, nullptr, "RequestEnsureDownloadTask"},
{704, nullptr, "ListDownloadTaskStatus"},
{705, nullptr, "RequestDownloadTaskListData"},
{800, nullptr, "RequestVersionList"},
{801, nullptr, "ListVersionList"},
{802, nullptr, "RequestVersionListData"},
{900, nullptr, "GetApplicationRecord"},
{901, nullptr, "GetApplicationRecordProperty"},
{902, nullptr, "EnableApplicationAutoUpdate"},
{903, nullptr, "DisableApplicationAutoUpdate"},
{904, nullptr, "TouchApplication"},
{905, nullptr, "RequestApplicationUpdate"},
{906, nullptr, "IsApplicationUpdateRequested"},
{907, nullptr, "WithdrawApplicationUpdateRequest"},
{908, nullptr, "ListApplicationRecordInstalledContentMeta"},
{909, nullptr, "WithdrawCleanupAddOnContentsWithNoRightsRecommendation"},
{910, nullptr, "HasApplicationRecord"},
{911, nullptr, "SetPreInstalledApplication"},
{912, nullptr, "ClearPreInstalledApplicationFlag"},
{1000, nullptr, "RequestVerifyApplicationDeprecated"},
{1001, nullptr, "CorruptApplicationForDebug"},
{1002, nullptr, "RequestVerifyAddOnContentsRights"},
{1003, nullptr, "RequestVerifyApplication"},
{1004, nullptr, "CorruptContentForDebug"},
{1200, nullptr, "NeedsUpdateVulnerability"},
{1300, nullptr, "IsAnyApplicationEntityInstalled"},
{1301, nullptr, "DeleteApplicationContentEntities"},
{1302, nullptr, "CleanupUnrecordedApplicationEntity"},
{1303, nullptr, "CleanupAddOnContentsWithNoRights"},
{1304, nullptr, "DeleteApplicationContentEntity"},
{1305, nullptr, "TryDeleteRunningApplicationEntity"},
{1306, nullptr, "TryDeleteRunningApplicationCompletely"},
{1307, nullptr, "TryDeleteRunningApplicationContentEntities"},
{1308, nullptr, "DeleteApplicationCompletelyForDebug"},
{1309, nullptr, "CleanupUnavailableAddOnContents"},
{1400, nullptr, "PrepareShutdown"},
{1500, nullptr, "FormatSdCard"},
{1501, nullptr, "NeedsSystemUpdateToFormatSdCard"},
{1502, nullptr, "GetLastSdCardFormatUnexpectedResult"},
{1504, nullptr, "InsertSdCard"},
{1505, nullptr, "RemoveSdCard"},
{1600, nullptr, "GetSystemSeedForPseudoDeviceId"},
{1601, nullptr, "ResetSystemSeedForPseudoDeviceId"},
{1700, nullptr, "ListApplicationDownloadingContentMeta"},
{1701, nullptr, "GetApplicationView"},
{1702, nullptr, "GetApplicationDownloadTaskStatus"},
{1703, nullptr, "GetApplicationViewDownloadErrorContext"},
{1800, nullptr, "IsNotificationSetupCompleted"},
{1801, nullptr, "GetLastNotificationInfoCount"},
{1802, nullptr, "ListLastNotificationInfo"},
{1803, nullptr, "ListNotificationTask"},
{1900, nullptr, "IsActiveAccount"},
{1901, nullptr, "RequestDownloadApplicationPrepurchasedRights"},
{1902, nullptr, "GetApplicationTicketInfo"},
{2000, nullptr, "GetSystemDeliveryInfo"},
{2001, nullptr, "SelectLatestSystemDeliveryInfo"},
{2002, nullptr, "VerifyDeliveryProtocolVersion"},
{2003, nullptr, "GetApplicationDeliveryInfo"},
{2004, nullptr, "HasAllContentsToDeliver"},
{2005, nullptr, "CompareApplicationDeliveryInfo"},
{2006, nullptr, "CanDeliverApplication"},
{2007, nullptr, "ListContentMetaKeyToDeliverApplication"},
{2008, nullptr, "NeedsSystemUpdateToDeliverApplication"},
{2009, nullptr, "EstimateRequiredSize"},
{2010, nullptr, "RequestReceiveApplication"},
{2011, nullptr, "CommitReceiveApplication"},
{2012, nullptr, "GetReceiveApplicationProgress"},
{2013, nullptr, "RequestSendApplication"},
{2014, nullptr, "GetSendApplicationProgress"},
{2015, nullptr, "CompareSystemDeliveryInfo"},
{2016, nullptr, "ListNotCommittedContentMeta"},
{2017, nullptr, "CreateDownloadTask"},
{2018, nullptr, "GetApplicationDeliveryInfoHash"},
{2050, nullptr, "GetApplicationRightsOnClient"},
{2100, nullptr, "GetApplicationTerminateResult"},
{2101, nullptr, "GetRawApplicationTerminateResult"},
{2150, nullptr, "CreateRightsEnvironment"},
{2151, nullptr, "DestroyRightsEnvironment"},
{2152, nullptr, "ActivateRightsEnvironment"},
{2153, nullptr, "DeactivateRightsEnvironment"},
{2154, nullptr, "ForceActivateRightsContextForExit"},
{2160, nullptr, "AddTargetApplicationToRightsEnvironment"},
{2161, nullptr, "SetUsersToRightsEnvironment"},
{2170, nullptr, "GetRightsEnvironmentStatus"},
{2171, nullptr, "GetRightsEnvironmentStatusChangedEvent"},
{2180, nullptr, "RequestExtendRightsInRightsEnvironment"},
{2181, nullptr, "GetLastResultOfExtendRightsInRightsEnvironment"},
{2182, nullptr, "SetActiveRightsContextUsingStateToRightsEnvironment"},
{2190, nullptr, "GetRightsEnvironmentHandleForApplication"},
{2199, nullptr, "GetRightsEnvironmentCountForDebug"},
{2200, nullptr, "GetGameCardApplicationCopyIdentifier"},
{2201, nullptr, "GetInstalledApplicationCopyIdentifier"},
{2250, nullptr, "RequestReportActiveELicence"},
{2300, nullptr, "ListEventLog"},
};
// clang-format on
void GetApplicationControlData(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto flag = rp.PopRaw<u64>();
LOG_DEBUG(Service_NS, "called with flag={:016X}", flag);
RegisterHandlers(functions);
}
const auto title_id = rp.PopRaw<u64>();
IApplicationManagerInterface::~IApplicationManagerInterface() = default;
const auto size = ctx.GetWriteBufferSize();
void IApplicationManagerInterface::GetApplicationControlData(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto flag = rp.PopRaw<u64>();
LOG_DEBUG(Service_NS, "called with flag={:016X}", flag);
const FileSys::PatchManager pm{title_id};
const auto control = pm.GetControlMetadata();
const auto title_id = rp.PopRaw<u64>();
std::vector<u8> out;
const auto size = ctx.GetWriteBufferSize();
if (control.first != nullptr) {
if (size < 0x4000) {
LOG_ERROR(Service_NS,
"output buffer is too small! (actual={:016X}, expected_min=0x4000)",
size);
IPC::ResponseBuilder rb{ctx, 2};
// TODO(DarkLordZach): Find a better error code for this.
rb.Push(ResultCode(-1));
return;
}
const FileSys::PatchManager pm{title_id};
const auto control = pm.GetControlMetadata();
out.resize(0x4000);
const auto bytes = control.first->GetRawBytes();
std::memcpy(out.data(), bytes.data(), bytes.size());
} else {
LOG_WARNING(Service_NS, "missing NACP data for title_id={:016X}, defaulting to zeros.",
title_id);
out.resize(std::min<u64>(0x4000, size));
std::vector<u8> out;
if (control.first != nullptr) {
if (size < 0x4000) {
LOG_ERROR(Service_NS,
"output buffer is too small! (actual={:016X}, expected_min=0x4000)", size);
IPC::ResponseBuilder rb{ctx, 2};
// TODO(DarkLordZach): Find a better error code for this.
rb.Push(ResultCode(-1));
return;
}
if (control.second != nullptr) {
if (size < 0x4000 + control.second->GetSize()) {
LOG_ERROR(Service_NS,
"output buffer is too small! (actual={:016X}, expected_min={:016X})",
size, 0x4000 + control.second->GetSize());
IPC::ResponseBuilder rb{ctx, 2};
// TODO(DarkLordZach): Find a better error code for this.
rb.Push(ResultCode(-1));
return;
}
out.resize(0x4000);
const auto bytes = control.first->GetRawBytes();
std::memcpy(out.data(), bytes.data(), bytes.size());
} else {
LOG_WARNING(Service_NS, "missing NACP data for title_id={:016X}, defaulting to zeros.",
title_id);
out.resize(std::min<u64>(0x4000, size));
}
out.resize(0x4000 + control.second->GetSize());
control.second->Read(out.data() + 0x4000, control.second->GetSize());
} else {
LOG_WARNING(Service_NS, "missing icon data for title_id={:016X}, defaulting to zeros.",
title_id);
if (control.second != nullptr) {
if (size < 0x4000 + control.second->GetSize()) {
LOG_ERROR(Service_NS,
"output buffer is too small! (actual={:016X}, expected_min={:016X})", size,
0x4000 + control.second->GetSize());
IPC::ResponseBuilder rb{ctx, 2};
// TODO(DarkLordZach): Find a better error code for this.
rb.Push(ResultCode(-1));
return;
}
ctx.WriteBuffer(out);
out.resize(0x4000 + control.second->GetSize());
control.second->Read(out.data() + 0x4000, control.second->GetSize());
} else {
LOG_WARNING(Service_NS, "missing icon data for title_id={:016X}, defaulting to zeros.",
title_id);
}
ctx.WriteBuffer(out);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(static_cast<u32>(out.size()));
}
void IApplicationManagerInterface::GetApplicationDesiredLanguage(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto supported_languages = rp.Pop<u32>();
const auto res = GetApplicationDesiredLanguage(supported_languages);
if (res.Succeeded()) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(static_cast<u32>(out.size()));
rb.Push<u32>(*res);
} else {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res.Code());
}
};
}
class IApplicationVersionInterface final : public ServiceFramework<IApplicationVersionInterface> {
public:
explicit IApplicationVersionInterface() : ServiceFramework{"IApplicationVersionInterface"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetLaunchRequiredVersion"},
{1, nullptr, "UpgradeLaunchRequiredVersion"},
{35, nullptr, "UpdateVersionList"},
{36, nullptr, "PushLaunchVersion"},
{37, nullptr, "ListRequiredVersion"},
{800, nullptr, "RequestVersionList"},
{801, nullptr, "ListVersionList"},
{802, nullptr, "RequestVersionListData"},
{1000, nullptr, "PerformAutoUpdate"},
};
// clang-format on
ResultVal<u8> IApplicationManagerInterface::GetApplicationDesiredLanguage(
const u32 supported_languages) {
LOG_DEBUG(Service_NS, "called with supported_languages={:08X}", supported_languages);
RegisterHandlers(functions);
// Get language code from settings
const auto language_code = Set::GetLanguageCodeFromIndex(Settings::values.language_index);
// Convert to application language, get priority list
const auto application_language = ConvertToApplicationLanguage(language_code);
if (application_language == std::nullopt) {
return ERR_APPLICATION_LANGUAGE_NOT_FOUND;
}
};
class IContentManagerInterface final : public ServiceFramework<IContentManagerInterface> {
public:
explicit IContentManagerInterface() : ServiceFramework{"IContentManagerInterface"} {
// clang-format off
static const FunctionInfo functions[] = {
{11, nullptr, "CalculateApplicationOccupiedSize"},
{43, nullptr, "CheckSdCardMountStatus"},
{47, nullptr, "GetTotalSpaceSize"},
{48, nullptr, "GetFreeSpaceSize"},
{600, nullptr, "CountApplicationContentMeta"},
{601, nullptr, "ListApplicationContentMetaStatus"},
{605, nullptr, "ListApplicationContentMetaStatusWithRightsCheck"},
{607, nullptr, "IsAnyApplicationRunning"},
};
// clang-format on
RegisterHandlers(functions);
const auto priority_list = GetApplicationLanguagePriorityList(*application_language);
if (!priority_list) {
return ERR_APPLICATION_LANGUAGE_NOT_FOUND;
}
};
class IDocumentInterface final : public ServiceFramework<IDocumentInterface> {
public:
explicit IDocumentInterface() : ServiceFramework{"IDocumentInterface"} {
// clang-format off
static const FunctionInfo functions[] = {
{21, nullptr, "GetApplicationContentPath"},
{23, nullptr, "ResolveApplicationContentPath"},
{93, nullptr, "GetRunningApplicationProgramId"},
};
// clang-format on
RegisterHandlers(functions);
// Try to find a valid language.
for (const auto lang : *priority_list) {
const auto supported_flag = GetSupportedLanguageFlag(lang);
if (supported_languages == 0 || (supported_languages & supported_flag) == supported_flag) {
return MakeResult(static_cast<u8>(lang));
}
}
};
class IDownloadTaskInterface final : public ServiceFramework<IDownloadTaskInterface> {
public:
explicit IDownloadTaskInterface() : ServiceFramework{"IDownloadTaskInterface"} {
// clang-format off
static const FunctionInfo functions[] = {
{701, nullptr, "ClearTaskStatusList"},
{702, nullptr, "RequestDownloadTaskList"},
{703, nullptr, "RequestEnsureDownloadTask"},
{704, nullptr, "ListDownloadTaskStatus"},
{705, nullptr, "RequestDownloadTaskListData"},
{706, nullptr, "TryCommitCurrentApplicationDownloadTask"},
{707, nullptr, "EnableAutoCommit"},
{708, nullptr, "DisableAutoCommit"},
{709, nullptr, "TriggerDynamicCommitEvent"},
};
// clang-format on
return ERR_APPLICATION_LANGUAGE_NOT_FOUND;
}
RegisterHandlers(functions);
void IApplicationManagerInterface::ConvertApplicationLanguageToLanguageCode(
Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto application_language = rp.Pop<u8>();
const auto res = ConvertApplicationLanguageToLanguageCode(application_language);
if (res.Succeeded()) {
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push(*res);
} else {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res.Code());
}
};
}
class IECommerceInterface final : public ServiceFramework<IECommerceInterface> {
public:
explicit IECommerceInterface() : ServiceFramework{"IECommerceInterface"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "RequestLinkDevice"},
{1, nullptr, "RequestCleanupAllPreInstalledApplications"},
{2, nullptr, "RequestCleanupPreInstalledApplication"},
{3, nullptr, "RequestSyncRights"},
{4, nullptr, "RequestUnlinkDevice"},
{5, nullptr, "RequestRevokeAllELicense"},
};
// clang-format on
RegisterHandlers(functions);
ResultVal<u64> IApplicationManagerInterface::ConvertApplicationLanguageToLanguageCode(
u8 application_language) {
const auto language_code =
ConvertToLanguageCode(static_cast<ApplicationLanguage>(application_language));
if (language_code == std::nullopt) {
return ERR_APPLICATION_LANGUAGE_NOT_FOUND;
}
};
class IFactoryResetInterface final : public ServiceFramework<IFactoryResetInterface> {
public:
explicit IFactoryResetInterface() : ServiceFramework{"IFactoryResetInterface"} {
// clang-format off
return MakeResult(static_cast<u64>(*language_code));
}
IApplicationVersionInterface::IApplicationVersionInterface()
: ServiceFramework{"IApplicationVersionInterface"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetLaunchRequiredVersion"},
{1, nullptr, "UpgradeLaunchRequiredVersion"},
{35, nullptr, "UpdateVersionList"},
{36, nullptr, "PushLaunchVersion"},
{37, nullptr, "ListRequiredVersion"},
{800, nullptr, "RequestVersionList"},
{801, nullptr, "ListVersionList"},
{802, nullptr, "RequestVersionListData"},
{1000, nullptr, "PerformAutoUpdate"},
};
// clang-format on
RegisterHandlers(functions);
}
IApplicationVersionInterface::~IApplicationVersionInterface() = default;
IContentManagerInterface::IContentManagerInterface()
: ServiceFramework{"IContentManagerInterface"} {
// clang-format off
static const FunctionInfo functions[] = {
{11, nullptr, "CalculateApplicationOccupiedSize"},
{43, nullptr, "CheckSdCardMountStatus"},
{47, nullptr, "GetTotalSpaceSize"},
{48, nullptr, "GetFreeSpaceSize"},
{600, nullptr, "CountApplicationContentMeta"},
{601, nullptr, "ListApplicationContentMetaStatus"},
{605, nullptr, "ListApplicationContentMetaStatusWithRightsCheck"},
{607, nullptr, "IsAnyApplicationRunning"},
};
// clang-format on
RegisterHandlers(functions);
}
IContentManagerInterface::~IContentManagerInterface() = default;
IDocumentInterface::IDocumentInterface() : ServiceFramework{"IDocumentInterface"} {
// clang-format off
static const FunctionInfo functions[] = {
{21, nullptr, "GetApplicationContentPath"},
{23, nullptr, "ResolveApplicationContentPath"},
{93, nullptr, "GetRunningApplicationProgramId"},
};
// clang-format on
RegisterHandlers(functions);
}
IDocumentInterface::~IDocumentInterface() = default;
IDownloadTaskInterface::IDownloadTaskInterface() : ServiceFramework{"IDownloadTaskInterface"} {
// clang-format off
static const FunctionInfo functions[] = {
{701, nullptr, "ClearTaskStatusList"},
{702, nullptr, "RequestDownloadTaskList"},
{703, nullptr, "RequestEnsureDownloadTask"},
{704, nullptr, "ListDownloadTaskStatus"},
{705, nullptr, "RequestDownloadTaskListData"},
{706, nullptr, "TryCommitCurrentApplicationDownloadTask"},
{707, nullptr, "EnableAutoCommit"},
{708, nullptr, "DisableAutoCommit"},
{709, nullptr, "TriggerDynamicCommitEvent"},
};
// clang-format on
RegisterHandlers(functions);
}
IDownloadTaskInterface::~IDownloadTaskInterface() = default;
IECommerceInterface::IECommerceInterface() : ServiceFramework{"IECommerceInterface"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "RequestLinkDevice"},
{1, nullptr, "RequestCleanupAllPreInstalledApplications"},
{2, nullptr, "RequestCleanupPreInstalledApplication"},
{3, nullptr, "RequestSyncRights"},
{4, nullptr, "RequestUnlinkDevice"},
{5, nullptr, "RequestRevokeAllELicense"},
};
// clang-format on
RegisterHandlers(functions);
}
IECommerceInterface::~IECommerceInterface() = default;
IFactoryResetInterface::IFactoryResetInterface::IFactoryResetInterface()
: ServiceFramework{"IFactoryResetInterface"} {
// clang-format off
static const FunctionInfo functions[] = {
{100, nullptr, "ResetToFactorySettings"},
{101, nullptr, "ResetToFactorySettingsWithoutUserSaveData"},
{102, nullptr, "ResetToFactorySettingsForRefurbishment"},
};
// clang-format on
// clang-format on
RegisterHandlers(functions);
}
};
RegisterHandlers(functions);
}
class NS final : public ServiceFramework<NS> {
public:
explicit NS(const char* name) : ServiceFramework{name} {
// clang-format off
static const FunctionInfo functions[] = {
{7992, &NS::PushInterface<IECommerceInterface>, "GetECommerceInterface"},
{7993, &NS::PushInterface<IApplicationVersionInterface>, "GetApplicationVersionInterface"},
{7994, &NS::PushInterface<IFactoryResetInterface>, "GetFactoryResetInterface"},
{7995, &NS::PushInterface<IAccountProxyInterface>, "GetAccountProxyInterface"},
{7996, &NS::PushInterface<IApplicationManagerInterface>, "GetApplicationManagerInterface"},
{7997, &NS::PushInterface<IDownloadTaskInterface>, "GetDownloadTaskInterface"},
{7998, &NS::PushInterface<IContentManagerInterface>, "GetContentManagementInterface"},
{7999, &NS::PushInterface<IDocumentInterface>, "GetDocumentInterface"},
};
// clang-format on
IFactoryResetInterface::~IFactoryResetInterface() = default;
RegisterHandlers(functions);
}
NS::NS(const char* name) : ServiceFramework{name} {
// clang-format off
static const FunctionInfo functions[] = {
{7992, &NS::PushInterface<IECommerceInterface>, "GetECommerceInterface"},
{7993, &NS::PushInterface<IApplicationVersionInterface>, "GetApplicationVersionInterface"},
{7994, &NS::PushInterface<IFactoryResetInterface>, "GetFactoryResetInterface"},
{7995, &NS::PushInterface<IAccountProxyInterface>, "GetAccountProxyInterface"},
{7996, &NS::PushInterface<IApplicationManagerInterface>, "GetApplicationManagerInterface"},
{7997, &NS::PushInterface<IDownloadTaskInterface>, "GetDownloadTaskInterface"},
{7998, &NS::PushInterface<IContentManagerInterface>, "GetContentManagementInterface"},
{7999, &NS::PushInterface<IDocumentInterface>, "GetDocumentInterface"},
};
// clang-format on
private:
template <typename T>
void PushInterface(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_NS, "called");
RegisterHandlers(functions);
}
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<T>();
}
};
NS::~NS() = default;
std::shared_ptr<IApplicationManagerInterface> NS::GetApplicationManagerInterface() const {
return GetInterface<IApplicationManagerInterface>();
}
class NS_DEV final : public ServiceFramework<NS_DEV> {
public:
+82
View File
@@ -8,6 +8,88 @@
namespace Service::NS {
class IAccountProxyInterface final : public ServiceFramework<IAccountProxyInterface> {
public:
explicit IAccountProxyInterface();
~IAccountProxyInterface();
};
class IApplicationManagerInterface final : public ServiceFramework<IApplicationManagerInterface> {
public:
explicit IApplicationManagerInterface();
~IApplicationManagerInterface();
ResultVal<u8> GetApplicationDesiredLanguage(u32 supported_languages);
ResultVal<u64> ConvertApplicationLanguageToLanguageCode(u8 application_language);
private:
void GetApplicationControlData(Kernel::HLERequestContext& ctx);
void GetApplicationDesiredLanguage(Kernel::HLERequestContext& ctx);
void ConvertApplicationLanguageToLanguageCode(Kernel::HLERequestContext& ctx);
};
class IApplicationVersionInterface final : public ServiceFramework<IApplicationVersionInterface> {
public:
explicit IApplicationVersionInterface();
~IApplicationVersionInterface();
};
class IContentManagerInterface final : public ServiceFramework<IContentManagerInterface> {
public:
explicit IContentManagerInterface();
~IContentManagerInterface();
};
class IDocumentInterface final : public ServiceFramework<IDocumentInterface> {
public:
explicit IDocumentInterface();
~IDocumentInterface();
};
class IDownloadTaskInterface final : public ServiceFramework<IDownloadTaskInterface> {
public:
explicit IDownloadTaskInterface();
~IDownloadTaskInterface();
};
class IECommerceInterface final : public ServiceFramework<IECommerceInterface> {
public:
explicit IECommerceInterface();
~IECommerceInterface();
};
class IFactoryResetInterface final : public ServiceFramework<IFactoryResetInterface> {
public:
explicit IFactoryResetInterface();
~IFactoryResetInterface();
};
class NS final : public ServiceFramework<NS> {
public:
explicit NS(const char* name);
~NS();
std::shared_ptr<IApplicationManagerInterface> GetApplicationManagerInterface() const;
private:
template <typename T>
void PushInterface(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_NS, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<T>();
}
template <typename T>
std::shared_ptr<T> GetInterface() const {
static_assert(std::is_base_of_v<Kernel::SessionRequestHandler, T>,
"Not a base of ServiceFrameworkBase");
return std::make_shared<T>();
}
};
/// Registers all NS services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager);
+42
View File
@@ -0,0 +1,42 @@
// Copyright 2019 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <optional>
#include <string>
#include "common/common_types.h"
#include "core/hle/service/set/set.h"
namespace Service::NS {
/// This is nn::ns::detail::ApplicationLanguage
enum class ApplicationLanguage : u8 {
AmericanEnglish = 0,
BritishEnglish,
Japanese,
French,
German,
LatinAmericanSpanish,
Spanish,
Italian,
Dutch,
CanadianFrench,
Portuguese,
Russian,
Korean,
TraditionalChinese,
SimplifiedChinese,
Count
};
using ApplicationLanguagePriorityList =
const std::array<ApplicationLanguage, static_cast<std::size_t>(ApplicationLanguage::Count)>;
constexpr u32 GetSupportedLanguageFlag(const ApplicationLanguage lang) {
return 1U << static_cast<u32>(lang);
}
const ApplicationLanguagePriorityList* GetApplicationLanguagePriorityList(ApplicationLanguage lang);
std::optional<ApplicationLanguage> ConvertToApplicationLanguage(
Service::Set::LanguageCode language_code);
std::optional<Service::Set::LanguageCode> ConvertToLanguageCode(ApplicationLanguage lang);
} // namespace Service::NS
-11
View File
@@ -153,17 +153,6 @@ public:
*/
virtual LoadResult Load(Kernel::Process& process) = 0;
/**
* Loads the system mode that this application needs.
* This function defaults to 2 (96MB allocated to the application) if it can't read the
* information.
* @returns A pair with the optional system mode, and and the status.
*/
virtual std::pair<std::optional<u32>, ResultStatus> LoadKernelSystemMode() {
// 96MB allocated to the application.
return std::make_pair(2, ResultStatus::Success);
}
/**
* Get the code (typically .code section) of the application
* @param buffer Reference to buffer to store data
+31 -28
View File
@@ -12,7 +12,6 @@
#include "common/file_util.h"
#include "common/logging/log.h"
#include "core/core.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
#include "core/loader/loader.h"
@@ -101,7 +100,30 @@ bool VerifyLogin(const std::string& username, const std::string& token) {
#endif
}
TelemetrySession::TelemetrySession() {
TelemetrySession::TelemetrySession() = default;
TelemetrySession::~TelemetrySession() {
// Log one-time session end information
const s64 shutdown_time{std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch())
.count()};
AddField(Telemetry::FieldType::Session, "Shutdown_Time", shutdown_time);
#ifdef ENABLE_WEB_SERVICE
auto backend = std::make_unique<WebService::TelemetryJson>(
Settings::values.web_api_url, Settings::values.yuzu_username, Settings::values.yuzu_token);
#else
auto backend = std::make_unique<Telemetry::NullVisitor>();
#endif
// Complete the session, submitting to the web service backend if necessary
field_collection.Accept(*backend);
if (Settings::values.enable_telemetry) {
backend->Complete();
}
}
void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader) {
// Log one-time top-level information
AddField(Telemetry::FieldType::None, "TelemetryId", GetTelemetryId());
@@ -112,26 +134,28 @@ TelemetrySession::TelemetrySession() {
AddField(Telemetry::FieldType::Session, "Init_Time", init_time);
u64 program_id{};
const Loader::ResultStatus res{System::GetInstance().GetAppLoader().ReadProgramId(program_id)};
const Loader::ResultStatus res{app_loader.ReadProgramId(program_id)};
if (res == Loader::ResultStatus::Success) {
const std::string formatted_program_id{fmt::format("{:016X}", program_id)};
AddField(Telemetry::FieldType::Session, "ProgramId", formatted_program_id);
std::string name;
System::GetInstance().GetAppLoader().ReadTitle(name);
app_loader.ReadTitle(name);
if (name.empty()) {
auto [nacp, icon_file] = FileSys::PatchManager(program_id).GetControlMetadata();
if (nacp != nullptr)
if (nacp != nullptr) {
name = nacp->GetApplicationName();
}
}
if (!name.empty())
if (!name.empty()) {
AddField(Telemetry::FieldType::Session, "ProgramName", name);
}
}
AddField(Telemetry::FieldType::Session, "ProgramFormat",
static_cast<u8>(System::GetInstance().GetAppLoader().GetFileType()));
static_cast<u8>(app_loader.GetFileType()));
// Log application information
Telemetry::AppendBuildInfo(field_collection);
@@ -162,27 +186,6 @@ TelemetrySession::TelemetrySession() {
Settings::values.use_docked_mode);
}
TelemetrySession::~TelemetrySession() {
// Log one-time session end information
const s64 shutdown_time{std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch())
.count()};
AddField(Telemetry::FieldType::Session, "Shutdown_Time", shutdown_time);
#ifdef ENABLE_WEB_SERVICE
auto backend = std::make_unique<WebService::TelemetryJson>(
Settings::values.web_api_url, Settings::values.yuzu_username, Settings::values.yuzu_token);
#else
auto backend = std::make_unique<Telemetry::NullVisitor>();
#endif
// Complete the session, submitting to web service if necessary
field_collection.Accept(*backend);
if (Settings::values.enable_telemetry)
backend->Complete();
backend = nullptr;
}
bool TelemetrySession::SubmitTestcase() {
#ifdef ENABLE_WEB_SERVICE
auto backend = std::make_unique<WebService::TelemetryJson>(
+28 -3
View File
@@ -4,10 +4,13 @@
#pragma once
#include <memory>
#include <string>
#include "common/telemetry.h"
namespace Loader {
class AppLoader;
}
namespace Core {
/**
@@ -15,11 +18,33 @@ namespace Core {
* session, logging any one-time fields. Interfaces with the telemetry backend used for submitting
* data to the web service. Submits session data on close.
*/
class TelemetrySession : NonCopyable {
class TelemetrySession {
public:
TelemetrySession();
explicit TelemetrySession();
~TelemetrySession();
TelemetrySession(const TelemetrySession&) = delete;
TelemetrySession& operator=(const TelemetrySession&) = delete;
TelemetrySession(TelemetrySession&&) = delete;
TelemetrySession& operator=(TelemetrySession&&) = delete;
/**
* Adds the initial telemetry info necessary when starting up a title.
*
* This includes information such as:
* - Telemetry ID
* - Initialization time
* - Title ID
* - Title name
* - Title file format
* - Miscellaneous settings values.
*
* @param app_loader The application loader to use to retrieve
* title-specific information.
*/
void AddInitialInfo(Loader::AppLoader& app_loader);
/**
* Wrapper around the Telemetry::FieldCollection::AddField method.
* @param type Type of the field to add.
-7
View File
@@ -6,15 +6,8 @@
#include <memory>
#include <vector>
#include "core/frontend/input.h"
#include "input_common/main.h"
union SDL_Event;
namespace Common {
class ParamPackage;
} // namespace Common
namespace InputCommon::Polling {
class DevicePoller;
enum class DeviceType;
+65 -69
View File
@@ -6,7 +6,6 @@
#include <atomic>
#include <cmath>
#include <functional>
#include <iterator>
#include <mutex>
#include <string>
#include <thread>
@@ -15,7 +14,6 @@
#include <utility>
#include <vector>
#include <SDL.h>
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/math_util.h"
#include "common/param_package.h"
@@ -23,12 +21,10 @@
#include "core/frontend/input.h"
#include "input_common/sdl/sdl_impl.h"
namespace InputCommon {
namespace SDL {
namespace InputCommon::SDL {
static std::string GetGUID(SDL_Joystick* joystick) {
SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
const SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
char guid_str[33];
SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str));
return guid_str;
@@ -37,26 +33,27 @@ static std::string GetGUID(SDL_Joystick* joystick) {
/// Creates a ParamPackage from an SDL_Event that can directly be used to create a ButtonDevice
static Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event);
static int SDLEventWatcher(void* userdata, SDL_Event* event) {
SDLState* sdl_state = reinterpret_cast<SDLState*>(userdata);
static int SDLEventWatcher(void* user_data, SDL_Event* event) {
auto* const sdl_state = static_cast<SDLState*>(user_data);
// Don't handle the event if we are configuring
if (sdl_state->polling) {
sdl_state->event_queue.Push(*event);
} else {
sdl_state->HandleGameControllerEvent(*event);
}
return 0;
}
class SDLJoystick {
public:
SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick,
decltype(&SDL_JoystickClose) deleter = &SDL_JoystickClose)
: guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, deleter} {}
SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick)
: guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose} {}
void SetButton(int button, bool value) {
std::lock_guard lock{mutex};
state.buttons[button] = value;
state.buttons.insert_or_assign(button, value);
}
bool GetButton(int button) const {
@@ -66,7 +63,7 @@ public:
void SetAxis(int axis, Sint16 value) {
std::lock_guard lock{mutex};
state.axes[axis] = value;
state.axes.insert_or_assign(axis, value);
}
float GetAxis(int axis) const {
@@ -93,7 +90,7 @@ public:
void SetHat(int hat, Uint8 direction) {
std::lock_guard lock{mutex};
state.hats[hat] = direction;
state.hats.insert_or_assign(hat, direction);
}
bool GetHatDirection(int hat, Uint8 direction) const {
@@ -118,10 +115,8 @@ public:
return sdl_joystick.get();
}
void SetSDLJoystick(SDL_Joystick* joystick,
decltype(&SDL_JoystickClose) deleter = &SDL_JoystickClose) {
sdl_joystick =
std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)>(joystick, deleter);
void SetSDLJoystick(SDL_Joystick* joystick) {
sdl_joystick.reset(joystick);
}
private:
@@ -136,59 +131,57 @@ private:
mutable std::mutex mutex;
};
/**
* Get the nth joystick with the corresponding GUID
*/
std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) {
std::lock_guard lock{joystick_map_mutex};
const auto it = joystick_map.find(guid);
if (it != joystick_map.end()) {
while (it->second.size() <= static_cast<std::size_t>(port)) {
auto joystick = std::make_shared<SDLJoystick>(guid, static_cast<int>(it->second.size()),
nullptr, [](SDL_Joystick*) {});
auto joystick =
std::make_shared<SDLJoystick>(guid, static_cast<int>(it->second.size()), nullptr);
it->second.emplace_back(std::move(joystick));
}
return it->second[port];
}
auto joystick = std::make_shared<SDLJoystick>(guid, 0, nullptr, [](SDL_Joystick*) {});
auto joystick = std::make_shared<SDLJoystick>(guid, 0, nullptr);
return joystick_map[guid].emplace_back(std::move(joystick));
}
/**
* Check how many identical joysticks (by guid) were connected before the one with sdl_id and so tie
* it to a SDLJoystick with the same guid and that port
*/
std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) {
auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id);
const std::string guid = GetGUID(sdl_joystick);
std::lock_guard lock{joystick_map_mutex};
auto map_it = joystick_map.find(guid);
const auto map_it = joystick_map.find(guid);
if (map_it != joystick_map.end()) {
auto vec_it = std::find_if(map_it->second.begin(), map_it->second.end(),
[&sdl_joystick](const std::shared_ptr<SDLJoystick>& joystick) {
return sdl_joystick == joystick->GetSDLJoystick();
});
const auto vec_it =
std::find_if(map_it->second.begin(), map_it->second.end(),
[&sdl_joystick](const std::shared_ptr<SDLJoystick>& joystick) {
return sdl_joystick == joystick->GetSDLJoystick();
});
if (vec_it != map_it->second.end()) {
// This is the common case: There is already an existing SDL_Joystick maped to a
// SDLJoystick. return the SDLJoystick
return *vec_it;
}
// Search for a SDLJoystick without a mapped SDL_Joystick...
auto nullptr_it = std::find_if(map_it->second.begin(), map_it->second.end(),
[](const std::shared_ptr<SDLJoystick>& joystick) {
return !joystick->GetSDLJoystick();
});
const auto nullptr_it = std::find_if(map_it->second.begin(), map_it->second.end(),
[](const std::shared_ptr<SDLJoystick>& joystick) {
return !joystick->GetSDLJoystick();
});
if (nullptr_it != map_it->second.end()) {
// ... and map it
(*nullptr_it)->SetSDLJoystick(sdl_joystick);
return *nullptr_it;
}
// There is no SDLJoystick without a mapped SDL_Joystick
// Create a new SDLJoystick
auto joystick = std::make_shared<SDLJoystick>(guid, map_it->second.size(), sdl_joystick);
const int port = static_cast<int>(map_it->second.size());
auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick);
return map_it->second.emplace_back(std::move(joystick));
}
auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick);
return joystick_map[guid].emplace_back(std::move(joystick));
}
@@ -215,17 +208,19 @@ void SDLState::InitJoystick(int joystick_index) {
(*it)->SetSDLJoystick(sdl_joystick);
return;
}
auto joystick = std::make_shared<SDLJoystick>(guid, joystick_guid_list.size(), sdl_joystick);
const int port = static_cast<int>(joystick_guid_list.size());
auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick);
joystick_guid_list.emplace_back(std::move(joystick));
}
void SDLState::CloseJoystick(SDL_Joystick* sdl_joystick) {
std::string guid = GetGUID(sdl_joystick);
const std::string guid = GetGUID(sdl_joystick);
std::shared_ptr<SDLJoystick> joystick;
{
std::lock_guard lock{joystick_map_mutex};
// This call to guid is safe since the joystick is guaranteed to be in the map
auto& joystick_guid_list = joystick_map[guid];
const auto& joystick_guid_list = joystick_map[guid];
const auto joystick_it =
std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(),
[&sdl_joystick](const std::shared_ptr<SDLJoystick>& joystick) {
@@ -233,9 +228,10 @@ void SDLState::CloseJoystick(SDL_Joystick* sdl_joystick) {
});
joystick = *joystick_it;
}
// Destruct SDL_Joystick outside the lock guard because SDL can internally call event calback
// which locks the mutex again
joystick->SetSDLJoystick(nullptr, [](SDL_Joystick*) {});
// Destruct SDL_Joystick outside the lock guard because SDL can internally call the
// event callback which locks the mutex again.
joystick->SetSDLJoystick(nullptr);
}
void SDLState::HandleGameControllerEvent(const SDL_Event& event) {
@@ -317,9 +313,10 @@ public:
trigger_if_greater(trigger_if_greater_) {}
bool GetStatus() const override {
float axis_value = joystick->GetAxis(axis);
if (trigger_if_greater)
const float axis_value = joystick->GetAxis(axis);
if (trigger_if_greater) {
return axis_value > threshold;
}
return axis_value < threshold;
}
@@ -444,7 +441,7 @@ public:
const int port = params.Get("port", 0);
const int axis_x = params.Get("axis_x", 0);
const int axis_y = params.Get("axis_y", 1);
float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, .99f);
const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, .99f);
auto joystick = state.GetSDLJoystickByGUID(guid, port);
@@ -470,7 +467,7 @@ SDLState::SDLState() {
return;
}
if (SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1") == SDL_FALSE) {
LOG_ERROR(Input, "Failed to set Hint for background events", SDL_GetError());
LOG_ERROR(Input, "Failed to set hint for background events with: {}", SDL_GetError());
}
SDL_AddEventWatch(&SDLEventWatcher, this);
@@ -507,12 +504,12 @@ SDLState::~SDLState() {
}
}
Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) {
static Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) {
Common::ParamPackage params({{"engine", "sdl"}});
switch (event.type) {
case SDL_JOYAXISMOTION: {
auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
params.Set("port", joystick->GetPort());
params.Set("guid", joystick->GetGUID());
params.Set("axis", event.jaxis.axis);
@@ -526,14 +523,14 @@ Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Eve
break;
}
case SDL_JOYBUTTONUP: {
auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which);
const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which);
params.Set("port", joystick->GetPort());
params.Set("guid", joystick->GetGUID());
params.Set("button", event.jbutton.button);
break;
}
case SDL_JOYHATMOTION: {
auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which);
const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which);
params.Set("port", joystick->GetPort());
params.Set("guid", joystick->GetGUID());
params.Set("hat", event.jhat.hat);
@@ -607,8 +604,8 @@ public:
SDLPoller::Start();
// Reset stored axes
analog_xaxis = -1;
analog_yaxis = -1;
analog_x_axis = -1;
analog_y_axis = -1;
analog_axes_joystick = -1;
}
@@ -620,25 +617,25 @@ public:
}
// An analog device needs two axes, so we need to store the axis for later and wait for
// a second SDL event. The axes also must be from the same joystick.
int axis = event.jaxis.axis;
if (analog_xaxis == -1) {
analog_xaxis = axis;
const int axis = event.jaxis.axis;
if (analog_x_axis == -1) {
analog_x_axis = axis;
analog_axes_joystick = event.jaxis.which;
} else if (analog_yaxis == -1 && analog_xaxis != axis &&
} else if (analog_y_axis == -1 && analog_x_axis != axis &&
analog_axes_joystick == event.jaxis.which) {
analog_yaxis = axis;
analog_y_axis = axis;
}
}
Common::ParamPackage params;
if (analog_xaxis != -1 && analog_yaxis != -1) {
auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
if (analog_x_axis != -1 && analog_y_axis != -1) {
const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
params.Set("engine", "sdl");
params.Set("port", joystick->GetPort());
params.Set("guid", joystick->GetGUID());
params.Set("axis_x", analog_xaxis);
params.Set("axis_y", analog_yaxis);
analog_xaxis = -1;
analog_yaxis = -1;
params.Set("axis_x", analog_x_axis);
params.Set("axis_y", analog_y_axis);
analog_x_axis = -1;
analog_y_axis = -1;
analog_axes_joystick = -1;
return params;
}
@@ -646,8 +643,8 @@ public:
}
private:
int analog_xaxis = -1;
int analog_yaxis = -1;
int analog_x_axis = -1;
int analog_y_axis = -1;
SDL_JoystickID analog_axes_joystick = -1;
};
} // namespace Polling
@@ -667,5 +664,4 @@ SDLState::Pollers SDLState::GetPollers(InputCommon::Polling::DeviceType type) {
return pollers;
}
} // namespace SDL
} // namespace InputCommon
} // namespace InputCommon::SDL
+11 -2
View File
@@ -6,7 +6,10 @@
#include <atomic>
#include <memory>
#include <mutex>
#include <thread>
#include <unordered_map>
#include "common/common_types.h"
#include "common/threadsafe_queue.h"
#include "input_common/sdl/sdl.h"
@@ -16,9 +19,9 @@ using SDL_JoystickID = s32;
namespace InputCommon::SDL {
class SDLJoystick;
class SDLButtonFactory;
class SDLAnalogFactory;
class SDLButtonFactory;
class SDLJoystick;
class SDLState : public State {
public:
@@ -31,7 +34,13 @@ public:
/// Handle SDL_Events for joysticks from SDL_PollEvent
void HandleGameControllerEvent(const SDL_Event& event);
/// Get the nth joystick with the corresponding GUID
std::shared_ptr<SDLJoystick> GetSDLJoystickBySDLID(SDL_JoystickID sdl_id);
/**
* Check how many identical joysticks (by guid) were connected before the one with sdl_id and so
* tie it to a SDLJoystick with the same guid and that port
*/
std::shared_ptr<SDLJoystick> GetSDLJoystickByGUID(const std::string& guid, int port);
/// Get all DevicePoller that use the SDL backend for a specific device type
@@ -2,11 +2,14 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <array>
#include <cstddef>
#include <glad/glad.h>
#include "common/logging/log.h"
#include "common/scope_exit.h"
#include "video_core/renderer_opengl/gl_device.h"
#include "video_core/renderer_opengl/gl_resource_manager.h"
namespace OpenGL {
@@ -24,6 +27,7 @@ Device::Device() {
max_vertex_attributes = GetInteger<u32>(GL_MAX_VERTEX_ATTRIBS);
max_varyings = GetInteger<u32>(GL_MAX_VARYING_VECTORS);
has_variable_aoffi = TestVariableAoffi();
has_component_indexing_bug = TestComponentIndexingBug();
}
Device::Device(std::nullptr_t) {
@@ -31,6 +35,7 @@ Device::Device(std::nullptr_t) {
max_vertex_attributes = 16;
max_varyings = 15;
has_variable_aoffi = true;
has_component_indexing_bug = false;
}
bool Device::TestVariableAoffi() {
@@ -52,4 +57,53 @@ void main() {
return supported;
}
bool Device::TestComponentIndexingBug() {
constexpr char log_message[] = "Renderer_ComponentIndexingBug: {}";
const GLchar* COMPONENT_TEST = R"(#version 430 core
layout (std430, binding = 0) buffer OutputBuffer {
uint output_value;
};
layout (std140, binding = 0) uniform InputBuffer {
uvec4 input_value[4096];
};
layout (location = 0) uniform uint idx;
void main() {
output_value = input_value[idx >> 2][idx & 3];
})";
const GLuint shader{glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &COMPONENT_TEST)};
SCOPE_EXIT({ glDeleteProgram(shader); });
glUseProgram(shader);
OGLVertexArray vao;
vao.Create();
glBindVertexArray(vao.handle);
constexpr std::array<GLuint, 8> values{0, 0, 0, 0, 0x1236327, 0x985482, 0x872753, 0x2378432};
OGLBuffer ubo;
ubo.Create();
glNamedBufferData(ubo.handle, sizeof(values), values.data(), GL_STATIC_DRAW);
glBindBufferBase(GL_UNIFORM_BUFFER, 0, ubo.handle);
OGLBuffer ssbo;
ssbo.Create();
glNamedBufferStorage(ssbo.handle, sizeof(GLuint), nullptr, GL_CLIENT_STORAGE_BIT);
for (GLuint index = 4; index < 8; ++index) {
glInvalidateBufferData(ssbo.handle);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ssbo.handle);
glProgramUniform1ui(shader, 0, index);
glDrawArrays(GL_POINTS, 0, 1);
GLuint result;
glGetNamedBufferSubData(ssbo.handle, 0, sizeof(result), &result);
if (result != values.at(index)) {
LOG_INFO(Render_OpenGL, log_message, true);
return true;
}
}
LOG_INFO(Render_OpenGL, log_message, false);
return false;
}
} // namespace OpenGL
@@ -30,13 +30,19 @@ public:
return has_variable_aoffi;
}
bool HasComponentIndexingBug() const {
return has_component_indexing_bug;
}
private:
static bool TestVariableAoffi();
static bool TestComponentIndexingBug();
std::size_t uniform_buffer_alignment{};
u32 max_vertex_attributes{};
u32 max_varyings{};
bool has_variable_aoffi{};
bool has_component_indexing_bug{};
};
} // namespace OpenGL
@@ -35,8 +35,8 @@ struct UnspecializedShader {
namespace {
/// Gets the address for the specified shader stage program
GPUVAddr GetShaderAddress(Maxwell::ShaderProgram program) {
const auto& gpu{Core::System::GetInstance().GPU().Maxwell3D()};
GPUVAddr GetShaderAddress(Core::System& system, Maxwell::ShaderProgram program) {
const auto& gpu{system.GPU().Maxwell3D()};
const auto& shader_config{gpu.regs.shader_config[static_cast<std::size_t>(program)]};
return gpu.regs.code_address.CodeAddress() + shader_config.offset;
}
@@ -350,7 +350,8 @@ ShaderDiskCacheUsage CachedShader::GetUsage(GLenum primitive_mode,
ShaderCacheOpenGL::ShaderCacheOpenGL(RasterizerOpenGL& rasterizer, Core::System& system,
Core::Frontend::EmuWindow& emu_window, const Device& device)
: RasterizerCache{rasterizer}, emu_window{emu_window}, device{device}, disk_cache{system} {}
: RasterizerCache{rasterizer}, system{system}, emu_window{emu_window}, device{device},
disk_cache{system} {}
void ShaderCacheOpenGL::LoadDiskCache(const std::atomic_bool& stop_loading,
const VideoCore::DiskResourceLoadCallback& callback) {
@@ -546,42 +547,45 @@ std::unordered_map<u64, UnspecializedShader> ShaderCacheOpenGL::GenerateUnspecia
}
Shader ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program) {
if (!Core::System::GetInstance().GPU().Maxwell3D().dirty_flags.shaders) {
return last_shaders[static_cast<u32>(program)];
if (!system.GPU().Maxwell3D().dirty_flags.shaders) {
return last_shaders[static_cast<std::size_t>(program)];
}
auto& memory_manager{Core::System::GetInstance().GPU().MemoryManager()};
const GPUVAddr program_addr{GetShaderAddress(program)};
auto& memory_manager{system.GPU().MemoryManager()};
const GPUVAddr program_addr{GetShaderAddress(system, program)};
// Look up shader in the cache based on address
const auto& host_ptr{memory_manager.GetPointer(program_addr)};
const auto host_ptr{memory_manager.GetPointer(program_addr)};
Shader shader{TryGet(host_ptr)};
if (!shader) {
// No shader found - create a new one
ProgramCode program_code{GetShaderCode(memory_manager, program_addr, host_ptr)};
ProgramCode program_code_b;
if (program == Maxwell::ShaderProgram::VertexA) {
const GPUVAddr program_addr_b{GetShaderAddress(Maxwell::ShaderProgram::VertexB)};
program_code_b = GetShaderCode(memory_manager, program_addr_b,
memory_manager.GetPointer(program_addr_b));
}
const u64 unique_identifier = GetUniqueIdentifier(program, program_code, program_code_b);
const VAddr cpu_addr{*memory_manager.GpuToCpuAddress(program_addr)};
const auto found = precompiled_shaders.find(unique_identifier);
if (found != precompiled_shaders.end()) {
shader =
std::make_shared<CachedShader>(cpu_addr, unique_identifier, program, disk_cache,
precompiled_programs, found->second, host_ptr);
} else {
shader = std::make_shared<CachedShader>(
device, cpu_addr, unique_identifier, program, disk_cache, precompiled_programs,
std::move(program_code), std::move(program_code_b), host_ptr);
}
Register(shader);
if (shader) {
return last_shaders[static_cast<std::size_t>(program)] = shader;
}
return last_shaders[static_cast<u32>(program)] = shader;
// No shader found - create a new one
ProgramCode program_code{GetShaderCode(memory_manager, program_addr, host_ptr)};
ProgramCode program_code_b;
if (program == Maxwell::ShaderProgram::VertexA) {
const GPUVAddr program_addr_b{GetShaderAddress(system, Maxwell::ShaderProgram::VertexB)};
program_code_b = GetShaderCode(memory_manager, program_addr_b,
memory_manager.GetPointer(program_addr_b));
}
const u64 unique_identifier = GetUniqueIdentifier(program, program_code, program_code_b);
const VAddr cpu_addr{*memory_manager.GpuToCpuAddress(program_addr)};
const auto found = precompiled_shaders.find(unique_identifier);
if (found != precompiled_shaders.end()) {
// Create a shader from the cache
shader = std::make_shared<CachedShader>(cpu_addr, unique_identifier, program, disk_cache,
precompiled_programs, found->second, host_ptr);
} else {
// Create a shader from guest memory
shader = std::make_shared<CachedShader>(
device, cpu_addr, unique_identifier, program, disk_cache, precompiled_programs,
std::move(program_code), std::move(program_code_b), host_ptr);
}
Register(shader);
return last_shaders[static_cast<std::size_t>(program)] = shader;
}
} // namespace OpenGL
@@ -137,6 +137,7 @@ private:
CachedProgram GeneratePrecompiledProgram(const ShaderDiskCacheDump& dump,
const std::set<GLenum>& supported_formats);
Core::System& system;
Core::Frontend::EmuWindow& emu_window;
const Device& device;
ShaderDiskCacheOpenGL disk_cache;
@@ -577,9 +577,26 @@ private:
if (std::holds_alternative<OperationNode>(*offset)) {
// Indirect access
const std::string final_offset = code.GenerateTemporary();
code.AddLine("uint {} = (ftou({}) / 4);", final_offset, Visit(offset));
return fmt::format("{}[{} / 4][{} % 4]", GetConstBuffer(cbuf->GetIndex()),
final_offset, final_offset);
code.AddLine("uint {} = ftou({}) >> 2;", final_offset, Visit(offset));
if (!device.HasComponentIndexingBug()) {
return fmt::format("{}[{} >> 2][{} & 3]", GetConstBuffer(cbuf->GetIndex()),
final_offset, final_offset);
}
// AMD's proprietary GLSL compiler emits ill code for variable component access.
// To bypass this driver bug generate 4 ifs, one per each component.
const std::string pack = code.GenerateTemporary();
code.AddLine("vec4 {} = {}[{} >> 2];", pack, GetConstBuffer(cbuf->GetIndex()),
final_offset);
const std::string result = code.GenerateTemporary();
code.AddLine("float {};", result);
for (u32 swizzle = 0; swizzle < 4; ++swizzle) {
code.AddLine("if (({} & 3) == {}) {} = {}{};", final_offset, swizzle, result,
pack, GetSwizzle(swizzle));
}
return result;
}
UNREACHABLE_MSG("Unmanaged offset node type");
+1 -7
View File
@@ -122,21 +122,15 @@ QtProfileSelectionDialog::QtProfileSelectionDialog(QWidget* parent)
QtProfileSelectionDialog::~QtProfileSelectionDialog() = default;
void QtProfileSelectionDialog::accept() {
ok = true;
QDialog::accept();
}
void QtProfileSelectionDialog::reject() {
ok = false;
user_index = 0;
QDialog::reject();
}
bool QtProfileSelectionDialog::GetStatus() const {
return ok;
}
u32 QtProfileSelectionDialog::GetIndex() const {
int QtProfileSelectionDialog::GetIndex() const {
return user_index;
}
+3 -5
View File
@@ -30,15 +30,13 @@ public:
void accept() override;
void reject() override;
bool GetStatus() const;
u32 GetIndex() const;
int GetIndex() const;
private:
bool ok = false;
u32 user_index = 0;
void SelectUser(const QModelIndex& index);
int user_index = 0;
QVBoxLayout* layout;
QTreeView* tree_view;
QStandardItemModel* item_model;
-6
View File
@@ -104,13 +104,11 @@ QtSoftwareKeyboardDialog::QtSoftwareKeyboardDialog(
QtSoftwareKeyboardDialog::~QtSoftwareKeyboardDialog() = default;
void QtSoftwareKeyboardDialog::accept() {
ok = true;
text = line_edit->text().toStdU16String();
QDialog::accept();
}
void QtSoftwareKeyboardDialog::reject() {
ok = false;
text.clear();
QDialog::reject();
}
@@ -119,10 +117,6 @@ std::u16string QtSoftwareKeyboardDialog::GetText() const {
return text;
}
bool QtSoftwareKeyboardDialog::GetStatus() const {
return ok;
}
QtSoftwareKeyboard::QtSoftwareKeyboard(GMainWindow& main_window) {
connect(this, &QtSoftwareKeyboard::MainWindowGetText, &main_window,
&GMainWindow::SoftwareKeyboardGetText, Qt::QueuedConnection);
-2
View File
@@ -36,10 +36,8 @@ public:
void reject() override;
std::u16string GetText() const;
bool GetStatus() const;
private:
bool ok = false;
std::u16string text;
QDialogButtonBox* buttons;
+33 -25
View File
@@ -26,6 +26,8 @@
EmuThread::EmuThread(GRenderWindow* render_window) : render_window(render_window) {}
EmuThread::~EmuThread() = default;
void EmuThread::run() {
render_window->MakeCurrent();
@@ -185,7 +187,7 @@ private:
bool do_painting;
};
GRenderWindow::GRenderWindow(QWidget* parent, EmuThread* emu_thread)
GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread)
: QWidget(parent), emu_thread(emu_thread) {
setWindowTitle(QStringLiteral("yuzu %1 | %2-%3")
.arg(QString::fromUtf8(Common::g_build_name),
@@ -194,8 +196,7 @@ GRenderWindow::GRenderWindow(QWidget* parent, EmuThread* emu_thread)
setAttribute(Qt::WA_AcceptTouchEvents);
InputCommon::Init();
connect(this, &GRenderWindow::FirstFrameDisplayed, static_cast<GMainWindow*>(parent),
&GMainWindow::OnLoadComplete);
connect(this, &GRenderWindow::FirstFrameDisplayed, parent, &GMainWindow::OnLoadComplete);
}
GRenderWindow::~GRenderWindow() {
@@ -247,9 +248,9 @@ void GRenderWindow::PollEvents() {}
void GRenderWindow::OnFramebufferSizeChanged() {
// Screen changes potentially incur a change in screen DPI, hence we should update the
// framebuffer size
qreal pixelRatio = GetWindowPixelRatio();
unsigned width = child->QPaintDevice::width() * pixelRatio;
unsigned height = child->QPaintDevice::height() * pixelRatio;
const qreal pixel_ratio = GetWindowPixelRatio();
const u32 width = child->QPaintDevice::width() * pixel_ratio;
const u32 height = child->QPaintDevice::height() * pixel_ratio;
UpdateCurrentFramebufferLayout(width, height);
}
@@ -266,7 +267,7 @@ void GRenderWindow::ForwardKeyReleaseEvent(QKeyEvent* event) {
}
void GRenderWindow::BackupGeometry() {
geometry = ((QWidget*)this)->saveGeometry();
geometry = QWidget::saveGeometry();
}
void GRenderWindow::RestoreGeometry() {
@@ -283,10 +284,11 @@ void GRenderWindow::restoreGeometry(const QByteArray& geometry) {
QByteArray GRenderWindow::saveGeometry() {
// If we are a top-level widget, store the current geometry
// otherwise, store the last backup
if (parent() == nullptr)
return ((QWidget*)this)->saveGeometry();
else
return geometry;
if (parent() == nullptr) {
return QWidget::saveGeometry();
}
return geometry;
}
qreal GRenderWindow::GetWindowPixelRatio() const {
@@ -294,10 +296,10 @@ qreal GRenderWindow::GetWindowPixelRatio() const {
return windowHandle() ? windowHandle()->screen()->devicePixelRatio() : 1.0f;
}
std::pair<unsigned, unsigned> GRenderWindow::ScaleTouch(const QPointF pos) const {
std::pair<u32, u32> GRenderWindow::ScaleTouch(const QPointF pos) const {
const qreal pixel_ratio = GetWindowPixelRatio();
return {static_cast<unsigned>(std::max(std::round(pos.x() * pixel_ratio), qreal{0.0})),
static_cast<unsigned>(std::max(std::round(pos.y() * pixel_ratio), qreal{0.0}))};
return {static_cast<u32>(std::max(std::round(pos.x() * pixel_ratio), qreal{0.0})),
static_cast<u32>(std::max(std::round(pos.y() * pixel_ratio), qreal{0.0}))};
}
void GRenderWindow::closeEvent(QCloseEvent* event) {
@@ -353,7 +355,7 @@ void GRenderWindow::focusOutEvent(QFocusEvent* event) {
InputCommon::GetKeyboard()->ReleaseAllKeys();
}
void GRenderWindow::OnClientAreaResized(unsigned width, unsigned height) {
void GRenderWindow::OnClientAreaResized(u32 width, u32 height) {
NotifyClientAreaSizeChanged(std::make_pair(width, height));
}
@@ -394,7 +396,7 @@ void GRenderWindow::InitRenderTarget() {
context->setShareContext(shared_context.get());
context->setFormat(fmt);
context->create();
fmt.setSwapInterval(false);
fmt.setSwapInterval(0);
child = new GGLWidgetInternal(this, shared_context.get());
container = QWidget::createWindowContainer(child, this);
@@ -424,23 +426,29 @@ void GRenderWindow::InitRenderTarget() {
BackupGeometry();
}
void GRenderWindow::CaptureScreenshot(u16 res_scale, const QString& screenshot_path) {
void GRenderWindow::CaptureScreenshot(u32 res_scale, const QString& screenshot_path) {
auto& renderer = Core::System::GetInstance().Renderer();
if (!res_scale)
if (res_scale == 0) {
res_scale = VideoCore::GetResolutionScaleFactor(renderer);
}
const Layout::FramebufferLayout layout{Layout::FrameLayoutFromResolutionScale(res_scale)};
screenshot_image = QImage(QSize(layout.width, layout.height), QImage::Format_RGB32);
renderer.RequestScreenshot(screenshot_image.bits(),
[=] {
screenshot_image.mirrored(false, true).save(screenshot_path);
LOG_INFO(Frontend, "The screenshot is saved.");
},
layout);
renderer.RequestScreenshot(
screenshot_image.bits(),
[=] {
const std::string std_screenshot_path = screenshot_path.toStdString();
if (screenshot_image.mirrored(false, true).save(screenshot_path)) {
LOG_INFO(Frontend, "Screenshot saved to \"{}\"", std_screenshot_path);
} else {
LOG_ERROR(Frontend, "Failed to save screenshot to \"{}\"", std_screenshot_path);
}
},
layout);
}
void GRenderWindow::OnMinimalClientAreaChangeRequest(std::pair<unsigned, unsigned> minimal_size) {
void GRenderWindow::OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) {
setMinimumSize(minimal_size.first, minimal_size.second);
}
+7 -6
View File
@@ -27,11 +27,12 @@ namespace VideoCore {
enum class LoadCallbackStage;
}
class EmuThread : public QThread {
class EmuThread final : public QThread {
Q_OBJECT
public:
explicit EmuThread(GRenderWindow* render_window);
~EmuThread() override;
/**
* Start emulation (on new thread)
@@ -114,7 +115,7 @@ class GRenderWindow : public QWidget, public Core::Frontend::EmuWindow {
Q_OBJECT
public:
GRenderWindow(QWidget* parent, EmuThread* emu_thread);
GRenderWindow(GMainWindow* parent, EmuThread* emu_thread);
~GRenderWindow() override;
// EmuWindow implementation
@@ -133,17 +134,17 @@ public:
QByteArray saveGeometry(); // overridden
qreal GetWindowPixelRatio() const;
std::pair<unsigned, unsigned> ScaleTouch(const QPointF pos) const;
std::pair<u32, u32> ScaleTouch(QPointF pos) const;
void closeEvent(QCloseEvent* event) override;
bool event(QEvent* event) override;
void focusOutEvent(QFocusEvent* event) override;
void OnClientAreaResized(unsigned width, unsigned height);
void OnClientAreaResized(u32 width, u32 height);
void InitRenderTarget();
void CaptureScreenshot(u16 res_scale, const QString& screenshot_path);
void CaptureScreenshot(u32 res_scale, const QString& screenshot_path);
public slots:
void moveContext(); // overridden
@@ -162,7 +163,7 @@ private:
void TouchUpdateEvent(const QTouchEvent* event);
void TouchEndEvent();
void OnMinimalClientAreaChangeRequest(std::pair<unsigned, unsigned> minimal_size) override;
void OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) override;
QWidget* container = nullptr;
GGLWidgetInternal* child = nullptr;
+39 -22
View File
@@ -4,6 +4,8 @@
#include <memory>
#include <QSignalBlocker>
#include "audio_core/sink.h"
#include "audio_core/sink_details.h"
#include "core/core.h"
@@ -15,18 +17,14 @@ ConfigureAudio::ConfigureAudio(QWidget* parent)
: QWidget(parent), ui(std::make_unique<Ui::ConfigureAudio>()) {
ui->setupUi(this);
ui->output_sink_combo_box->clear();
ui->output_sink_combo_box->addItem(QString::fromUtf8(AudioCore::auto_device_name));
for (const char* id : AudioCore::GetSinkIDs()) {
ui->output_sink_combo_box->addItem(QString::fromUtf8(id));
}
InitializeAudioOutputSinkComboBox();
connect(ui->volume_slider, &QSlider::valueChanged, this,
&ConfigureAudio::setVolumeIndicatorText);
this->setConfiguration();
&ConfigureAudio::SetVolumeIndicatorText);
connect(ui->output_sink_combo_box, qOverload<int>(&QComboBox::currentIndexChanged), this,
&ConfigureAudio::updateAudioDevices);
&ConfigureAudio::UpdateAudioDevices);
SetConfiguration();
const bool is_powered_on = Core::System::GetInstance().IsPoweredOn();
ui->output_sink_combo_box->setEnabled(!is_powered_on);
@@ -35,22 +33,23 @@ ConfigureAudio::ConfigureAudio(QWidget* parent)
ConfigureAudio::~ConfigureAudio() = default;
void ConfigureAudio::setConfiguration() {
setOutputSinkFromSinkID();
void ConfigureAudio::SetConfiguration() {
SetOutputSinkFromSinkID();
// The device list cannot be pre-populated (nor listed) until the output sink is known.
updateAudioDevices(ui->output_sink_combo_box->currentIndex());
UpdateAudioDevices(ui->output_sink_combo_box->currentIndex());
setAudioDeviceFromDeviceID();
SetAudioDeviceFromDeviceID();
ui->toggle_audio_stretching->setChecked(Settings::values.enable_audio_stretching);
ui->volume_slider->setValue(Settings::values.volume * ui->volume_slider->maximum());
setVolumeIndicatorText(ui->volume_slider->sliderPosition());
SetVolumeIndicatorText(ui->volume_slider->sliderPosition());
}
void ConfigureAudio::setOutputSinkFromSinkID() {
int new_sink_index = 0;
void ConfigureAudio::SetOutputSinkFromSinkID() {
[[maybe_unused]] const QSignalBlocker blocker(ui->output_sink_combo_box);
int new_sink_index = 0;
const QString sink_id = QString::fromStdString(Settings::values.sink_id);
for (int index = 0; index < ui->output_sink_combo_box->count(); index++) {
if (ui->output_sink_combo_box->itemText(index) == sink_id) {
@@ -62,7 +61,7 @@ void ConfigureAudio::setOutputSinkFromSinkID() {
ui->output_sink_combo_box->setCurrentIndex(new_sink_index);
}
void ConfigureAudio::setAudioDeviceFromDeviceID() {
void ConfigureAudio::SetAudioDeviceFromDeviceID() {
int new_device_index = -1;
const QString device_id = QString::fromStdString(Settings::values.audio_device_id);
@@ -76,11 +75,11 @@ void ConfigureAudio::setAudioDeviceFromDeviceID() {
ui->audio_device_combo_box->setCurrentIndex(new_device_index);
}
void ConfigureAudio::setVolumeIndicatorText(int percentage) {
void ConfigureAudio::SetVolumeIndicatorText(int percentage) {
ui->volume_indicator->setText(tr("%1%", "Volume percentage (e.g. 50%)").arg(percentage));
}
void ConfigureAudio::applyConfiguration() {
void ConfigureAudio::ApplyConfiguration() {
Settings::values.sink_id =
ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex())
.toStdString();
@@ -92,7 +91,15 @@ void ConfigureAudio::applyConfiguration() {
static_cast<float>(ui->volume_slider->sliderPosition()) / ui->volume_slider->maximum();
}
void ConfigureAudio::updateAudioDevices(int sink_index) {
void ConfigureAudio::changeEvent(QEvent* event) {
if (event->type() == QEvent::LanguageChange) {
RetranslateUI();
}
QWidget::changeEvent(event);
}
void ConfigureAudio::UpdateAudioDevices(int sink_index) {
ui->audio_device_combo_box->clear();
ui->audio_device_combo_box->addItem(QString::fromUtf8(AudioCore::auto_device_name));
@@ -102,6 +109,16 @@ void ConfigureAudio::updateAudioDevices(int sink_index) {
}
}
void ConfigureAudio::retranslateUi() {
ui->retranslateUi(this);
void ConfigureAudio::InitializeAudioOutputSinkComboBox() {
ui->output_sink_combo_box->clear();
ui->output_sink_combo_box->addItem(QString::fromUtf8(AudioCore::auto_device_name));
for (const char* id : AudioCore::GetSinkIDs()) {
ui->output_sink_combo_box->addItem(QString::fromUtf8(id));
}
}
void ConfigureAudio::RetranslateUI() {
ui->retranslateUi(this);
SetVolumeIndicatorText(ui->volume_slider->sliderPosition());
}
+12 -7
View File
@@ -18,16 +18,21 @@ public:
explicit ConfigureAudio(QWidget* parent = nullptr);
~ConfigureAudio() override;
void applyConfiguration();
void retranslateUi();
void ApplyConfiguration();
private:
void updateAudioDevices(int sink_index);
void changeEvent(QEvent* event) override;
void setConfiguration();
void setOutputSinkFromSinkID();
void setAudioDeviceFromDeviceID();
void setVolumeIndicatorText(int percentage);
void InitializeAudioOutputSinkComboBox();
void RetranslateUI();
void UpdateAudioDevices(int sink_index);
void SetConfiguration();
void SetOutputSinkFromSinkID();
void SetAudioDeviceFromDeviceID();
void SetVolumeIndicatorText(int percentage);
std::unique_ptr<Ui::ConfigureAudio> ui;
};
+3 -3
View File
@@ -20,7 +20,7 @@
<item>
<layout class="QHBoxLayout">
<item>
<widget class="QLabel" name="label">
<widget class="QLabel" name="label_1">
<property name="text">
<string>Output Engine:</string>
</property>
@@ -44,7 +44,7 @@
<item>
<layout class="QHBoxLayout">
<item>
<widget class="QLabel" name="label">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Audio Device:</string>
</property>
@@ -61,7 +61,7 @@
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Volume:</string>
</property>
+16 -3
View File
@@ -16,7 +16,8 @@
ConfigureDebug::ConfigureDebug(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureDebug) {
ui->setupUi(this);
this->setConfiguration();
SetConfiguration();
connect(ui->open_log_button, &QPushButton::pressed, []() {
QString path = QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::LogDir));
QDesktopServices::openUrl(QUrl::fromLocalFile(path));
@@ -25,7 +26,7 @@ ConfigureDebug::ConfigureDebug(QWidget* parent) : QWidget(parent), ui(new Ui::Co
ConfigureDebug::~ConfigureDebug() = default;
void ConfigureDebug::setConfiguration() {
void ConfigureDebug::SetConfiguration() {
ui->toggle_gdbstub->setChecked(Settings::values.use_gdbstub);
ui->gdbport_spinbox->setEnabled(Settings::values.use_gdbstub);
ui->gdbport_spinbox->setValue(Settings::values.gdbstub_port);
@@ -37,7 +38,7 @@ void ConfigureDebug::setConfiguration() {
ui->dump_decompressed_nso->setChecked(Settings::values.dump_nso);
}
void ConfigureDebug::applyConfiguration() {
void ConfigureDebug::ApplyConfiguration() {
Settings::values.use_gdbstub = ui->toggle_gdbstub->isChecked();
Settings::values.gdbstub_port = ui->gdbport_spinbox->value();
UISettings::values.show_console = ui->toggle_console->isChecked();
@@ -50,3 +51,15 @@ void ConfigureDebug::applyConfiguration() {
filter.ParseFilterString(Settings::values.log_filter);
Log::SetGlobalFilter(filter);
}
void ConfigureDebug::changeEvent(QEvent* event) {
if (event->type() == QEvent::LanguageChange) {
RetranslateUI();
}
QWidget::changeEvent(event);
}
void ConfigureDebug::RetranslateUI() {
ui->retranslateUi(this);
}
+5 -2
View File
@@ -18,10 +18,13 @@ public:
explicit ConfigureDebug(QWidget* parent = nullptr);
~ConfigureDebug() override;
void applyConfiguration();
void ApplyConfiguration();
private:
void setConfiguration();
void changeEvent(QEvent* event) override;
void RetranslateUI();
void SetConfiguration();
std::unique_ptr<Ui::ConfigureDebug> ui;
};
+9 -9
View File
@@ -45,7 +45,7 @@
</spacer>
</item>
<item>
<widget class="QLabel" name="label_2">
<widget class="QLabel" name="label_1">
<property name="text">
<string>Port:</string>
</property>
@@ -70,11 +70,11 @@
<property name="title">
<string>Logging</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Global Log Filter</string>
</property>
@@ -86,7 +86,7 @@
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QCheckBox" name="toggle_console">
<property name="text">
@@ -111,11 +111,11 @@
<property name="title">
<string>Homebrew</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="label">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Arguments String</string>
</property>
@@ -134,7 +134,7 @@
<property name="title">
<string>Dump</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QCheckBox" name="dump_decompressed_nso">
<property name="whatsThis">
+60 -30
View File
@@ -4,6 +4,7 @@
#include <QHash>
#include <QListWidgetItem>
#include <QSignalBlocker>
#include "core/settings.h"
#include "ui_configure.h"
#include "yuzu/configuration/config.h"
@@ -15,11 +16,11 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry)
: QDialog(parent), ui(new Ui::ConfigureDialog), registry(registry) {
ui->setupUi(this);
ui->hotkeysTab->Populate(registry);
this->setConfiguration();
this->PopulateSelectionList();
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
SetConfiguration();
PopulateSelectionList();
connect(ui->selectorList, &QListWidget::itemSelectionChanged, this,
&ConfigureDialog::UpdateVisibleTabs);
@@ -29,30 +30,55 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry)
ConfigureDialog::~ConfigureDialog() = default;
void ConfigureDialog::setConfiguration() {}
void ConfigureDialog::SetConfiguration() {}
void ConfigureDialog::applyConfiguration() {
ui->generalTab->applyConfiguration();
ui->gameListTab->applyConfiguration();
ui->systemTab->applyConfiguration();
ui->profileManagerTab->applyConfiguration();
ui->inputTab->applyConfiguration();
ui->hotkeysTab->applyConfiguration(registry);
ui->graphicsTab->applyConfiguration();
ui->audioTab->applyConfiguration();
ui->debugTab->applyConfiguration();
ui->webTab->applyConfiguration();
void ConfigureDialog::ApplyConfiguration() {
ui->generalTab->ApplyConfiguration();
ui->gameListTab->ApplyConfiguration();
ui->systemTab->ApplyConfiguration();
ui->profileManagerTab->ApplyConfiguration();
ui->inputTab->ApplyConfiguration();
ui->hotkeysTab->ApplyConfiguration(registry);
ui->graphicsTab->ApplyConfiguration();
ui->audioTab->ApplyConfiguration();
ui->debugTab->ApplyConfiguration();
ui->webTab->ApplyConfiguration();
Settings::Apply();
Settings::LogSettings();
}
void ConfigureDialog::changeEvent(QEvent* event) {
if (event->type() == QEvent::LanguageChange) {
RetranslateUI();
}
QDialog::changeEvent(event);
}
void ConfigureDialog::RetranslateUI() {
const int old_row = ui->selectorList->currentRow();
const int old_index = ui->tabWidget->currentIndex();
ui->retranslateUi(this);
PopulateSelectionList();
ui->selectorList->setCurrentRow(old_row);
UpdateVisibleTabs();
ui->tabWidget->setCurrentIndex(old_index);
}
void ConfigureDialog::PopulateSelectionList() {
const std::array<std::pair<QString, QStringList>, 4> items{
{{tr("General"), {tr("General"), tr("Web"), tr("Debug"), tr("Game List")}},
{tr("System"), {tr("System"), tr("Profiles"), tr("Audio")}},
{tr("Graphics"), {tr("Graphics")}},
{tr("Controls"), {tr("Input"), tr("Hotkeys")}}}};
{tr("Controls"), {tr("Input"), tr("Hotkeys")}}},
};
[[maybe_unused]] const QSignalBlocker blocker(ui->selectorList);
ui->selectorList->clear();
for (const auto& entry : items) {
auto* const item = new QListWidgetItem(entry.first);
item->setData(Qt::UserRole, entry.second);
@@ -63,24 +89,28 @@ void ConfigureDialog::PopulateSelectionList() {
void ConfigureDialog::UpdateVisibleTabs() {
const auto items = ui->selectorList->selectedItems();
if (items.isEmpty())
if (items.isEmpty()) {
return;
}
const std::map<QString, QWidget*> widgets = {{tr("General"), ui->generalTab},
{tr("System"), ui->systemTab},
{tr("Profiles"), ui->profileManagerTab},
{tr("Input"), ui->inputTab},
{tr("Hotkeys"), ui->hotkeysTab},
{tr("Graphics"), ui->graphicsTab},
{tr("Audio"), ui->audioTab},
{tr("Debug"), ui->debugTab},
{tr("Web"), ui->webTab},
{tr("Game List"), ui->gameListTab}};
const std::map<QString, QWidget*> widgets = {
{tr("General"), ui->generalTab},
{tr("System"), ui->systemTab},
{tr("Profiles"), ui->profileManagerTab},
{tr("Input"), ui->inputTab},
{tr("Hotkeys"), ui->hotkeysTab},
{tr("Graphics"), ui->graphicsTab},
{tr("Audio"), ui->audioTab},
{tr("Debug"), ui->debugTab},
{tr("Web"), ui->webTab},
{tr("Game List"), ui->gameListTab},
};
[[maybe_unused]] const QSignalBlocker blocker(ui->tabWidget);
ui->tabWidget->clear();
const QStringList tabs = items[0]->data(Qt::UserRole).toStringList();
for (const auto& tab : tabs)
for (const auto& tab : tabs) {
ui->tabWidget->addTab(widgets.find(tab)->second, tab);
}
}
+6 -2
View File
@@ -20,10 +20,14 @@ public:
explicit ConfigureDialog(QWidget* parent, HotkeyRegistry& registry);
~ConfigureDialog() override;
void applyConfiguration();
void ApplyConfiguration();
private:
void setConfiguration();
void changeEvent(QEvent* event) override;
void RetranslateUI();
void SetConfiguration();
void UpdateVisibleTabs();
void PopulateSelectionList();
@@ -12,20 +12,20 @@
#include "yuzu/ui_settings.h"
namespace {
constexpr std::array<std::pair<u32, const char*>, 5> default_icon_sizes{{
constexpr std::array default_icon_sizes{
std::make_pair(0, QT_TR_NOOP("None")),
std::make_pair(32, QT_TR_NOOP("Small (32x32)")),
std::make_pair(64, QT_TR_NOOP("Standard (64x64)")),
std::make_pair(128, QT_TR_NOOP("Large (128x128)")),
std::make_pair(256, QT_TR_NOOP("Full Size (256x256)")),
}};
};
constexpr std::array<const char*, 4> row_text_names{{
constexpr std::array row_text_names{
QT_TR_NOOP("Filename"),
QT_TR_NOOP("Filetype"),
QT_TR_NOOP("Title ID"),
QT_TR_NOOP("Title Name"),
}};
};
} // Anonymous namespace
ConfigureGameList::ConfigureGameList(QWidget* parent)
@@ -35,7 +35,7 @@ ConfigureGameList::ConfigureGameList(QWidget* parent)
InitializeIconSizeComboBox();
InitializeRowComboBoxes();
this->setConfiguration();
SetConfiguration();
// Force game list reload if any of the relevant settings are changed.
connect(ui->show_unknown, &QCheckBox::stateChanged, this,
@@ -50,7 +50,7 @@ ConfigureGameList::ConfigureGameList(QWidget* parent)
ConfigureGameList::~ConfigureGameList() = default;
void ConfigureGameList::applyConfiguration() {
void ConfigureGameList::ApplyConfiguration() {
UISettings::values.show_unknown = ui->show_unknown->isChecked();
UISettings::values.show_add_ons = ui->show_add_ons->isChecked();
UISettings::values.icon_size = ui->icon_size_combobox->currentData().toUInt();
@@ -63,7 +63,7 @@ void ConfigureGameList::RequestGameListUpdate() {
UISettings::values.is_game_list_reload_pending.exchange(true);
}
void ConfigureGameList::setConfiguration() {
void ConfigureGameList::SetConfiguration() {
ui->show_unknown->setChecked(UISettings::values.show_unknown);
ui->show_add_ons->setChecked(UISettings::values.show_add_ons);
ui->icon_size_combobox->setCurrentIndex(
@@ -77,7 +77,6 @@ void ConfigureGameList::setConfiguration() {
void ConfigureGameList::changeEvent(QEvent* event) {
if (event->type() == QEvent::LanguageChange) {
RetranslateUI();
return;
}
QWidget::changeEvent(event);
+2 -2
View File
@@ -18,12 +18,12 @@ public:
explicit ConfigureGameList(QWidget* parent = nullptr);
~ConfigureGameList() override;
void applyConfiguration();
void ApplyConfiguration();
private:
void RequestGameListUpdate();
void setConfiguration();
void SetConfiguration();
void changeEvent(QEvent*) override;
void RetranslateUI();
+15 -3
View File
@@ -18,7 +18,7 @@ ConfigureGeneral::ConfigureGeneral(QWidget* parent)
QString::fromUtf8(theme.second));
}
this->setConfiguration();
SetConfiguration();
connect(ui->toggle_deepscan, &QCheckBox::stateChanged, this,
[] { UISettings::values.is_game_list_reload_pending.exchange(true); });
@@ -28,7 +28,7 @@ ConfigureGeneral::ConfigureGeneral(QWidget* parent)
ConfigureGeneral::~ConfigureGeneral() = default;
void ConfigureGeneral::setConfiguration() {
void ConfigureGeneral::SetConfiguration() {
ui->toggle_deepscan->setChecked(UISettings::values.game_directory_deepscan);
ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing);
ui->toggle_user_on_boot->setChecked(UISettings::values.select_user_on_boot);
@@ -36,7 +36,7 @@ void ConfigureGeneral::setConfiguration() {
ui->use_cpu_jit->setChecked(Settings::values.use_cpu_jit);
}
void ConfigureGeneral::applyConfiguration() {
void ConfigureGeneral::ApplyConfiguration() {
UISettings::values.game_directory_deepscan = ui->toggle_deepscan->isChecked();
UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked();
UISettings::values.select_user_on_boot = ui->toggle_user_on_boot->isChecked();
@@ -45,3 +45,15 @@ void ConfigureGeneral::applyConfiguration() {
Settings::values.use_cpu_jit = ui->use_cpu_jit->isChecked();
}
void ConfigureGeneral::changeEvent(QEvent* event) {
if (event->type() == QEvent::LanguageChange) {
RetranslateUI();
}
QWidget::changeEvent(event);
}
void ConfigureGeneral::RetranslateUI() {
ui->retranslateUi(this);
}
+5 -2
View File
@@ -20,10 +20,13 @@ public:
explicit ConfigureGeneral(QWidget* parent = nullptr);
~ConfigureGeneral() override;
void applyConfiguration();
void ApplyConfiguration();
private:
void setConfiguration();
void changeEvent(QEvent* event) override;
void RetranslateUI();
void SetConfiguration();
std::unique_ptr<Ui::ConfigureGeneral> ui;
};
+20 -8
View File
@@ -51,29 +51,29 @@ Resolution FromResolutionFactor(float factor) {
ConfigureGraphics::ConfigureGraphics(QWidget* parent)
: QWidget(parent), ui(new Ui::ConfigureGraphics) {
ui->setupUi(this);
this->setConfiguration();
ui->frame_limit->setEnabled(Settings::values.use_frame_limit);
connect(ui->toggle_frame_limit, &QCheckBox::stateChanged, ui->frame_limit,
&QSpinBox::setEnabled);
SetConfiguration();
connect(ui->toggle_frame_limit, &QCheckBox::toggled, ui->frame_limit, &QSpinBox::setEnabled);
connect(ui->bg_button, &QPushButton::clicked, this, [this] {
const QColor new_bg_color = QColorDialog::getColor(bg_color);
if (!new_bg_color.isValid())
if (!new_bg_color.isValid()) {
return;
}
UpdateBackgroundColorButton(new_bg_color);
});
}
ConfigureGraphics::~ConfigureGraphics() = default;
void ConfigureGraphics::setConfiguration() {
void ConfigureGraphics::SetConfiguration() {
const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn();
ui->resolution_factor_combobox->setCurrentIndex(
static_cast<int>(FromResolutionFactor(Settings::values.resolution_factor)));
ui->toggle_frame_limit->setChecked(Settings::values.use_frame_limit);
ui->frame_limit->setEnabled(ui->toggle_frame_limit->isChecked());
ui->frame_limit->setValue(Settings::values.frame_limit);
ui->use_compatibility_profile->setEnabled(runtime_lock);
ui->use_compatibility_profile->setChecked(Settings::values.use_compatibility_profile);
@@ -88,7 +88,7 @@ void ConfigureGraphics::setConfiguration() {
Settings::values.bg_blue));
}
void ConfigureGraphics::applyConfiguration() {
void ConfigureGraphics::ApplyConfiguration() {
Settings::values.resolution_factor =
ToResolutionFactor(static_cast<Resolution>(ui->resolution_factor_combobox->currentIndex()));
Settings::values.use_frame_limit = ui->toggle_frame_limit->isChecked();
@@ -104,6 +104,18 @@ void ConfigureGraphics::applyConfiguration() {
Settings::values.bg_blue = static_cast<float>(bg_color.blueF());
}
void ConfigureGraphics::changeEvent(QEvent* event) {
if (event->type() == QEvent::LanguageChange) {
RetranslateUI();
}
QWidget::changeEvent(event);
}
void ConfigureGraphics::RetranslateUI() {
ui->retranslateUi(this);
}
void ConfigureGraphics::UpdateBackgroundColorButton(QColor color) {
bg_color = color;
+5 -2
View File
@@ -18,10 +18,13 @@ public:
explicit ConfigureGraphics(QWidget* parent = nullptr);
~ConfigureGraphics() override;
void applyConfiguration();
void ApplyConfiguration();
private:
void setConfiguration();
void changeEvent(QEvent* event) override;
void RetranslateUI();
void SetConfiguration();
void UpdateBackgroundColorButton(QColor color);
+17 -6
View File
@@ -17,7 +17,6 @@ ConfigureHotkeys::ConfigureHotkeys(QWidget* parent)
model = new QStandardItemModel(this);
model->setColumnCount(3);
model->setHorizontalHeaderLabels({tr("Action"), tr("Hotkey"), tr("Context")});
connect(ui->hotkey_list, &QTreeView::doubleClicked, this, &ConfigureHotkeys::Configure);
ui->hotkey_list->setModel(model);
@@ -27,6 +26,8 @@ ConfigureHotkeys::ConfigureHotkeys(QWidget* parent)
ui->hotkey_list->setColumnWidth(0, 200);
ui->hotkey_list->resizeColumnToContents(1);
RetranslateUI();
}
ConfigureHotkeys::~ConfigureHotkeys() = default;
@@ -49,6 +50,20 @@ void ConfigureHotkeys::Populate(const HotkeyRegistry& registry) {
ui->hotkey_list->expandAll();
}
void ConfigureHotkeys::changeEvent(QEvent* event) {
if (event->type() == QEvent::LanguageChange) {
RetranslateUI();
}
QWidget::changeEvent(event);
}
void ConfigureHotkeys::RetranslateUI() {
ui->retranslateUi(this);
model->setHorizontalHeaderLabels({tr("Action"), tr("Hotkey"), tr("Context")});
}
void ConfigureHotkeys::Configure(QModelIndex index) {
if (!index.parent().isValid()) {
return;
@@ -92,7 +107,7 @@ bool ConfigureHotkeys::IsUsedKey(QKeySequence key_sequence) const {
return false;
}
void ConfigureHotkeys::applyConfiguration(HotkeyRegistry& registry) {
void ConfigureHotkeys::ApplyConfiguration(HotkeyRegistry& registry) {
for (int key_id = 0; key_id < model->rowCount(); key_id++) {
const QStandardItem* parent = model->item(key_id, 0);
for (int key_column_id = 0; key_column_id < parent->rowCount(); key_column_id++) {
@@ -112,7 +127,3 @@ void ConfigureHotkeys::applyConfiguration(HotkeyRegistry& registry) {
registry.SaveHotkeys();
}
void ConfigureHotkeys::retranslateUi() {
ui->retranslateUi(this);
}
+4 -2
View File
@@ -21,8 +21,7 @@ public:
explicit ConfigureHotkeys(QWidget* parent = nullptr);
~ConfigureHotkeys() override;
void applyConfiguration(HotkeyRegistry& registry);
void retranslateUi();
void ApplyConfiguration(HotkeyRegistry& registry);
/**
* Populates the hotkey list widget using data from the provided registry.
@@ -32,6 +31,9 @@ public:
void Populate(const HotkeyRegistry& registry);
private:
void changeEvent(QEvent* event) override;
void RetranslateUI();
void Configure(QModelIndex index);
bool IsUsedKey(QKeySequence key_sequence) const;
+54 -28
View File
@@ -5,6 +5,7 @@
#include <algorithm>
#include <memory>
#include <QSignalBlocker>
#include <QTimer>
#include "configuration/configure_touchscreen_advanced.h"
@@ -50,12 +51,12 @@ void OnDockedModeChanged(bool last_state, bool new_state) {
namespace {
template <typename Dialog, typename... Args>
void CallConfigureDialog(ConfigureInput& parent, Args&&... args) {
parent.applyConfiguration();
parent.ApplyConfiguration();
Dialog dialog(&parent, std::forward<Args>(args)...);
const auto res = dialog.exec();
if (res == QDialog::Accepted) {
dialog.applyConfiguration();
dialog.ApplyConfiguration();
}
}
} // Anonymous namespace
@@ -74,29 +75,25 @@ ConfigureInput::ConfigureInput(QWidget* parent)
ui->player5_configure, ui->player6_configure, ui->player7_configure, ui->player8_configure,
};
for (auto* controller_box : players_controller) {
controller_box->addItems({tr("None"), tr("Pro Controller"), tr("Dual Joycons"),
tr("Single Right Joycon"), tr("Single Left Joycon")});
}
this->loadConfiguration();
updateUIEnabled();
RetranslateUI();
LoadConfiguration();
UpdateUIEnabled();
connect(ui->restore_defaults_button, &QPushButton::pressed, this,
&ConfigureInput::restoreDefaults);
&ConfigureInput::RestoreDefaults);
for (auto* enabled : players_controller) {
connect(enabled, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
&ConfigureInput::updateUIEnabled);
&ConfigureInput::UpdateUIEnabled);
}
connect(ui->use_docked_mode, &QCheckBox::stateChanged, this, &ConfigureInput::updateUIEnabled);
connect(ui->use_docked_mode, &QCheckBox::stateChanged, this, &ConfigureInput::UpdateUIEnabled);
connect(ui->handheld_connected, &QCheckBox::stateChanged, this,
&ConfigureInput::updateUIEnabled);
connect(ui->mouse_enabled, &QCheckBox::stateChanged, this, &ConfigureInput::updateUIEnabled);
connect(ui->keyboard_enabled, &QCheckBox::stateChanged, this, &ConfigureInput::updateUIEnabled);
connect(ui->debug_enabled, &QCheckBox::stateChanged, this, &ConfigureInput::updateUIEnabled);
&ConfigureInput::UpdateUIEnabled);
connect(ui->mouse_enabled, &QCheckBox::stateChanged, this, &ConfigureInput::UpdateUIEnabled);
connect(ui->keyboard_enabled, &QCheckBox::stateChanged, this, &ConfigureInput::UpdateUIEnabled);
connect(ui->debug_enabled, &QCheckBox::stateChanged, this, &ConfigureInput::UpdateUIEnabled);
connect(ui->touchscreen_enabled, &QCheckBox::stateChanged, this,
&ConfigureInput::updateUIEnabled);
&ConfigureInput::UpdateUIEnabled);
for (std::size_t i = 0; i < players_configure.size(); ++i) {
connect(players_configure[i], &QPushButton::pressed, this,
@@ -118,7 +115,7 @@ ConfigureInput::ConfigureInput(QWidget* parent)
ConfigureInput::~ConfigureInput() = default;
void ConfigureInput::applyConfiguration() {
void ConfigureInput::ApplyConfiguration() {
for (std::size_t i = 0; i < players_controller.size(); ++i) {
const auto controller_type_index = players_controller[i]->currentIndex();
@@ -144,7 +141,32 @@ void ConfigureInput::applyConfiguration() {
Settings::values.touchscreen.enabled = ui->touchscreen_enabled->isChecked();
}
void ConfigureInput::updateUIEnabled() {
void ConfigureInput::changeEvent(QEvent* event) {
if (event->type() == QEvent::LanguageChange) {
RetranslateUI();
}
QDialog::changeEvent(event);
}
void ConfigureInput::RetranslateUI() {
ui->retranslateUi(this);
RetranslateControllerComboBoxes();
}
void ConfigureInput::RetranslateControllerComboBoxes() {
for (auto* controller_box : players_controller) {
[[maybe_unused]] const QSignalBlocker blocker(controller_box);
controller_box->clear();
controller_box->addItems({tr("None"), tr("Pro Controller"), tr("Dual Joycons"),
tr("Single Right Joycon"), tr("Single Left Joycon")});
}
LoadPlayerControllerIndices();
}
void ConfigureInput::UpdateUIEnabled() {
bool hit_disabled = false;
for (auto* player : players_controller) {
player->setDisabled(hit_disabled);
@@ -168,18 +190,14 @@ void ConfigureInput::updateUIEnabled() {
ui->touchscreen_advanced->setEnabled(ui->touchscreen_enabled->isChecked());
}
void ConfigureInput::loadConfiguration() {
void ConfigureInput::LoadConfiguration() {
std::stable_partition(
Settings::values.players.begin(),
Settings::values.players.begin() +
Service::HID::Controller_NPad::NPadIdToIndex(Service::HID::NPAD_HANDHELD),
[](const auto& player) { return player.connected; });
for (std::size_t i = 0; i < players_controller.size(); ++i) {
const auto connected = Settings::values.players[i].connected;
players_controller[i]->setCurrentIndex(
connected ? static_cast<u8>(Settings::values.players[i].type) + 1 : 0);
}
LoadPlayerControllerIndices();
ui->use_docked_mode->setChecked(Settings::values.use_docked_mode);
ui->handheld_connected->setChecked(
@@ -191,10 +209,18 @@ void ConfigureInput::loadConfiguration() {
ui->keyboard_enabled->setChecked(Settings::values.keyboard_enabled);
ui->touchscreen_enabled->setChecked(Settings::values.touchscreen.enabled);
updateUIEnabled();
UpdateUIEnabled();
}
void ConfigureInput::restoreDefaults() {
void ConfigureInput::LoadPlayerControllerIndices() {
for (std::size_t i = 0; i < players_controller.size(); ++i) {
const auto connected = Settings::values.players[i].connected;
players_controller[i]->setCurrentIndex(
connected ? static_cast<u8>(Settings::values.players[i].type) + 1 : 0);
}
}
void ConfigureInput::RestoreDefaults() {
players_controller[0]->setCurrentIndex(2);
for (std::size_t i = 1; i < players_controller.size(); ++i) {
@@ -207,5 +233,5 @@ void ConfigureInput::restoreDefaults() {
ui->keyboard_enabled->setCheckState(Qt::Unchecked);
ui->debug_enabled->setCheckState(Qt::Unchecked);
ui->touchscreen_enabled->setCheckState(Qt::Checked);
updateUIEnabled();
UpdateUIEnabled();
}
+10 -4
View File
@@ -30,15 +30,21 @@ public:
~ConfigureInput() override;
/// Save all button configurations to settings file
void applyConfiguration();
void ApplyConfiguration();
private:
void updateUIEnabled();
void changeEvent(QEvent* event) override;
void RetranslateUI();
void RetranslateControllerComboBoxes();
void UpdateUIEnabled();
/// Load configuration settings.
void loadConfiguration();
void LoadConfiguration();
void LoadPlayerControllerIndices();
/// Restore all buttons to their default values.
void restoreDefaults();
void RestoreDefaults();
std::unique_ptr<Ui::ConfigureInput> ui;
+3 -3
View File
@@ -17,7 +17,7 @@
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="gridGroupBox">
<widget class="QGroupBox" name="gridGroupBox_1">
<property name="title">
<string>Players</string>
</property>
@@ -260,7 +260,7 @@
</widget>
</item>
<item>
<widget class="QGroupBox" name="gridGroupBox">
<widget class="QGroupBox" name="gridGroupBox_2">
<property name="title">
<string>Handheld</string>
</property>
@@ -332,7 +332,7 @@
</widget>
</item>
<item>
<widget class="QGroupBox" name="gridGroupBox">
<widget class="QGroupBox" name="gridGroupBox_3">
<property name="title">
<string>Other</string>
</property>
@@ -245,7 +245,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
button->setContextMenuPolicy(Qt::CustomContextMenu);
connect(button, &QPushButton::released, [=] {
handleClick(
HandleClick(
button_map[button_id],
[=](const Common::ParamPackage& params) { buttons_param[button_id] = params; },
InputCommon::Polling::DeviceType::Button);
@@ -274,7 +274,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
analog_button->setContextMenuPolicy(Qt::CustomContextMenu);
connect(analog_button, &QPushButton::released, [=]() {
handleClick(analog_map_buttons[analog_id][sub_button_id],
HandleClick(analog_map_buttons[analog_id][sub_button_id],
[=](const Common::ParamPackage& params) {
SetAnalogButton(params, analogs_param[analog_id],
analog_sub_buttons[sub_button_id]);
@@ -304,7 +304,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
QMessageBox::information(this, tr("Information"),
tr("After pressing OK, first move your joystick horizontally, "
"and then vertically."));
handleClick(
HandleClick(
analog_map_stick[analog_id],
[=](const Common::ParamPackage& params) { analogs_param[analog_id] = params; },
InputCommon::Polling::DeviceType::Analog);
@@ -312,17 +312,17 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
}
connect(ui->buttonClearAll, &QPushButton::released, [this] { ClearAll(); });
connect(ui->buttonRestoreDefaults, &QPushButton::released, [this]() { restoreDefaults(); });
connect(ui->buttonRestoreDefaults, &QPushButton::released, [this] { RestoreDefaults(); });
timeout_timer->setSingleShot(true);
connect(timeout_timer.get(), &QTimer::timeout, [this]() { setPollingResult({}, true); });
connect(timeout_timer.get(), &QTimer::timeout, [this] { SetPollingResult({}, true); });
connect(poll_timer.get(), &QTimer::timeout, [this]() {
connect(poll_timer.get(), &QTimer::timeout, [this] {
Common::ParamPackage params;
for (auto& poller : device_pollers) {
params = poller->GetNextInput();
if (params.Has("engine")) {
setPollingResult(params, false);
SetPollingResult(params, false);
return;
}
}
@@ -340,8 +340,8 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
[this, i] { OnControllerButtonClick(static_cast<int>(i)); });
}
this->loadConfiguration();
this->resize(0, 0);
LoadConfiguration();
resize(0, 0);
// TODO(wwylele): enable this when we actually emulate it
ui->buttonHome->setEnabled(false);
@@ -349,7 +349,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
ConfigureInputPlayer::~ConfigureInputPlayer() = default;
void ConfigureInputPlayer::applyConfiguration() {
void ConfigureInputPlayer::ApplyConfiguration() {
auto& buttons =
debug ? Settings::values.debug_pad_buttons : Settings::values.players[player_index].buttons;
auto& analogs =
@@ -373,6 +373,19 @@ void ConfigureInputPlayer::applyConfiguration() {
Settings::values.players[player_index].button_color_right = colors[3];
}
void ConfigureInputPlayer::changeEvent(QEvent* event) {
if (event->type() == QEvent::LanguageChange) {
RetranslateUI();
}
QDialog::changeEvent(event);
}
void ConfigureInputPlayer::RetranslateUI() {
ui->retranslateUi(this);
UpdateButtonLabels();
}
void ConfigureInputPlayer::OnControllerButtonClick(int i) {
const QColor new_bg_color = QColorDialog::getColor(controller_colors[i]);
if (!new_bg_color.isValid())
@@ -382,7 +395,7 @@ void ConfigureInputPlayer::OnControllerButtonClick(int i) {
QStringLiteral("QPushButton { background-color: %1 }").arg(controller_colors[i].name()));
}
void ConfigureInputPlayer::loadConfiguration() {
void ConfigureInputPlayer::LoadConfiguration() {
if (debug) {
std::transform(Settings::values.debug_pad_buttons.begin(),
Settings::values.debug_pad_buttons.end(), buttons_param.begin(),
@@ -399,7 +412,7 @@ void ConfigureInputPlayer::loadConfiguration() {
[](const std::string& str) { return Common::ParamPackage(str); });
}
updateButtonLabels();
UpdateButtonLabels();
if (debug)
return;
@@ -421,7 +434,7 @@ void ConfigureInputPlayer::loadConfiguration() {
}
}
void ConfigureInputPlayer::restoreDefaults() {
void ConfigureInputPlayer::RestoreDefaults() {
for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) {
buttons_param[button_id] = Common::ParamPackage{
InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])};
@@ -434,7 +447,7 @@ void ConfigureInputPlayer::restoreDefaults() {
SetAnalogButton(params, analogs_param[analog_id], analog_sub_buttons[sub_button_id]);
}
}
updateButtonLabels();
UpdateButtonLabels();
}
void ConfigureInputPlayer::ClearAll() {
@@ -458,10 +471,10 @@ void ConfigureInputPlayer::ClearAll() {
}
}
updateButtonLabels();
UpdateButtonLabels();
}
void ConfigureInputPlayer::updateButtonLabels() {
void ConfigureInputPlayer::UpdateButtonLabels() {
for (int button = 0; button < Settings::NativeButton::NumButtons; button++) {
button_map[button]->setText(ButtonToText(buttons_param[button]));
}
@@ -481,7 +494,7 @@ void ConfigureInputPlayer::updateButtonLabels() {
}
}
void ConfigureInputPlayer::handleClick(
void ConfigureInputPlayer::HandleClick(
QPushButton* button, std::function<void(const Common::ParamPackage&)> new_input_setter,
InputCommon::Polling::DeviceType type) {
button->setText(tr("[press key]"));
@@ -509,7 +522,7 @@ void ConfigureInputPlayer::handleClick(
poll_timer->start(200); // Check for new inputs every 200ms
}
void ConfigureInputPlayer::setPollingResult(const Common::ParamPackage& params, bool abort) {
void ConfigureInputPlayer::SetPollingResult(const Common::ParamPackage& params, bool abort) {
releaseKeyboard();
releaseMouse();
timeout_timer->stop();
@@ -522,22 +535,23 @@ void ConfigureInputPlayer::setPollingResult(const Common::ParamPackage& params,
(*input_setter)(params);
}
updateButtonLabels();
UpdateButtonLabels();
input_setter = std::nullopt;
}
void ConfigureInputPlayer::keyPressEvent(QKeyEvent* event) {
if (!input_setter || !event)
if (!input_setter || !event) {
return;
}
if (event->key() != Qt::Key_Escape) {
if (want_keyboard_keys) {
setPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->key())},
SetPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->key())},
false);
} else {
// Escape key wasn't pressed and we don't want any keyboard keys, so don't stop polling
return;
}
}
setPollingResult({}, true);
SetPollingResult({}, true);
}
@@ -38,28 +38,31 @@ public:
~ConfigureInputPlayer() override;
/// Save all button configurations to settings file
void applyConfiguration();
void ApplyConfiguration();
private:
void changeEvent(QEvent* event) override;
void RetranslateUI();
void OnControllerButtonClick(int i);
/// Load configuration settings.
void loadConfiguration();
void LoadConfiguration();
/// Restore all buttons to their default values.
void restoreDefaults();
void RestoreDefaults();
/// Clear all input configuration
void ClearAll();
/// Update UI to reflect current configuration.
void updateButtonLabels();
void UpdateButtonLabels();
/// Called when the button was pressed.
void handleClick(QPushButton* button,
void HandleClick(QPushButton* button,
std::function<void(const Common::ParamPackage&)> new_input_setter,
InputCommon::Polling::DeviceType type);
/// Finish polling and configure input using the input_setter
void setPollingResult(const Common::ParamPackage& params, bool abort);
void SetPollingResult(const Common::ParamPackage& params, bool abort);
/// Handle key press events.
void keyPressEvent(QKeyEvent* event) override;
@@ -15,12 +15,12 @@ namespace {
template <typename Dialog, typename... Args>
void CallConfigureDialog(ConfigureInputSimple* caller, Args&&... args) {
caller->applyConfiguration();
caller->ApplyConfiguration();
Dialog dialog(caller, std::forward<Args>(args)...);
const auto res = dialog.exec();
if (res == QDialog::Accepted) {
dialog.applyConfiguration();
dialog.ApplyConfiguration();
}
}
@@ -103,27 +103,41 @@ ConfigureInputSimple::ConfigureInputSimple(QWidget* parent)
&ConfigureInputSimple::OnSelectProfile);
connect(ui->profile_configure, &QPushButton::pressed, this, &ConfigureInputSimple::OnConfigure);
this->loadConfiguration();
LoadConfiguration();
}
ConfigureInputSimple::~ConfigureInputSimple() = default;
void ConfigureInputSimple::applyConfiguration() {
void ConfigureInputSimple::ApplyConfiguration() {
auto index = ui->profile_combobox->currentIndex();
// Make the stored index for "Custom" very large so that if new profiles are added it
// doesn't change.
if (index >= static_cast<int>(INPUT_PROFILES.size() - 1))
if (index >= static_cast<int>(INPUT_PROFILES.size() - 1)) {
index = std::numeric_limits<int>::max();
}
UISettings::values.profile_index = index;
}
void ConfigureInputSimple::loadConfiguration() {
void ConfigureInputSimple::changeEvent(QEvent* event) {
if (event->type() == QEvent::LanguageChange) {
RetranslateUI();
}
QWidget::changeEvent(event);
}
void ConfigureInputSimple::RetranslateUI() {
ui->retranslateUi(this);
}
void ConfigureInputSimple::LoadConfiguration() {
const auto index = UISettings::values.profile_index;
if (index >= static_cast<int>(INPUT_PROFILES.size()) || index < 0)
if (index >= static_cast<int>(INPUT_PROFILES.size()) || index < 0) {
ui->profile_combobox->setCurrentIndex(static_cast<int>(INPUT_PROFILES.size() - 1));
else
} else {
ui->profile_combobox->setCurrentIndex(index);
}
}
void ConfigureInputSimple::OnSelectProfile(int index) {
@@ -27,11 +27,14 @@ public:
~ConfigureInputSimple() override;
/// Save all button configurations to settings file
void applyConfiguration();
void ApplyConfiguration();
private:
void changeEvent(QEvent* event) override;
void RetranslateUI();
/// Load configuration settings.
void loadConfiguration();
void LoadConfiguration();
void OnSelectProfile(int index);
void OnConfigure();
@@ -84,7 +84,7 @@ ConfigureMouseAdvanced::ConfigureMouseAdvanced(QWidget* parent)
button->setContextMenuPolicy(Qt::CustomContextMenu);
connect(button, &QPushButton::released, [=] {
handleClick(
HandleClick(
button_map[button_id],
[=](const Common::ParamPackage& params) { buttons_param[button_id] = params; },
InputCommon::Polling::DeviceType::Button);
@@ -105,48 +105,60 @@ ConfigureMouseAdvanced::ConfigureMouseAdvanced(QWidget* parent)
}
connect(ui->buttonClearAll, &QPushButton::released, [this] { ClearAll(); });
connect(ui->buttonRestoreDefaults, &QPushButton::released, [this]() { restoreDefaults(); });
connect(ui->buttonRestoreDefaults, &QPushButton::released, [this] { RestoreDefaults(); });
timeout_timer->setSingleShot(true);
connect(timeout_timer.get(), &QTimer::timeout, [this]() { setPollingResult({}, true); });
connect(timeout_timer.get(), &QTimer::timeout, [this] { SetPollingResult({}, true); });
connect(poll_timer.get(), &QTimer::timeout, [this]() {
connect(poll_timer.get(), &QTimer::timeout, [this] {
Common::ParamPackage params;
for (auto& poller : device_pollers) {
params = poller->GetNextInput();
if (params.Has("engine")) {
setPollingResult(params, false);
SetPollingResult(params, false);
return;
}
}
});
loadConfiguration();
LoadConfiguration();
resize(0, 0);
}
ConfigureMouseAdvanced::~ConfigureMouseAdvanced() = default;
void ConfigureMouseAdvanced::applyConfiguration() {
void ConfigureMouseAdvanced::ApplyConfiguration() {
std::transform(buttons_param.begin(), buttons_param.end(),
Settings::values.mouse_buttons.begin(),
[](const Common::ParamPackage& param) { return param.Serialize(); });
}
void ConfigureMouseAdvanced::loadConfiguration() {
void ConfigureMouseAdvanced::LoadConfiguration() {
std::transform(Settings::values.mouse_buttons.begin(), Settings::values.mouse_buttons.end(),
buttons_param.begin(),
[](const std::string& str) { return Common::ParamPackage(str); });
updateButtonLabels();
UpdateButtonLabels();
}
void ConfigureMouseAdvanced::restoreDefaults() {
void ConfigureMouseAdvanced::changeEvent(QEvent* event) {
if (event->type() == QEvent::LanguageChange) {
RetranslateUI();
}
QDialog::changeEvent(event);
}
void ConfigureMouseAdvanced::RetranslateUI() {
ui->retranslateUi(this);
}
void ConfigureMouseAdvanced::RestoreDefaults() {
for (int button_id = 0; button_id < Settings::NativeMouseButton::NumMouseButtons; button_id++) {
buttons_param[button_id] = Common::ParamPackage{
InputCommon::GenerateKeyboardParam(Config::default_mouse_buttons[button_id])};
}
updateButtonLabels();
UpdateButtonLabels();
}
void ConfigureMouseAdvanced::ClearAll() {
@@ -157,16 +169,16 @@ void ConfigureMouseAdvanced::ClearAll() {
}
}
updateButtonLabels();
UpdateButtonLabels();
}
void ConfigureMouseAdvanced::updateButtonLabels() {
void ConfigureMouseAdvanced::UpdateButtonLabels() {
for (int button = 0; button < Settings::NativeMouseButton::NumMouseButtons; button++) {
button_map[button]->setText(ButtonToText(buttons_param[button]));
}
}
void ConfigureMouseAdvanced::handleClick(
void ConfigureMouseAdvanced::HandleClick(
QPushButton* button, std::function<void(const Common::ParamPackage&)> new_input_setter,
InputCommon::Polling::DeviceType type) {
button->setText(tr("[press key]"));
@@ -194,7 +206,7 @@ void ConfigureMouseAdvanced::handleClick(
poll_timer->start(200); // Check for new inputs every 200ms
}
void ConfigureMouseAdvanced::setPollingResult(const Common::ParamPackage& params, bool abort) {
void ConfigureMouseAdvanced::SetPollingResult(const Common::ParamPackage& params, bool abort) {
releaseKeyboard();
releaseMouse();
timeout_timer->stop();
@@ -207,22 +219,23 @@ void ConfigureMouseAdvanced::setPollingResult(const Common::ParamPackage& params
(*input_setter)(params);
}
updateButtonLabels();
UpdateButtonLabels();
input_setter = std::nullopt;
}
void ConfigureMouseAdvanced::keyPressEvent(QKeyEvent* event) {
if (!input_setter || !event)
if (!input_setter || !event) {
return;
}
if (event->key() != Qt::Key_Escape) {
if (want_keyboard_keys) {
setPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->key())},
SetPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->key())},
false);
} else {
// Escape key wasn't pressed and we don't want any keyboard keys, so don't stop polling
return;
}
}
setPollingResult({}, true);
SetPollingResult({}, true);
}
@@ -25,26 +25,29 @@ public:
explicit ConfigureMouseAdvanced(QWidget* parent);
~ConfigureMouseAdvanced() override;
void applyConfiguration();
void ApplyConfiguration();
private:
void changeEvent(QEvent* event) override;
void RetranslateUI();
/// Load configuration settings.
void loadConfiguration();
void LoadConfiguration();
/// Restore all buttons to their default values.
void restoreDefaults();
void RestoreDefaults();
/// Clear all input configuration
void ClearAll();
/// Update UI to reflect current configuration.
void updateButtonLabels();
void UpdateButtonLabels();
/// Called when the button was pressed.
void handleClick(QPushButton* button,
void HandleClick(QPushButton* button,
std::function<void(const Common::ParamPackage&)> new_input_setter,
InputCommon::Polling::DeviceType type);
/// Finish polling and configure input using the input_setter
void setPollingResult(const Common::ParamPackage& params, bool abort);
void SetPollingResult(const Common::ParamPackage& params, bool abort);
/// Handle key press events.
void keyPressEvent(QKeyEvent* event) override;
@@ -67,12 +67,12 @@ ConfigurePerGameGeneral::ConfigurePerGameGeneral(QWidget* parent, u64 title_id)
connect(item_model, &QStandardItemModel::itemChanged,
[] { UISettings::values.is_game_list_reload_pending.exchange(true); });
this->loadConfiguration();
LoadConfiguration();
}
ConfigurePerGameGeneral::~ConfigurePerGameGeneral() = default;
void ConfigurePerGameGeneral::applyConfiguration() {
void ConfigurePerGameGeneral::ApplyConfiguration() {
std::vector<std::string> disabled_addons;
for (const auto& item : list_items) {
@@ -92,12 +92,24 @@ void ConfigurePerGameGeneral::applyConfiguration() {
Settings::values.disabled_addons[title_id] = disabled_addons;
}
void ConfigurePerGameGeneral::loadFromFile(FileSys::VirtualFile file) {
this->file = std::move(file);
this->loadConfiguration();
void ConfigurePerGameGeneral::changeEvent(QEvent* event) {
if (event->type() == QEvent::LanguageChange) {
RetranslateUI();
}
QDialog::changeEvent(event);
}
void ConfigurePerGameGeneral::loadConfiguration() {
void ConfigurePerGameGeneral::RetranslateUI() {
ui->retranslateUi(this);
}
void ConfigurePerGameGeneral::LoadFromFile(FileSys::VirtualFile file) {
this->file = std::move(file);
LoadConfiguration();
}
void ConfigurePerGameGeneral::LoadConfiguration() {
if (file == nullptr) {
return;
}
@@ -30,11 +30,16 @@ public:
~ConfigurePerGameGeneral() override;
/// Save all button configurations to settings file
void applyConfiguration();
void ApplyConfiguration();
void loadFromFile(FileSys::VirtualFile file);
void LoadFromFile(FileSys::VirtualFile file);
private:
void changeEvent(QEvent* event) override;
void RetranslateUI();
void LoadConfiguration();
std::unique_ptr<Ui::ConfigurePerGameGeneral> ui;
FileSys::VirtualFile file;
u64 title_id;
@@ -45,6 +50,4 @@ private:
QGraphicsScene* scene;
std::vector<QList<QStandardItem*>> list_items;
void loadConfiguration();
};
@@ -80,11 +80,10 @@ ConfigureProfileManager ::ConfigureProfileManager(QWidget* parent)
profile_manager(std::make_unique<Service::Account::ProfileManager>()) {
ui->setupUi(this);
layout = new QVBoxLayout;
tree_view = new QTreeView;
item_model = new QStandardItemModel(tree_view);
item_model->insertColumns(0, 1);
tree_view->setModel(item_model);
tree_view->setAlternatingRowColors(true);
tree_view->setSelectionMode(QHeaderView::SingleSelection);
tree_view->setSelectionBehavior(QHeaderView::SelectRows);
@@ -96,13 +95,11 @@ ConfigureProfileManager ::ConfigureProfileManager(QWidget* parent)
tree_view->setIconSize({64, 64});
tree_view->setContextMenuPolicy(Qt::NoContextMenu);
item_model->insertColumns(0, 1);
item_model->setHeaderData(0, Qt::Horizontal, tr("Users"));
// We must register all custom types with the Qt Automoc system so that we are able to use it
// with signals/slots. In this case, QList falls under the umbrells of custom types.
qRegisterMetaType<QList<QStandardItem*>>("QList<QStandardItem*>");
layout = new QVBoxLayout;
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(0);
layout->addWidget(tree_view);
@@ -119,12 +116,26 @@ ConfigureProfileManager ::ConfigureProfileManager(QWidget* parent)
scene = new QGraphicsScene;
ui->current_user_icon->setScene(scene);
this->setConfiguration();
SetConfiguration();
RetranslateUI();
}
ConfigureProfileManager::~ConfigureProfileManager() = default;
void ConfigureProfileManager::setConfiguration() {
void ConfigureProfileManager::changeEvent(QEvent* event) {
if (event->type() == QEvent::LanguageChange) {
RetranslateUI();
}
QWidget::changeEvent(event);
}
void ConfigureProfileManager::RetranslateUI() {
ui->retranslateUi(this);
item_model->setHeaderData(0, Qt::Horizontal, tr("Users"));
}
void ConfigureProfileManager::SetConfiguration() {
enabled = !Core::System::GetInstance().IsPoweredOn();
item_model->removeRows(0, item_model->rowCount());
list_items.clear();
@@ -164,9 +175,10 @@ void ConfigureProfileManager::UpdateCurrentUser() {
ui->current_user_username->setText(username);
}
void ConfigureProfileManager::applyConfiguration() {
if (!enabled)
void ConfigureProfileManager::ApplyConfiguration() {
if (!enabled) {
return;
}
Settings::Apply();
}
@@ -30,10 +30,14 @@ public:
explicit ConfigureProfileManager(QWidget* parent = nullptr);
~ConfigureProfileManager() override;
void applyConfiguration();
void setConfiguration();
void ApplyConfiguration();
private:
void changeEvent(QEvent* event) override;
void RetranslateUI();
void SetConfiguration();
void PopulateUserList();
void UpdateCurrentUser();
+30 -11
View File
@@ -23,22 +23,36 @@ ConfigureSystem::ConfigureSystem(QWidget* parent) : QWidget(parent), ui(new Ui::
connect(ui->rng_seed_checkbox, &QCheckBox::stateChanged, this, [this](bool checked) {
ui->rng_seed_edit->setEnabled(checked);
if (!checked)
if (!checked) {
ui->rng_seed_edit->setText(QStringLiteral("00000000"));
}
});
connect(ui->custom_rtc_checkbox, &QCheckBox::stateChanged, this, [this](bool checked) {
ui->custom_rtc_edit->setEnabled(checked);
if (!checked)
if (!checked) {
ui->custom_rtc_edit->setDateTime(QDateTime::currentDateTime());
}
});
this->setConfiguration();
SetConfiguration();
}
ConfigureSystem::~ConfigureSystem() = default;
void ConfigureSystem::setConfiguration() {
void ConfigureSystem::changeEvent(QEvent* event) {
if (event->type() == QEvent::LanguageChange) {
RetranslateUI();
}
QWidget::changeEvent(event);
}
void ConfigureSystem::RetranslateUI() {
ui->retranslateUi(this);
}
void ConfigureSystem::SetConfiguration() {
enabled = !Core::System::GetInstance().IsPoweredOn();
ui->combo_language->setCurrentIndex(Settings::values.language_index);
@@ -61,22 +75,25 @@ void ConfigureSystem::setConfiguration() {
void ConfigureSystem::ReadSystemSettings() {}
void ConfigureSystem::applyConfiguration() {
if (!enabled)
void ConfigureSystem::ApplyConfiguration() {
if (!enabled) {
return;
}
Settings::values.language_index = ui->combo_language->currentIndex();
if (ui->rng_seed_checkbox->isChecked())
if (ui->rng_seed_checkbox->isChecked()) {
Settings::values.rng_seed = ui->rng_seed_edit->text().toULongLong(nullptr, 16);
else
} else {
Settings::values.rng_seed = std::nullopt;
}
if (ui->custom_rtc_checkbox->isChecked())
if (ui->custom_rtc_checkbox->isChecked()) {
Settings::values.custom_rtc =
std::chrono::seconds(ui->custom_rtc_edit->dateTime().toSecsSinceEpoch());
else
} else {
Settings::values.custom_rtc = std::nullopt;
}
Settings::Apply();
}
@@ -89,8 +106,10 @@ void ConfigureSystem::RefreshConsoleID() {
"if you use an outdated config savegame. Continue?");
reply = QMessageBox::critical(this, tr("Warning"), warning_text,
QMessageBox::No | QMessageBox::Yes);
if (reply == QMessageBox::No)
if (reply == QMessageBox::No) {
return;
}
u64 console_id{};
ui->label_console_id->setText(
tr("Console ID: 0x%1").arg(QString::number(console_id, 16).toUpper()));
+6 -2
View File
@@ -20,10 +20,14 @@ public:
explicit ConfigureSystem(QWidget* parent = nullptr);
~ConfigureSystem() override;
void applyConfiguration();
void setConfiguration();
void ApplyConfiguration();
private:
void changeEvent(QEvent* event) override;
void RetranslateUI();
void SetConfiguration();
void ReadSystemSettings();
void RefreshConsoleID();
@@ -12,29 +12,41 @@ ConfigureTouchscreenAdvanced::ConfigureTouchscreenAdvanced(QWidget* parent)
ui->setupUi(this);
connect(ui->restore_defaults_button, &QPushButton::pressed, this,
&ConfigureTouchscreenAdvanced::restoreDefaults);
&ConfigureTouchscreenAdvanced::RestoreDefaults);
loadConfiguration();
LoadConfiguration();
resize(0, 0);
}
ConfigureTouchscreenAdvanced::~ConfigureTouchscreenAdvanced() = default;
void ConfigureTouchscreenAdvanced::applyConfiguration() {
void ConfigureTouchscreenAdvanced::changeEvent(QEvent* event) {
if (event->type() == QEvent::LanguageChange) {
RetranslateUI();
}
QDialog::changeEvent(event);
}
void ConfigureTouchscreenAdvanced::RetranslateUI() {
ui->retranslateUi(this);
}
void ConfigureTouchscreenAdvanced::ApplyConfiguration() {
Settings::values.touchscreen.finger = ui->finger_box->value();
Settings::values.touchscreen.diameter_x = ui->diameter_x_box->value();
Settings::values.touchscreen.diameter_y = ui->diameter_y_box->value();
Settings::values.touchscreen.rotation_angle = ui->angle_box->value();
}
void ConfigureTouchscreenAdvanced::loadConfiguration() {
void ConfigureTouchscreenAdvanced::LoadConfiguration() {
ui->finger_box->setValue(Settings::values.touchscreen.finger);
ui->diameter_x_box->setValue(Settings::values.touchscreen.diameter_x);
ui->diameter_y_box->setValue(Settings::values.touchscreen.diameter_y);
ui->angle_box->setValue(Settings::values.touchscreen.rotation_angle);
}
void ConfigureTouchscreenAdvanced::restoreDefaults() {
void ConfigureTouchscreenAdvanced::RestoreDefaults() {
ui->finger_box->setValue(0);
ui->diameter_x_box->setValue(15);
ui->diameter_y_box->setValue(15);
@@ -18,13 +18,16 @@ public:
explicit ConfigureTouchscreenAdvanced(QWidget* parent);
~ConfigureTouchscreenAdvanced() override;
void applyConfiguration();
void ApplyConfiguration();
private:
void changeEvent(QEvent* event) override;
void RetranslateUI();
/// Load configuration settings.
void loadConfiguration();
void LoadConfiguration();
/// Restore all buttons to their default values.
void restoreDefaults();
void RestoreDefaults();
std::unique_ptr<Ui::ConfigureTouchscreenAdvanced> ui;
};
+29 -13
View File
@@ -22,41 +22,61 @@ ConfigureWeb::ConfigureWeb(QWidget* parent)
#ifndef USE_DISCORD_PRESENCE
ui->discord_group->setVisible(false);
#endif
this->setConfiguration();
SetConfiguration();
RetranslateUI();
}
ConfigureWeb::~ConfigureWeb() = default;
void ConfigureWeb::setConfiguration() {
ui->web_credentials_disclaimer->setWordWrap(true);
ui->telemetry_learn_more->setOpenExternalLinks(true);
void ConfigureWeb::changeEvent(QEvent* event) {
if (event->type() == QEvent::LanguageChange) {
RetranslateUI();
}
QWidget::changeEvent(event);
}
void ConfigureWeb::RetranslateUI() {
ui->retranslateUi(this);
ui->telemetry_learn_more->setText(
tr("<a href='https://yuzu-emu.org/help/feature/telemetry/'><span style=\"text-decoration: "
"underline; color:#039be5;\">Learn more</span></a>"));
ui->web_signup_link->setOpenExternalLinks(true);
ui->web_signup_link->setText(
tr("<a href='https://profile.yuzu-emu.org/'><span style=\"text-decoration: underline; "
"color:#039be5;\">Sign up</span></a>"));
ui->web_token_info_link->setOpenExternalLinks(true);
ui->web_token_info_link->setText(
tr("<a href='https://yuzu-emu.org/wiki/yuzu-web-service/'><span style=\"text-decoration: "
"underline; color:#039be5;\">What is my token?</span></a>"));
ui->label_telemetry_id->setText(
tr("Telemetry ID: 0x%1").arg(QString::number(Core::GetTelemetryId(), 16).toUpper()));
}
void ConfigureWeb::SetConfiguration() {
ui->web_credentials_disclaimer->setWordWrap(true);
ui->telemetry_learn_more->setOpenExternalLinks(true);
ui->web_signup_link->setOpenExternalLinks(true);
ui->web_token_info_link->setOpenExternalLinks(true);
ui->toggle_telemetry->setChecked(Settings::values.enable_telemetry);
ui->edit_username->setText(QString::fromStdString(Settings::values.yuzu_username));
ui->edit_token->setText(QString::fromStdString(Settings::values.yuzu_token));
// Connect after setting the values, to avoid calling OnLoginChanged now
connect(ui->edit_token, &QLineEdit::textChanged, this, &ConfigureWeb::OnLoginChanged);
connect(ui->edit_username, &QLineEdit::textChanged, this, &ConfigureWeb::OnLoginChanged);
ui->label_telemetry_id->setText(
tr("Telemetry ID: 0x%1").arg(QString::number(Core::GetTelemetryId(), 16).toUpper()));
user_verified = true;
ui->toggle_discordrpc->setChecked(UISettings::values.enable_discord_presence);
}
void ConfigureWeb::applyConfiguration() {
void ConfigureWeb::ApplyConfiguration() {
Settings::values.enable_telemetry = ui->toggle_telemetry->isChecked();
UISettings::values.enable_discord_presence = ui->toggle_discordrpc->isChecked();
if (user_verified) {
@@ -120,7 +140,3 @@ void ConfigureWeb::OnLoginVerified() {
"correctly, and that your internet connection is working."));
}
}
void ConfigureWeb::retranslateUi() {
ui->retranslateUi(this);
}
+5 -3
View File
@@ -19,16 +19,18 @@ public:
explicit ConfigureWeb(QWidget* parent = nullptr);
~ConfigureWeb() override;
void applyConfiguration();
void retranslateUi();
void ApplyConfiguration();
private:
void changeEvent(QEvent* event) override;
void RetranslateUI();
void RefreshTelemetryID();
void OnLoginChanged();
void VerifyLogin();
void OnLoginVerified();
void setConfiguration();
void SetConfiguration();
bool user_verified = true;
QFutureWatcher<bool> verify_watcher;
+26 -36
View File
@@ -8,6 +8,7 @@
#include <vector>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QSettings>
@@ -32,11 +33,6 @@
namespace {
template <typename T>
T GetGameListCachedObject(const std::string& filename, const std::string& ext,
const std::function<T()>& generator);
template <>
QString GetGameListCachedObject(const std::string& filename, const std::string& ext,
const std::function<QString()>& generator) {
if (!UISettings::values.cache_game_list || filename == "0000000000000000") {
@@ -51,26 +47,22 @@ QString GetGameListCachedObject(const std::string& filename, const std::string&
if (!FileUtil::Exists(path)) {
const auto str = generator();
std::ofstream stream(path);
if (stream) {
stream << str.toStdString();
QFile file{QString::fromStdString(path)};
if (file.open(QFile::WriteOnly)) {
file.write(str.toUtf8());
}
return str;
}
std::ifstream stream(path);
if (stream) {
const std::string out(std::istreambuf_iterator<char>{stream},
std::istreambuf_iterator<char>{});
return QString::fromStdString(out);
QFile file{QString::fromStdString(path)};
if (file.open(QFile::ReadOnly)) {
return QString::fromUtf8(file.readAll());
}
return generator();
}
template <>
std::pair<std::vector<u8>, std::string> GetGameListCachedObject(
const std::string& filename, const std::string& ext,
const std::function<std::pair<std::vector<u8>, std::string>()>& generator) {
@@ -88,58 +80,56 @@ std::pair<std::vector<u8>, std::string> GetGameListCachedObject(
if (!FileUtil::Exists(path1) || !FileUtil::Exists(path2)) {
const auto [icon, nacp] = generator();
FileUtil::IOFile file1(path1, "wb");
if (!file1.IsOpen()) {
QFile file1{QString::fromStdString(path1)};
if (!file1.open(QFile::WriteOnly)) {
LOG_ERROR(Frontend, "Failed to open cache file.");
return generator();
}
if (!file1.Resize(icon.size())) {
if (!file1.resize(icon.size())) {
LOG_ERROR(Frontend, "Failed to resize cache file to necessary size.");
return generator();
}
if (file1.WriteBytes(icon.data(), icon.size()) != icon.size()) {
if (file1.write(reinterpret_cast<const char*>(icon.data()), icon.size()) != icon.size()) {
LOG_ERROR(Frontend, "Failed to write data to cache file.");
return generator();
}
std::ofstream stream2(path2, std::ios::out);
if (stream2) {
stream2 << nacp;
QFile file2{QString::fromStdString(path2)};
if (file2.open(QFile::WriteOnly)) {
file2.write(nacp.data(), nacp.size());
}
return std::make_pair(icon, nacp);
}
FileUtil::IOFile file1(path1, "rb");
std::ifstream stream2(path2);
QFile file1(QString::fromStdString(path1));
QFile file2(QString::fromStdString(path2));
if (!file1.IsOpen()) {
if (!file1.open(QFile::ReadOnly)) {
LOG_ERROR(Frontend, "Failed to open cache file for reading.");
return generator();
}
if (!stream2) {
if (!file2.open(QFile::ReadOnly)) {
LOG_ERROR(Frontend, "Failed to open cache file for reading.");
return generator();
}
std::vector<u8> vec(file1.GetSize());
file1.ReadBytes(vec.data(), vec.size());
if (stream2 && !vec.empty()) {
const std::string out(std::istreambuf_iterator<char>{stream2},
std::istreambuf_iterator<char>{});
return std::make_pair(vec, out);
std::vector<u8> vec(file1.size());
if (file1.read(reinterpret_cast<char*>(vec.data()), vec.size()) !=
static_cast<s64>(vec.size())) {
return generator();
}
return generator();
const auto data = file2.readAll();
return std::make_pair(vec, data.toStdString());
}
void GetMetadataFromControlNCA(const FileSys::PatchManager& patch_manager, const FileSys::NCA& nca,
std::vector<u8>& icon, std::string& name) {
std::tie(icon, name) = GetGameListCachedObject<std::pair<std::vector<u8>, std::string>>(
std::tie(icon, name) = GetGameListCachedObject(
fmt::format("{:016X}", patch_manager.GetTitleID()), {}, [&patch_manager, &nca] {
const auto [nacp, icon_f] = patch_manager.ParseControlNCA(nca);
return std::make_pair(icon_f->ReadAllBytes(), nacp->GetApplicationName());
@@ -221,7 +211,7 @@ QList<QStandardItem*> MakeGameListEntry(const std::string& path, const std::stri
};
if (UISettings::values.show_add_ons) {
const auto patch_versions = GetGameListCachedObject<QString>(
const auto patch_versions = GetGameListCachedObject(
fmt::format("{:016X}", patch.GetTitleID()), "pv.txt", [&patch, &loader] {
return FormatPatchNameVersions(patch, loader, loader.IsRomFSUpdatable());
});
+36 -38
View File
@@ -238,15 +238,13 @@ void GMainWindow::ProfileSelectorSelectProfile() {
dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);
dialog.setWindowModality(Qt::WindowModal);
dialog.exec();
if (!dialog.GetStatus()) {
if (dialog.exec() == QDialog::Rejected) {
emit ProfileSelectorFinishedSelection(std::nullopt);
return;
}
Service::Account::ProfileManager manager;
const auto uuid = manager.GetUser(dialog.GetIndex());
const auto uuid = manager.GetUser(static_cast<std::size_t>(dialog.GetIndex()));
if (!uuid.has_value()) {
emit ProfileSelectorFinishedSelection(std::nullopt);
return;
@@ -261,9 +259,8 @@ void GMainWindow::SoftwareKeyboardGetText(
dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);
dialog.setWindowModality(Qt::WindowModal);
dialog.exec();
if (!dialog.GetStatus()) {
if (dialog.exec() == QDialog::Rejected) {
emit SoftwareKeyboardFinishedText(std::nullopt);
return;
}
@@ -850,11 +847,6 @@ bool GMainWindow::LoadROM(const QString& filename) {
QMessageBox::critical(this, tr("Error while loading ROM!"),
tr("The ROM format is not supported."));
break;
case Core::System::ResultStatus::ErrorSystemMode:
LOG_CRITICAL(Frontend, "Failed to load ROM!");
QMessageBox::critical(this, tr("Error while loading ROM!"),
tr("Could not determine the system mode."));
break;
case Core::System::ResultStatus::ErrorVideoCore:
QMessageBox::critical(
this, tr("An error occurred initializing the video core."),
@@ -901,11 +893,12 @@ void GMainWindow::SelectAndSetCurrentUser() {
dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);
dialog.setWindowModality(Qt::WindowModal);
dialog.exec();
if (dialog.GetStatus()) {
Settings::values.current_user = static_cast<s32>(dialog.GetIndex());
if (dialog.exec() == QDialog::Rejected) {
return;
}
Settings::values.current_user = dialog.GetIndex();
}
void GMainWindow::BootGame(const QString& filename) {
@@ -1055,14 +1048,13 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target
const std::string nand_dir = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir);
ASSERT(program_id != 0);
const auto select_profile = [this]() -> s32 {
const auto select_profile = [this] {
QtProfileSelectionDialog dialog(this);
dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);
dialog.setWindowModality(Qt::WindowModal);
dialog.exec();
if (!dialog.GetStatus()) {
if (dialog.exec() == QDialog::Rejected) {
return -1;
}
@@ -1070,11 +1062,12 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target
};
const auto index = select_profile();
if (index == -1)
if (index == -1) {
return;
}
Service::Account::ProfileManager manager;
const auto user_id = manager.GetUser(index);
const auto user_id = manager.GetUser(static_cast<std::size_t>(index));
ASSERT(user_id);
path = nand_dir + FileSys::SaveDataFactory::GetFullPath(FileSys::SaveDataSpaceId::NandUser,
FileSys::SaveDataType::SaveData,
@@ -1296,10 +1289,10 @@ void GMainWindow::OnGameListOpenPerGameProperties(const std::string& file) {
}
ConfigurePerGameGeneral dialog(this, title_id);
dialog.loadFromFile(v_file);
dialog.LoadFromFile(v_file);
auto result = dialog.exec();
if (result == QDialog::Accepted) {
dialog.applyConfiguration();
dialog.ApplyConfiguration();
const auto reload = UISettings::values.is_game_list_reload_pending.exchange(false);
if (reload) {
@@ -1690,26 +1683,31 @@ void GMainWindow::ToggleWindowMode() {
}
void GMainWindow::OnConfigure() {
ConfigureDialog configureDialog(this, hotkey_registry);
auto old_theme = UISettings::values.theme;
const auto old_theme = UISettings::values.theme;
const bool old_discord_presence = UISettings::values.enable_discord_presence;
auto result = configureDialog.exec();
if (result == QDialog::Accepted) {
configureDialog.applyConfiguration();
InitializeHotkeys();
if (UISettings::values.theme != old_theme)
UpdateUITheme();
if (UISettings::values.enable_discord_presence != old_discord_presence)
SetDiscordEnabled(UISettings::values.enable_discord_presence);
const auto reload = UISettings::values.is_game_list_reload_pending.exchange(false);
if (reload) {
game_list->PopulateAsync(UISettings::values.game_directory_path,
UISettings::values.game_directory_deepscan);
}
config->Save();
ConfigureDialog configure_dialog(this, hotkey_registry);
const auto result = configure_dialog.exec();
if (result != QDialog::Accepted) {
return;
}
configure_dialog.ApplyConfiguration();
InitializeHotkeys();
if (UISettings::values.theme != old_theme) {
UpdateUITheme();
}
if (UISettings::values.enable_discord_presence != old_discord_presence) {
SetDiscordEnabled(UISettings::values.enable_discord_presence);
}
const auto reload = UISettings::values.is_game_list_reload_pending.exchange(false);
if (reload) {
game_list->PopulateAsync(UISettings::values.game_directory_path,
UISettings::values.game_directory_deepscan);
}
config->Save();
}
void GMainWindow::OnLoadAmiibo() {
+1 -4
View File
@@ -192,7 +192,7 @@ int main(int argc, char** argv) {
switch (load_result) {
case Core::System::ResultStatus::ErrorGetLoader:
LOG_CRITICAL(Frontend, "Failed to obtain loader for %s!", filepath.c_str());
LOG_CRITICAL(Frontend, "Failed to obtain loader for {}!", filepath);
return -1;
case Core::System::ResultStatus::ErrorLoader:
LOG_CRITICAL(Frontend, "Failed to load ROM!");
@@ -200,9 +200,6 @@ int main(int argc, char** argv) {
case Core::System::ResultStatus::ErrorNotInitialized:
LOG_CRITICAL(Frontend, "CPUCore not initialized");
return -1;
case Core::System::ResultStatus::ErrorSystemMode:
LOG_CRITICAL(Frontend, "Failed to determine system mode!");
return -1;
case Core::System::ResultStatus::ErrorVideoCore:
LOG_CRITICAL(Frontend, "Failed to initialize VideoCore!");
return -1;