[XAM] Added storage device select UI

This commit is contained in:
NicknineTheEagle 2024-06-17 18:53:26 +03:00 committed by Radosław Gliński
parent e5c8f00e26
commit 16affb94d4
3 changed files with 62 additions and 10 deletions

View File

@ -59,6 +59,20 @@ const DummyDeviceInfo* GetDummyDeviceInfo(uint32_t device_id) {
return it == end ? nullptr : *it; return it == end ? nullptr : *it;
} }
std::vector<const DummyDeviceInfo*> ListStorageDevices(bool include_readonly) {
// FIXME: Should probably check content flags here instead.
std::vector<const DummyDeviceInfo*> devices;
for (const auto& device_info : dummy_device_infos_) {
if (!include_readonly && device_info->device_type == DeviceType::ODD) {
continue;
}
devices.emplace_back(device_info);
}
return devices;
}
dword_result_t XamContentGetDeviceName_entry(dword_t device_id, dword_result_t XamContentGetDeviceName_entry(dword_t device_id,
lpu16string_t name_buffer, lpu16string_t name_buffer,
dword_t name_capacity) { dword_t name_capacity) {

View File

@ -35,6 +35,8 @@ struct DummyDeviceInfo {
}; };
const DummyDeviceInfo* GetDummyDeviceInfo(uint32_t device_id); const DummyDeviceInfo* GetDummyDeviceInfo(uint32_t device_id);
std::vector<const DummyDeviceInfo*> ListStorageDevices(
bool include_readonly = false);
} // namespace xam } // namespace xam
} // namespace kernel } // namespace kernel

View File

@ -14,6 +14,7 @@
#include "xenia/kernel/kernel_flags.h" #include "xenia/kernel/kernel_flags.h"
#include "xenia/kernel/kernel_state.h" #include "xenia/kernel/kernel_state.h"
#include "xenia/kernel/util/shim_utils.h" #include "xenia/kernel/util/shim_utils.h"
#include "xenia/kernel/xam/xam_content_device.h"
#include "xenia/kernel/xam/xam_private.h" #include "xenia/kernel/xam/xam_private.h"
#include "xenia/ui/imgui_dialog.h" #include "xenia/ui/imgui_dialog.h"
#include "xenia/ui/imgui_drawer.h" #include "xenia/ui/imgui_drawer.h"
@ -25,6 +26,10 @@ namespace xe {
namespace kernel { namespace kernel {
namespace xam { namespace xam {
DEFINE_bool(storage_selection_dialog, false,
"Show storage device selection dialog when the game requests it.",
"UI");
// TODO(gibbed): This is all one giant WIP that seems to work better than the // TODO(gibbed): This is all one giant WIP that seems to work better than the
// previous immediate synchronous completion of dialogs. // previous immediate synchronous completion of dialogs.
// //
@ -286,7 +291,7 @@ static dword_result_t XamShowMessageBoxUi(
} }
X_RESULT result; X_RESULT result;
if (cvars::headless) { if (::cvars::headless) {
// Auto-pick the focused button. // Auto-pick the focused button.
auto run = [result_ptr, active_button]() -> X_RESULT { auto run = [result_ptr, active_button]() -> X_RESULT {
*result_ptr = static_cast<uint32_t>(active_button); *result_ptr = static_cast<uint32_t>(active_button);
@ -358,7 +363,7 @@ dword_result_t XNotifyQueueUI_entry(dword_t exnq, dword_t dwUserIndex,
XELOGI("XNotifyQueueUI: {}", displayText); XELOGI("XNotifyQueueUI: {}", displayText);
if (cvars::headless) { if (::cvars::headless) {
return X_ERROR_SUCCESS; return X_ERROR_SUCCESS;
} }
@ -478,7 +483,7 @@ dword_result_t XamShowKeyboardUI_entry(
auto buffer_size = static_cast<size_t>(buffer_length) * 2; auto buffer_size = static_cast<size_t>(buffer_length) * 2;
X_RESULT result; X_RESULT result;
if (cvars::headless) { if (::cvars::headless) {
auto run = [default_text, buffer, buffer_length, auto run = [default_text, buffer, buffer_length,
buffer_size]() -> X_RESULT { buffer_size]() -> X_RESULT {
// Redirect default_text back into the buffer. // Redirect default_text back into the buffer.
@ -526,18 +531,49 @@ dword_result_t XamShowDeviceSelectorUI_entry(
dword_t user_index, dword_t content_type, dword_t content_flags, dword_t user_index, dword_t content_type, dword_t content_flags,
qword_t total_requested, lpdword_t device_id_ptr, qword_t total_requested, lpdword_t device_id_ptr,
pointer_t<XAM_OVERLAPPED> overlapped) { pointer_t<XAM_OVERLAPPED> overlapped) {
return xeXamDispatchHeadless( std::vector<const DummyDeviceInfo*> devices = ListStorageDevices();
[device_id_ptr]() -> X_RESULT {
// NOTE: 0x00000001 is our dummy device ID from xam_content.cc if (::cvars::headless || !cvars::storage_selection_dialog) {
*device_id_ptr = 0x00000001; // Default to the first storage device (HDD) if headless.
return X_ERROR_SUCCESS; return xeXamDispatchHeadless(
}, [device_id_ptr, devices]() -> X_RESULT {
if (devices.empty()) return X_ERROR_CANCELLED;
const DummyDeviceInfo* device_info = devices.front();
*device_id_ptr = static_cast<uint32_t>(device_info->device_id);
return X_ERROR_SUCCESS;
},
overlapped);
}
auto close = [device_id_ptr, devices](MessageBoxDialog* dialog) -> X_RESULT {
uint32_t button = dialog->chosen_button();
if (button >= devices.size()) return X_ERROR_CANCELLED;
const DummyDeviceInfo* device_info = devices.at(button);
*device_id_ptr = static_cast<uint32_t>(device_info->device_id);
return X_ERROR_SUCCESS;
};
std::string title = "Select storage device";
std::string desc = "";
cxxopts::OptionNames buttons;
for (auto& device_info : devices) {
buttons.push_back(to_utf8(device_info->name));
}
buttons.push_back("Cancel");
const Emulator* emulator = kernel_state()->emulator();
ui::ImGuiDrawer* imgui_drawer = emulator->imgui_drawer();
return xeXamDispatchDialog<MessageBoxDialog>(
new MessageBoxDialog(imgui_drawer, title, desc, buttons, 0), close,
overlapped); overlapped);
} }
DECLARE_XAM_EXPORT1(XamShowDeviceSelectorUI, kUI, kImplemented); DECLARE_XAM_EXPORT1(XamShowDeviceSelectorUI, kUI, kImplemented);
void XamShowDirtyDiscErrorUI_entry(dword_t user_index) { void XamShowDirtyDiscErrorUI_entry(dword_t user_index) {
if (cvars::headless) { if (::cvars::headless) {
assert_always(); assert_always();
exit(1); exit(1);
return; return;