[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:
committed by
Radosław Gliński
parent
2e9c459846
commit
9054a29483
@@ -107,6 +107,10 @@ dword_result_t XamInputGetState_entry(dword_t user_index, dword_t flags,
|
||||
return X_ERROR_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
|
||||
if (kernel_state()->xam_state()->xam_dialogs_shown_ > 0) {
|
||||
return X_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
// Games call this with a NULL state ptr, probably as a query.
|
||||
|
||||
uint32_t actual_user_index = user_index;
|
||||
|
||||
@@ -17,23 +17,6 @@ namespace xe {
|
||||
namespace kernel {
|
||||
namespace xam {
|
||||
|
||||
std::atomic<int> xam_dialogs_shown_ = {0};
|
||||
std::atomic<int> xam_nui_dialogs_shown_ = {0};
|
||||
|
||||
// FixMe(RodoMa92): Same hack as main_init_posix.cc:40
|
||||
// Force initialization before constructor calling, mimicking
|
||||
// Windows.
|
||||
// Ref:
|
||||
// https://reviews.llvm.org/D12689#243295
|
||||
#ifdef XE_PLATFORM_LINUX
|
||||
__attribute__((init_priority(101)))
|
||||
#endif
|
||||
static std::vector<xe::cpu::Export*>
|
||||
xam_exports(4096);
|
||||
|
||||
bool xeXamIsUIActive() { return xam_dialogs_shown_ > 0; }
|
||||
bool xeXamIsNuiUIActive() { return xam_nui_dialogs_shown_ > 0; }
|
||||
|
||||
XamModule::XamModule(Emulator* emulator, KernelState* kernel_state)
|
||||
: KernelModule(kernel_state, "xe:\\xam.xex"), loader_data_() {
|
||||
RegisterExportTable(export_resolver_);
|
||||
@@ -45,7 +28,13 @@ XamModule::XamModule(Emulator* emulator, KernelState* kernel_state)
|
||||
#undef XE_MODULE_EXPORT_GROUP
|
||||
}
|
||||
|
||||
static auto& get_xam_exports() {
|
||||
static std::vector<xe::cpu::Export*> xam_exports(4096);
|
||||
return xam_exports;
|
||||
}
|
||||
|
||||
xe::cpu::Export* RegisterExport_xam(xe::cpu::Export* export_entry) {
|
||||
auto& xam_exports = get_xam_exports();
|
||||
assert_true(export_entry->ordinal < xam_exports.size());
|
||||
xam_exports[export_entry->ordinal] = export_entry;
|
||||
return export_entry;
|
||||
@@ -58,6 +47,7 @@ static constexpr xe::cpu::Export xam_export_table[] = {
|
||||
#include "xenia/kernel/util/export_table_post.inc"
|
||||
void XamModule::RegisterExportTable(xe::cpu::ExportResolver* export_resolver) {
|
||||
assert_not_null(export_resolver);
|
||||
auto& xam_exports = get_xam_exports();
|
||||
|
||||
for (size_t i = 0; i < xe::countof(xam_export_table); ++i) {
|
||||
auto& export_entry = xam_export_table[i];
|
||||
@@ -67,7 +57,7 @@ void XamModule::RegisterExportTable(xe::cpu::ExportResolver* export_resolver) {
|
||||
const_cast<xe::cpu::Export*>(&export_entry);
|
||||
}
|
||||
}
|
||||
export_resolver->RegisterTable("xam.xex", &xam_exports);
|
||||
export_resolver->RegisterTable("xam.xex", &get_xam_exports());
|
||||
}
|
||||
|
||||
XamModule::~XamModule() {}
|
||||
|
||||
@@ -20,9 +20,6 @@ namespace xe {
|
||||
namespace kernel {
|
||||
namespace xam {
|
||||
|
||||
bool xeXamIsUIActive();
|
||||
bool xeXamIsNuiUIActive();
|
||||
|
||||
static constexpr std::string_view kXamModuleLoaderDataFileName =
|
||||
"launch_data.bin";
|
||||
|
||||
|
||||
@@ -28,10 +28,6 @@ DEFINE_bool(allow_nui_initialization, false,
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace xam {
|
||||
|
||||
extern std::atomic<int> xam_dialogs_shown_;
|
||||
extern std::atomic<int> xam_nui_dialogs_shown_;
|
||||
|
||||
// https://web.cs.ucdavis.edu/~okreylos/ResDev/Kinect/MainPage.html
|
||||
|
||||
struct X_NUI_DEVICE_STATUS {
|
||||
@@ -185,7 +181,9 @@ dword_result_t XamNuiCameraSetFlags_entry(qword_t unk1, dword_t unk2) {
|
||||
}
|
||||
DECLARE_XAM_EXPORT1(XamNuiCameraSetFlags, kNone, kStub);
|
||||
|
||||
dword_result_t XamIsNuiUIActive_entry() { return xeXamIsNuiUIActive(); }
|
||||
dword_result_t XamIsNuiUIActive_entry() {
|
||||
return kernel_state()->xam_state()->xam_nui_dialogs_shown_ > 0;
|
||||
}
|
||||
DECLARE_XAM_EXPORT1(XamIsNuiUIActive, kNone, kImplemented);
|
||||
|
||||
dword_result_t XamNuiIsDeviceReady_entry() {
|
||||
@@ -367,9 +365,9 @@ dword_result_t XamShowNuiTroubleshooterUI_entry(dword_t user_index,
|
||||
"The game has indicated there is a problem with NUI (Kinect).")
|
||||
->Then(&fence);
|
||||
})) {
|
||||
++xam_dialogs_shown_;
|
||||
kernel_state()->xam_state()->xam_dialogs_shown_++;
|
||||
fence.Wait();
|
||||
--xam_dialogs_shown_;
|
||||
kernel_state()->xam_state()->xam_dialogs_shown_--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,9 +17,6 @@ namespace xe {
|
||||
namespace kernel {
|
||||
namespace xam {
|
||||
|
||||
bool xeXamIsUIActive();
|
||||
bool xeXamIsNuiUIActive();
|
||||
|
||||
xe::cpu::Export* RegisterExport_xam(xe::cpu::Export* export_entry);
|
||||
|
||||
// Registration functions, one per file.
|
||||
|
||||
@@ -59,6 +59,9 @@ class XamState {
|
||||
|
||||
X_DASH_APP_INFO dash_app_info_ = {};
|
||||
|
||||
std::atomic<int32_t> xam_dialogs_shown_ = {0};
|
||||
std::atomic<int32_t> xam_nui_dialogs_shown_ = {0};
|
||||
|
||||
private:
|
||||
KernelState* kernel_state_;
|
||||
|
||||
|
||||
@@ -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/
|
||||
|
||||
@@ -25,10 +25,9 @@ class XamDialog : public xe::ui::ImGuiDialog {
|
||||
}
|
||||
|
||||
protected:
|
||||
XamDialog(xe::ui::ImGuiDrawer* imgui_drawer)
|
||||
: xe::ui::ImGuiDialog(imgui_drawer) {}
|
||||
XamDialog(xe::ui::ImGuiDrawer* imgui_drawer);
|
||||
|
||||
virtual ~XamDialog() {}
|
||||
~XamDialog();
|
||||
void OnClose() override {
|
||||
if (close_callback_) {
|
||||
close_callback_();
|
||||
|
||||
Reference in New Issue
Block a user