[UI] Add simple support for controller usage in UI

- Disabled unnecessary hotkeys thread when it is not used
- Removed problematic xam_exports static initialization
- Moved xam_dialogs_shown_ and xam_nui_dialogs_shown_ to XamState
This commit is contained in:
Gliniak
2025-08-11 21:56:13 +02:00
committed by Radosław Gliński
parent 2e9c459846
commit 9054a29483
17 changed files with 221 additions and 154 deletions

View File

@@ -54,16 +54,24 @@ namespace xam {
//
// We deliberately delay the XN_SYS_UI = false notification to give games time
// to create a listener (if they're insane enough do this).
XamDialog::XamDialog(xe::ui::ImGuiDrawer* imgui_drawer)
: xe::ui::ImGuiDialog(imgui_drawer) {
kernel_state()->BroadcastNotification(kXNotificationSystemUI, true);
kernel_state()->xam_state()->xam_dialogs_shown_++;
}
extern std::atomic<int> xam_dialogs_shown_;
XamDialog::~XamDialog() {
kernel_state()->xam_state()->xam_dialogs_shown_--;
if (kernel_state()->xam_state()->xam_dialogs_shown_ == 0) {
kernel_state()->BroadcastNotification(kXNotificationSystemUI, false);
}
}
template <typename T>
X_RESULT xeXamDispatchDialog(T* dialog,
std::function<X_RESULT(T*)> close_callback,
uint32_t overlapped) {
auto pre = []() {
kernel_state()->BroadcastNotification(kXNotificationSystemUI, true);
};
auto pre = []() {};
auto run = [dialog, close_callback]() -> X_RESULT {
X_RESULT result;
dialog->set_close_callback([&dialog, &result, &close_callback]() {
@@ -74,19 +82,14 @@ X_RESULT xeXamDispatchDialog(T* dialog,
kernel_state()->emulator()->display_window()->app_context();
if (app_context.CallInUIThreadSynchronous(
[&dialog, &fence]() { dialog->Then(&fence); })) {
++xam_dialogs_shown_;
fence.Wait();
--xam_dialogs_shown_;
} else {
delete dialog;
}
// dialog should be deleted at this point!
return result;
};
auto post = []() {
xe::threading::Sleep(std::chrono::milliseconds(100));
kernel_state()->BroadcastNotification(kXNotificationSystemUI, false);
};
auto post = []() { xe::threading::Sleep(std::chrono::milliseconds(100)); };
if (!overlapped) {
pre();
auto result = run();
@@ -102,9 +105,7 @@ template <typename T>
X_RESULT xeXamDispatchDialogEx(
T* dialog, std::function<X_RESULT(T*, uint32_t&, uint32_t&)> close_callback,
uint32_t overlapped) {
auto pre = []() {
kernel_state()->BroadcastNotification(kXNotificationSystemUI, true);
};
auto pre = []() {};
auto run = [dialog, close_callback](uint32_t& extended_error,
uint32_t& length) -> X_RESULT {
auto display_window = kernel_state()->emulator()->display_window();
@@ -116,19 +117,14 @@ X_RESULT xeXamDispatchDialogEx(
xe::threading::Fence fence;
if (display_window->app_context().CallInUIThreadSynchronous(
[&dialog, &fence]() { dialog->Then(&fence); })) {
++xam_dialogs_shown_;
fence.Wait();
--xam_dialogs_shown_;
} else {
delete dialog;
}
// dialog should be deleted at this point!
return result;
};
auto post = []() {
xe::threading::Sleep(std::chrono::milliseconds(100));
kernel_state()->BroadcastNotification(kXNotificationSystemUI, false);
};
auto post = []() { xe::threading::Sleep(std::chrono::milliseconds(100)); };
if (!overlapped) {
pre();
uint32_t extended_error, length;
@@ -144,13 +140,8 @@ X_RESULT xeXamDispatchDialogEx(
X_RESULT xeXamDispatchHeadless(std::function<X_RESULT()> run_callback,
uint32_t overlapped) {
auto pre = []() {
kernel_state()->BroadcastNotification(kXNotificationSystemUI, true);
};
auto post = []() {
xe::threading::Sleep(std::chrono::milliseconds(100));
kernel_state()->BroadcastNotification(kXNotificationSystemUI, false);
};
auto pre = []() {};
auto post = []() { xe::threading::Sleep(std::chrono::milliseconds(100)); };
if (!overlapped) {
pre();
auto result = run_callback();
@@ -166,13 +157,8 @@ X_RESULT xeXamDispatchHeadless(std::function<X_RESULT()> run_callback,
X_RESULT xeXamDispatchHeadlessEx(
std::function<X_RESULT(uint32_t&, uint32_t&)> run_callback,
uint32_t overlapped) {
auto pre = []() {
kernel_state()->BroadcastNotification(kXNotificationSystemUI, true);
};
auto post = []() {
xe::threading::Sleep(std::chrono::milliseconds(100));
kernel_state()->BroadcastNotification(kXNotificationSystemUI, false);
};
auto pre = []() {};
auto post = []() { xe::threading::Sleep(std::chrono::milliseconds(100)); };
if (!overlapped) {
pre();
uint32_t extended_error, length;
@@ -190,20 +176,14 @@ X_RESULT xeXamDispatchHeadlessEx(
template <typename T>
X_RESULT xeXamDispatchDialogAsync(T* dialog,
std::function<void(T*)> close_callback) {
kernel_state()->BroadcastNotification(kXNotificationSystemUI, true);
++xam_dialogs_shown_;
// Important to pass captured vars by value here since we return from this
// without waiting for the dialog to close so the original local vars will be
// destroyed.
dialog->set_close_callback([dialog, close_callback]() {
close_callback(dialog);
--xam_dialogs_shown_;
auto run = []() -> void {
xe::threading::Sleep(std::chrono::milliseconds(100));
kernel_state()->BroadcastNotification(kXNotificationSystemUI, false);
};
std::thread thread(run);
@@ -214,18 +194,12 @@ X_RESULT xeXamDispatchDialogAsync(T* dialog,
}
X_RESULT xeXamDispatchHeadlessAsync(std::function<void()> run_callback) {
kernel_state()->BroadcastNotification(kXNotificationSystemUI, true);
++xam_dialogs_shown_;
auto display_window = kernel_state()->emulator()->display_window();
display_window->app_context().CallInUIThread([run_callback]() {
run_callback();
--xam_dialogs_shown_;
auto run = []() -> void {
xe::threading::Sleep(std::chrono::milliseconds(100));
kernel_state()->BroadcastNotification(kXNotificationSystemUI, false);
};
std::thread thread(run);
@@ -393,7 +367,9 @@ static dword_result_t XamShowMessageBoxUi(
return result;
}
dword_result_t XamIsUIActive_entry() { return xeXamIsUIActive(); }
dword_result_t XamIsUIActive_entry() {
return kernel_state()->xam_state()->xam_dialogs_shown_ > 0;
}
DECLARE_XAM_EXPORT2(XamIsUIActive, kUI, kImplemented, kHighFrequency);
// https://www.se7ensins.com/forums/threads/working-xshowmessageboxui.844116/