[XAM/UI] Implemented profile passcode UI

This commit is contained in:
Adrian 2024-12-29 15:14:59 +00:00 committed by Radosław Gliński
parent fe85be8817
commit ceb94e019a
3 changed files with 196 additions and 26 deletions

View File

@ -180,6 +180,10 @@ class UserProfile {
uint32_t GetSubscriptionTier() const {
return account_info_.GetSubscriptionTier();
}
void GetPasscode(uint16_t* passcode) const {
std::memcpy(passcode, account_info_.passcode,
sizeof(account_info_.passcode));
};
void AddSetting(std::unique_ptr<UserSetting> setting);
UserSetting* GetSetting(uint32_t setting_id);

View File

@ -320,6 +320,119 @@ class MessageBoxDialog : public XamDialog {
uint32_t chosen_button_ = 0;
};
class ProfilePasscodeDialog : public XamDialog {
public:
const char* labelled_keys_[11] = {"None", "X", "Y", "RB", "LB", "LT",
"RT", "Up", "Down", "Left", "Right"};
const std::map<std::string, uint16_t> keys_map_ = {
{"None", 0},
{"X", X_BUTTON_PASSCODE},
{"Y", Y_BUTTON_PASSCODE},
{"RB", RIGHT_BUMPER_PASSCODE},
{"LB", LEFT_BUMPER_PASSCODE},
{"LT", LEFT_TRIGGER_PASSCODE},
{"RT", RIGHT_TRIGGER_PASSCODE},
{"Up", DPAD_UP_PASSCODE},
{"Down", DPAD_DOWN_PASSCODE},
{"Left", DPAD_LEFT_PASSCODE},
{"Right", DPAD_RIGHT_PASSCODE}};
ProfilePasscodeDialog(xe::ui::ImGuiDrawer* imgui_drawer, std::string& title,
std::string& description, MESSAGEBOX_RESULT* result_ptr)
: XamDialog(imgui_drawer),
title_(title),
description_(description),
result_ptr_(result_ptr) {
std::memset(result_ptr, 0, sizeof(MESSAGEBOX_RESULT));
if (title_.empty()) {
title_ = "Enter Pass Code";
}
if (description_.empty()) {
description_ = "Enter your Xbox LIVE pass code.";
}
}
void DrawPasscodeField(uint8_t key_id) {
const std::string label = fmt::format("##Key {}", key_id);
if (ImGui::BeginCombo(label.c_str(),
labelled_keys_[key_indexes_[key_id]])) {
for (uint8_t key_index = 0; key_index < keys_map_.size(); key_index++) {
bool is_selected = key_id == key_index;
if (ImGui::Selectable(labelled_keys_[key_index], is_selected)) {
key_indexes_[key_id] = key_index;
}
if (is_selected) {
ImGui::SetItemDefaultFocus();
}
}
ImGui::EndCombo();
}
}
void OnDraw(ImGuiIO& io) override {
if (!has_opened_) {
ImGui::OpenPopup(title_.c_str());
has_opened_ = true;
}
if (ImGui::BeginPopupModal(title_.c_str(), nullptr,
ImGuiWindowFlags_AlwaysAutoResize)) {
if (description_.size()) {
ImGui::Text(description_.c_str());
}
for (uint8_t i = 0; i < passcode_length; i++) {
DrawPasscodeField(i);
// result_ptr_->Passcode[i] =
// keys_map_.at(labelled_keys_[key_indexes_[i]]);
}
ImGui::NewLine();
// We write each key on close to prevent simultaneous dialogs.
if (ImGui::Button("Sign In")) {
for (uint8_t i = 0; i < passcode_length; i++) {
result_ptr_->Passcode[i] =
keys_map_.at(labelled_keys_[key_indexes_[i]]);
}
selected_signed_in_ = true;
Close();
}
ImGui::SameLine();
if (ImGui::Button("Cancel")) {
Close();
}
}
ImGui::EndPopup();
}
virtual ~ProfilePasscodeDialog() {}
bool SelectedSignedIn() const { return selected_signed_in_; }
private:
bool has_opened_ = false;
bool selected_signed_in_ = false;
std::string title_;
std::string description_;
static const uint8_t passcode_length = sizeof(X_XAMACCOUNTINFO::passcode);
int key_indexes_[passcode_length] = {0, 0, 0, 0};
MESSAGEBOX_RESULT* result_ptr_;
};
class GamertagModifyDialog final : public ui::ImGuiDialog {
public:
GamertagModifyDialog(ui::ImGuiDrawer* imgui_drawer,
@ -783,7 +896,8 @@ class GamesInfoDialog final : public ui::ImGuiDialog {
static dword_result_t XamShowMessageBoxUi(
dword_t user_index, lpu16string_t title_ptr, lpu16string_t text_ptr,
dword_t button_count, lpdword_t button_ptrs, dword_t active_button,
dword_t flags, lpdword_t result_ptr, pointer_t<XAM_OVERLAPPED> overlapped) {
dword_t flags, pointer_t<MESSAGEBOX_RESULT> result_ptr,
pointer_t<XAM_OVERLAPPED> overlapped) {
std::string title = title_ptr ? xe::to_utf8(title_ptr.value()) : "";
std::string text = text_ptr ? xe::to_utf8(text_ptr.value()) : "";
@ -799,38 +913,53 @@ static dword_result_t XamShowMessageBoxUi(
if (cvars::headless) {
// Auto-pick the focused button.
auto run = [result_ptr, active_button]() -> X_RESULT {
*result_ptr = static_cast<uint32_t>(active_button);
result_ptr->ButtonPressed = static_cast<uint32_t>(active_button);
return X_ERROR_SUCCESS;
};
result = xeXamDispatchHeadless(run, overlapped);
} else {
// TODO(benvanik): setup icon states.
switch (flags & 0xF) {
case 0:
// config.pszMainIcon = nullptr;
break;
case 1:
// config.pszMainIcon = TD_ERROR_ICON;
break;
case 2:
// config.pszMainIcon = TD_WARNING_ICON;
break;
case 3:
// config.pszMainIcon = TD_INFORMATION_ICON;
break;
case XMBox_NOICON: {
} break;
case XMBox_ERRORICON: {
} break;
case XMBox_WARNINGICON: {
} break;
case XMBox_ALERTICON: {
} break;
}
auto close = [result_ptr](MessageBoxDialog* dialog) -> X_RESULT {
*result_ptr = dialog->chosen_button();
return X_ERROR_SUCCESS;
};
const Emulator* emulator = kernel_state()->emulator();
ui::ImGuiDrawer* imgui_drawer = emulator->imgui_drawer();
result = xeXamDispatchDialog<MessageBoxDialog>(
new MessageBoxDialog(imgui_drawer, title, text, buttons,
static_cast<uint32_t>(active_button)),
close, overlapped);
if (flags & XMBox_PASSCODEMODE || flags & XMBox_VERIFYPASSCODEMODE) {
auto close = [result_ptr,
active_button](ProfilePasscodeDialog* dialog) -> X_RESULT {
if (dialog->SelectedSignedIn()) {
// Logged in
return X_ERROR_SUCCESS;
} else {
return X_ERROR_FUNCTION_FAILED;
}
};
result = xeXamDispatchDialog<ProfilePasscodeDialog>(
new ProfilePasscodeDialog(imgui_drawer, title, text, result_ptr),
close, overlapped);
} else {
auto close = [result_ptr](MessageBoxDialog* dialog) -> X_RESULT {
result_ptr->ButtonPressed = dialog->chosen_button();
return X_ERROR_SUCCESS;
};
result = xeXamDispatchDialog<MessageBoxDialog>(
new MessageBoxDialog(imgui_drawer, title, text, buttons,
static_cast<uint32_t>(active_button)),
close, overlapped);
}
}
return result;
}
@ -838,7 +967,8 @@ static dword_result_t XamShowMessageBoxUi(
dword_result_t XamShowMessageBoxUI_entry(
dword_t user_index, lpu16string_t title_ptr, lpu16string_t text_ptr,
dword_t button_count, lpdword_t button_ptrs, dword_t active_button,
dword_t flags, lpdword_t result_ptr, pointer_t<XAM_OVERLAPPED> overlapped) {
dword_t flags, pointer_t<MESSAGEBOX_RESULT> result_ptr,
pointer_t<XAM_OVERLAPPED> overlapped) {
return XamShowMessageBoxUi(user_index, title_ptr, text_ptr, button_count,
button_ptrs, active_button, flags, result_ptr,
overlapped);
@ -848,7 +978,8 @@ DECLARE_XAM_EXPORT1(XamShowMessageBoxUI, kUI, kImplemented);
dword_result_t XamShowMessageBoxUIEx_entry(
dword_t user_index, lpu16string_t title_ptr, lpu16string_t text_ptr,
dword_t button_count, lpdword_t button_ptrs, dword_t active_button,
dword_t flags, dword_t unknown_unused, lpdword_t result_ptr,
dword_t flags, dword_t unknown_unused,
pointer_t<MESSAGEBOX_RESULT> result_ptr,
pointer_t<XAM_OVERLAPPED> overlapped) {
return XamShowMessageBoxUi(user_index, title_ptr, text_ptr, button_count,
button_ptrs, active_button, flags, result_ptr,

View File

@ -664,8 +664,43 @@ struct X_PROFILEENUMRESULT {
};
static_assert_size(X_PROFILEENUMRESULT, 0x188);
} // namespace xe
struct MESSAGEBOX_RESULT {
union {
xe::be<uint32_t> ButtonPressed;
xe::be<uint16_t> Passcode[4];
};
};
// clang-format off
#define XMBox_NOICON 0x00000000
#define XMBox_ERRORICON 0x00000001
#define XMBox_WARNINGICON 0x00000002
#define XMBox_ALERTICON 0x00000003
#define XMBox_PASSCODEMODE 0x00010000
#define XMBox_VERIFYPASSCODEMODE 0x00020000
#define XMBox_WAITANIMATION 0x00001000
#define XMBox_LIVEPASSCODEMODE 0x00030000
#define XMBox_MODEMASK 0x00030000
#define XMBox_OK 1
#define XMBox_CANCEL 2
#define X_BUTTON_PASSCODE 0x00005802
#define Y_BUTTON_PASSCODE 0x00005803
#define RIGHT_BUMPER_PASSCODE 0x00005804
#define LEFT_BUMPER_PASSCODE 0x00005805
#define LEFT_TRIGGER_PASSCODE 0x00005806
#define RIGHT_TRIGGER_PASSCODE 0x00005807
#define DPAD_UP_PASSCODE 0x00005810
#define DPAD_DOWN_PASSCODE 0x00005811
#define DPAD_LEFT_PASSCODE 0x00005812
#define DPAD_RIGHT_PASSCODE 0x00005813
// clang-format on
} // namespace xe
#endif // XENIA_XBOX_H_