From 1f404c57da108d1bd4a2c2d90b649d50e0440334 Mon Sep 17 00:00:00 2001 From: ergo720 <45463469+ergo720@users.noreply.github.com> Date: Sun, 13 Jun 2021 14:39:53 +0200 Subject: [PATCH 1/9] Added support to mu to settings + created mu folders --- src/common/Settings.cpp | 16 +++++++++++++++- src/common/Settings.hpp | 2 ++ src/core/kernel/init/CxbxKrnl.cpp | 22 ++++++++++++++++++++++ src/core/kernel/support/EmuFile.cpp | 9 ++++++++- src/core/kernel/support/EmuFile.h | 14 +++++++------- 5 files changed, 54 insertions(+), 9 deletions(-) diff --git a/src/common/Settings.cpp b/src/common/Settings.cpp index 0a36f8662..0faa84d7f 100644 --- a/src/common/Settings.cpp +++ b/src/common/Settings.cpp @@ -148,6 +148,8 @@ static struct { const char* type = "Type"; const char* device = "DeviceName"; const char* config = "ProfileName"; + const char *top_slot = "TopSlot"; + const char *bottom_slot = "BottomSlot"; } sect_input_port; static const char* section_input_profiles = "input-profile-"; @@ -465,15 +467,25 @@ bool Settings::LoadConfig() // ==== Input Port Begin ==== for (int port_num = 0; port_num < 4; port_num++) { + m_input_port[port_num].Type = to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID); + m_input_port[port_num].TopSlotType = to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID); + m_input_port[port_num].BottomSlotType = to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID); + std::string current_section = std::string(section_input_port) + std::to_string(port_num); int ret = m_si.GetLongValue(current_section.c_str(), sect_input_port.type, -2); if (ret == -2) { - m_input_port[port_num].Type = to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID); continue; } m_input_port[port_num].Type = ret; m_input_port[port_num].DeviceName = m_si.GetValue(current_section.c_str(), sect_input_port.device); m_input_port[port_num].ProfileName = TrimQuoteFromString(m_si.GetValue(current_section.c_str(), sect_input_port.config)); + ret = m_si.GetLongValue(current_section.c_str(), sect_input_port.top_slot, -2); + if (ret == -2) { + continue; + } + m_input_port[port_num].TopSlotType = ret; + m_input_port[port_num].BottomSlotType = m_si.GetLongValue(current_section.c_str(), sect_input_port.bottom_slot, -2); + assert(m_input_port[port_num].BottomSlotType != -2); } // ==== Input Port End ============== @@ -644,6 +656,8 @@ bool Settings::Save(std::string file_path) m_si.SetLongValue(current_section.c_str(), sect_input_port.type, m_input_port[port_num].Type, nullptr, false, true); m_si.SetValue(current_section.c_str(), sect_input_port.device, m_input_port[port_num].DeviceName.c_str(), nullptr, true); m_si.SetValue(current_section.c_str(), sect_input_port.config, quoted_prf_str.c_str(), nullptr, true); + m_si.SetLongValue(current_section.c_str(), sect_input_port.top_slot, m_input_port[port_num].TopSlotType, nullptr, false, true); + m_si.SetLongValue(current_section.c_str(), sect_input_port.bottom_slot, m_input_port[port_num].BottomSlotType, nullptr, false, true); } // ==== Input Port End ============== diff --git a/src/common/Settings.hpp b/src/common/Settings.hpp index 000ff615d..0d3da1b73 100644 --- a/src/common/Settings.hpp +++ b/src/common/Settings.hpp @@ -149,6 +149,8 @@ public: int Type; std::string DeviceName; std::string ProfileName; + int TopSlotType; + int BottomSlotType; }; std::array m_input_port; diff --git a/src/core/kernel/init/CxbxKrnl.cpp b/src/core/kernel/init/CxbxKrnl.cpp index 6babf23c0..00111d56a 100644 --- a/src/core/kernel/init/CxbxKrnl.cpp +++ b/src/core/kernel/init/CxbxKrnl.cpp @@ -96,6 +96,7 @@ char szFilePath_EEPROM_bin[MAX_PATH] = { 0 }; char szFilePath_Xbe[xbox::max_path*2] = { 0 }; // NOTE: LAUNCH_DATA_HEADER's szLaunchPath is xbox::max_path*2 = 520 std::string CxbxBasePath; +std::string MuBasePath; HANDLE CxbxBasePathHandle; Xbe* CxbxKrnl_Xbe = NULL; bool g_bIsChihiro = false; @@ -1433,11 +1434,14 @@ __declspec(noreturn) void CxbxKrnlInit char szBuffer[sizeof(szFilePath_Xbe)]; g_EmuShared->GetStorageLocation(szBuffer); + MuBasePath = std::string(szBuffer) + "\\EmuMu"; CxbxBasePath = std::string(szBuffer) + "\\EmuDisk"; CxbxResolveHostToFullPath(CxbxBasePath, "Cxbx-Reloaded's EmuDisk directory"); + CxbxResolveHostToFullPath(MuBasePath, "Cxbx-Reloaded's EmuMu directory"); // Since canonical always remove the extra slash, we need to manually add it back. // TODO: Once CxbxBasePath is filesystem::path, replace CxbxBasePath's + operators to / for include path separator internally. CxbxBasePath = std::filesystem::path(CxbxBasePath).append("").string(); + MuBasePath = std::filesystem::path(MuBasePath).append("").string(); } // Determine xbe path @@ -1505,6 +1509,17 @@ __declspec(noreturn) void CxbxKrnlInit CxbxRegisterDeviceHostPath(DeviceHarddisk0Partition7, CxbxBasePath + "Partition7"); CxbxRegisterDeviceHostPath(DevicePrefix + "\\Chihiro", CxbxBasePath + "Chihiro"); + // Create MU directories + for (unsigned i = 0; i < 8; ++i) { + std::error_code error; + static char mu_letter = 'F'; + std::string mu_path = MuBasePath + mu_letter; + if (!(std::filesystem::exists(mu_path) || std::filesystem::create_directory(mu_path, error))) { + CxbxKrnlCleanup("Failed to create memory unit directories"); + } + ++mu_letter; + } + // Create default symbolic links : EmuLogInit(LOG_LEVEL::DEBUG, "Creating default symbolic links."); { @@ -1747,6 +1762,13 @@ void CxbxInitFilePaths() CxbxKrnlCleanup("%s : Couldn't create Cxbx-Reloaded EmuDisk folder!", __func__); } + // Make sure the EmuDMu folder exists + std::string emuMu = std::string(szFolder_CxbxReloadedData) + std::string("\\EmuMu"); + result = std::filesystem::exists(emuMu); + if (!result && !std::filesystem::create_directory(emuMu)) { + CxbxKrnlCleanup("%s : Couldn't create Cxbx-Reloaded EmuMu folder!", __func__); + } + snprintf(szFilePath_EEPROM_bin, MAX_PATH, "%s\\EEPROM.bin", szFolder_CxbxReloadedData); GetModuleFileName(GetModuleHandle(nullptr), szFilePath_CxbxReloaded_Exe, MAX_PATH); diff --git a/src/core/kernel/support/EmuFile.cpp b/src/core/kernel/support/EmuFile.cpp index 682a0fd4f..c10e0cbb3 100644 --- a/src/core/kernel/support/EmuFile.cpp +++ b/src/core/kernel/support/EmuFile.cpp @@ -248,7 +248,14 @@ const std::string DriveA = DrivePrefix + "A:"; // A: could be CDROM const std::string DriveC = DrivePrefix + "C:"; // C: is HDD0 const std::string DriveD = DrivePrefix + "D:"; // D: is DVD Player const std::string DriveE = DrivePrefix + "E:"; -const std::string DriveF = DrivePrefix + "F:"; +const std::string DriveF = DrivePrefix + "F:"; // MU port 0, slot top +const std::string DriveG = DrivePrefix + "G:"; // MU port 0, slot bottom +const std::string DriveH = DrivePrefix + "H:"; // MU port 1, slot top +const std::string DriveI = DrivePrefix + "I:"; // MU port 1, slot bottom +const std::string DriveJ = DrivePrefix + "J:"; // MU port 2, slot top +const std::string DriveK = DrivePrefix + "K:"; // MU port 2, slot bottom +const std::string DriveL = DrivePrefix + "L:"; // MU port 3, slot top +const std::string DriveM = DrivePrefix + "M:"; // MU port 3, slot bottom const std::string DriveS = DrivePrefix + "S:"; const std::string DriveT = DrivePrefix + "T:"; // T: is Title persistent data region const std::string DriveU = DrivePrefix + "U:"; // U: is User persistent data region diff --git a/src/core/kernel/support/EmuFile.h b/src/core/kernel/support/EmuFile.h index 81d86d6dd..33c11bf3e 100644 --- a/src/core/kernel/support/EmuFile.h +++ b/src/core/kernel/support/EmuFile.h @@ -62,13 +62,13 @@ extern const std::string DriveC; extern const std::string DriveD; extern const std::string DriveE; extern const std::string DriveF; -extern const std::string DriveS; -extern const std::string DriveT; -extern const std::string DriveU; -extern const std::string DriveV; -extern const std::string DriveW; -extern const std::string DriveX; -extern const std::string DriveY; +extern const std::string DriveG; +extern const std::string DriveH; +extern const std::string DriveI; +extern const std::string DriveJ; +extern const std::string DriveK; +extern const std::string DriveL; +extern const std::string DriveM; extern const std::string DriveZ; extern const std::string DevicePrefix; extern const std::string DeviceCdrom0; From 1d9dc0df2dff15cf6fb3c9e4228f48fffcce3dda Mon Sep 17 00:00:00 2001 From: ergo720 <45463469+ergo720@users.noreply.github.com> Date: Sun, 13 Jun 2021 17:56:57 +0200 Subject: [PATCH 2/9] Added support to mu to input gui --- src/common/Settings.cpp | 2 + src/common/input/Button.h | 2 + src/common/input/InputManager.h | 3 + src/common/input/InputWindow.cpp | 23 +++++++ src/common/input/InputWindow.h | 11 ++- src/common/win32/EmuShared.h | 3 + src/gui/DlgInputConfig.cpp | 2 + .../controllers/DlgDukeControllerConfig.cpp | 69 +++++++++++++------ src/gui/controllers/DlgSBControllerConfig.cpp | 28 -------- src/gui/resource/Cxbx.rc | 21 ++++-- src/gui/resource/ResCxbx.h | 6 +- 11 files changed, 112 insertions(+), 58 deletions(-) diff --git a/src/common/Settings.cpp b/src/common/Settings.cpp index 0faa84d7f..60bf628b8 100644 --- a/src/common/Settings.cpp +++ b/src/common/Settings.cpp @@ -783,6 +783,8 @@ void Settings::SyncToEmulator() // register xbox device input settings for (int i = 0; i < 4; i++) { g_EmuShared->SetInputDevTypeSettings(&m_input_port[i].Type, i); + g_EmuShared->SetInputSlotTypeSettings(&m_input_port[i].TopSlotType, i, MU_SLOT_TOP); + g_EmuShared->SetInputSlotTypeSettings(&m_input_port[i].BottomSlotType, i, MU_SLOT_BOTTOM); if (m_input_port[i].Type != to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)) { g_EmuShared->SetInputDevNameSettings(m_input_port[i].DeviceName.c_str(), i); auto it = std::find_if(m_input_profiles[m_input_port[i].Type].begin(), diff --git a/src/common/input/Button.h b/src/common/input/Button.h index a74afded5..ac0658bfe 100644 --- a/src/common/input/Button.h +++ b/src/common/input/Button.h @@ -35,6 +35,8 @@ #define SBC_NUM_BUTTONS 56 #define HIGHEST_NUM_BUTTONS SBC_NUM_BUTTONS +#define MU_NUM_SLOTS 2 + #define XBOX_BUTTON_NAME_LENGTH 30 #define HOST_BUTTON_NAME_LENGTH 30 diff --git a/src/common/input/InputManager.h b/src/common/input/InputManager.h index 8edf43dd1..15ce595d7 100644 --- a/src/common/input/InputManager.h +++ b/src/common/input/InputManager.h @@ -37,6 +37,9 @@ #undef SetPort #endif +#define MU_SLOT_TOP 0 +#define MU_SLOT_BOTTOM 1 + extern int dev_num_buttons[to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX)]; inline XBOX_INPUT_DEVICE input_support_list[] = { diff --git a/src/common/input/InputWindow.cpp b/src/common/input/InputWindow.cpp index 69fcef6ed..485265758 100644 --- a/src/common/input/InputWindow.cpp +++ b/src/common/input/InputWindow.cpp @@ -177,6 +177,29 @@ void InputWindow::BindButton(int ControlID) } } +void InputWindow::UpdateProfile(const std::string &name, int command) +{ + switch (command) + { + case PROFILE_LOAD: + LoadProfile(name); + break; + + case PROFILE_SAVE: + SaveProfile(name); + break; + + case PROFILE_DELETE: + DeleteProfile(name); + break; + + case BUTTON_CLEAR: + case BUTTON_SWAP: + m_bHasChanges = true; + break; + } +} + InputWindow::ProfileIt InputWindow::FindProfile(const std::string& name) { auto it = std::find_if(g_Settings->m_input_profiles[m_dev_type].begin(), diff --git a/src/common/input/InputWindow.h b/src/common/input/InputWindow.h index e860bb52b..025c0c8a5 100644 --- a/src/common/input/InputWindow.h +++ b/src/common/input/InputWindow.h @@ -40,6 +40,7 @@ #define RUMBLE_CLEAR 7 #define BUTTON_CLEAR 8 #define BUTTON_SWAP 9 +#define SLOTS_CHANGED 10 #define XINPUT_DEFAULT 0 #define DINPUT_DEFAULT 1 @@ -58,9 +59,9 @@ public: void UpdateDeviceList(); void BindButton(int ControlID); virtual void ClearBindings() = 0; - virtual void UpdateProfile(const std::string& name, int command) = 0; + virtual void UpdateProfile(const std::string& name, int command); void UpdateCurrentDevice(); - bool IsProfileSaved(); + virtual bool IsProfileSaved(); void SwapMoCursorAxis(Button *button); @@ -106,6 +107,7 @@ public: void BindDefault(); void ClearBindings() override; void UpdateProfile(const std::string &name, int command) override; + bool IsProfileSaved() override; private: @@ -118,6 +120,10 @@ private: HWND m_hwnd_rumble; // handle of the rumble combobox HWND m_hwnd_rumble_list; + // handle of the top slot combobox + HWND m_hwnd_top_slot_list; + // handle of the bottom slot combobox + HWND m_hwnd_bottom_slot_list; // currently selected rumble control std::string m_rumble; }; @@ -127,7 +133,6 @@ class SbcInputWindow : public InputWindow public: void Initialize(HWND hwnd, int port_num, int dev_type) override; void ClearBindings() override; - void UpdateProfile(const std::string &name, int command) override; private: diff --git a/src/common/win32/EmuShared.h b/src/common/win32/EmuShared.h index 923d5f9c7..1b36b352b 100644 --- a/src/common/win32/EmuShared.h +++ b/src/common/win32/EmuShared.h @@ -135,6 +135,8 @@ class EmuShared : public Mutex // ****************************************************************** void GetInputDevTypeSettings(int* type, int port) { Lock(); *type = m_DeviceType[port]; Unlock(); } void SetInputDevTypeSettings(const int* type, int port) { Lock(); m_DeviceType[port] = *type; Unlock(); } + void GetInputSlotTypeSettings(int *type, int port, int slot) { Lock(); *type = m_SlotDeviceType[port][slot]; Unlock(); } + void SetInputSlotTypeSettings(const int *type, int port, int slot) { Lock(); m_SlotDeviceType[port][slot] = *type; Unlock(); } void GetInputDevNameSettings(char* name, int port) { Lock(); strncpy(name, m_DeviceName[port], 50); Unlock(); } void SetInputDevNameSettings(const char* name, int port) { Lock(); strncpy(m_DeviceName[port], name, 50); Unlock(); } void GetInputBindingsSettings(char button_str[][HOST_BUTTON_NAME_LENGTH], int max_num_buttons, int port) @@ -366,6 +368,7 @@ class EmuShared : public Mutex bool m_bClipCursor; unsigned int m_dwKrnlProcID; // Only used for kernel mode level. int m_DeviceType[4]; + int m_SlotDeviceType[4][MU_NUM_SLOTS]; char m_DeviceControlNames[4][HIGHEST_NUM_BUTTONS][HOST_BUTTON_NAME_LENGTH]; char m_DeviceName[4][50]; char m_TitleMountPath[xbox::max_path]; diff --git a/src/gui/DlgInputConfig.cpp b/src/gui/DlgInputConfig.cpp index b614aa38e..f3a782ec7 100644 --- a/src/gui/DlgInputConfig.cpp +++ b/src/gui/DlgInputConfig.cpp @@ -51,6 +51,8 @@ void SyncInputSettings(int port_num, int dev_type, bool is_opt) if (!is_opt) { // Sync updated input to kernel process to use run-time settings. g_EmuShared->SetInputDevTypeSettings(&g_Settings->m_input_port[port_num].Type, port_num); + g_EmuShared->SetInputSlotTypeSettings(&g_Settings->m_input_port[port_num].TopSlotType, port_num, MU_SLOT_TOP); + g_EmuShared->SetInputSlotTypeSettings(&g_Settings->m_input_port[port_num].BottomSlotType, port_num, MU_SLOT_BOTTOM); if (dev_type != to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)) { std::string dev_name = g_Settings->m_input_port[port_num].DeviceName; diff --git a/src/gui/controllers/DlgDukeControllerConfig.cpp b/src/gui/controllers/DlgDukeControllerConfig.cpp index 0eca3788e..9acbcac51 100644 --- a/src/gui/controllers/DlgDukeControllerConfig.cpp +++ b/src/gui/controllers/DlgDukeControllerConfig.cpp @@ -49,6 +49,8 @@ void DukeInputWindow::Initialize(HWND hwnd, int port_num, int dev_type) m_hwnd_device_list = GetDlgItem(m_hwnd_window, IDC_DEVICE_LIST); m_hwnd_profile_list = GetDlgItem(m_hwnd_window, IDC_PROFILE_NAME); m_hwnd_default = GetDlgItem(m_hwnd_window, IDC_DEFAULT); + m_hwnd_top_slot_list = GetDlgItem(hwnd, IDC_DEVICE_LIST_TOP_SLOT); + m_hwnd_bottom_slot_list = GetDlgItem(hwnd, IDC_DEVICE_LIST_BOTTOM_SLOT); m_dev_type = dev_type; m_max_num_buttons = dev_num_buttons[dev_type]; m_port_num = port_num; @@ -84,6 +86,24 @@ void DukeInputWindow::Initialize(HWND hwnd, int port_num, int dev_type) // Set the maximum profile name lenght the user can enter in the profile combobox SendMessage(m_hwnd_profile_list, CB_LIMITTEXT, 49, 0); + // Set up the device types we support in the slot ports + SendMessage(m_hwnd_top_slot_list, CB_ADDSTRING, 0, + reinterpret_cast(GetInputDeviceName(to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)).c_str())); + SendMessage(m_hwnd_bottom_slot_list, CB_ADDSTRING, 0, + reinterpret_cast(GetInputDeviceName(to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)).c_str())); + + if (m_dev_type != to_underlying(XBOX_INPUT_DEVICE::ARCADE_STICK)) { + SendMessage(m_hwnd_top_slot_list, CB_ADDSTRING, 0, + reinterpret_cast(GetInputDeviceName(to_underlying(XBOX_INPUT_DEVICE::MEMORY_UNIT)).c_str())); + SendMessage(m_hwnd_bottom_slot_list, CB_ADDSTRING, 0, + reinterpret_cast(GetInputDeviceName(to_underlying(XBOX_INPUT_DEVICE::MEMORY_UNIT)).c_str())); + } + else { + // The arcade joystick does not have slot ports so always disable the corresponding options + EnableWindow(m_hwnd_top_slot_list, FALSE); + EnableWindow(m_hwnd_bottom_slot_list, FALSE); + } + // construct emu device m_DeviceConfig = new EmuDevice(m_dev_type, m_hwnd_window, this); @@ -181,32 +201,16 @@ void DukeInputWindow::UpdateProfile(const std::string &name, int command) { switch (command) { - case PROFILE_LOAD: { - LoadProfile(name); - } - break; - - case PROFILE_SAVE: { - SaveProfile(name); - } - break; - - case PROFILE_DELETE: { - DeleteProfile(name); - } - break; - - case RUMBLE_CLEAR: { + case RUMBLE_CLEAR: m_rumble = std::string(); - } - break; + break; - case BUTTON_CLEAR: - case BUTTON_SWAP: { + case SLOTS_CHANGED: m_bHasChanges = true; - } - break; + break; + default: + dynamic_cast(this)->UpdateProfile(name, command); } } @@ -239,6 +243,20 @@ void DukeInputWindow::DetectOutput(int ms) } } +bool DukeInputWindow::IsProfileSaved() +{ + if (dynamic_cast(this)->IsProfileSaved()) { + int DeviceType = SendMessage(m_hwnd_top_slot_list, CB_GETITEMDATA, SendMessage(m_hwnd_top_slot_list, CB_GETCURSEL, 0, 0), 0); + g_Settings->m_input_port[m_port_num].TopSlotType = DeviceType; + DeviceType = SendMessage(m_hwnd_bottom_slot_list, CB_GETITEMDATA, SendMessage(m_hwnd_bottom_slot_list, CB_GETCURSEL, 0, 0), 0); + g_Settings->m_input_port[m_port_num].BottomSlotType = DeviceType; + + return true; + } + + return false; +} + static INT_PTR CALLBACK DlgRumbleConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); INT_PTR CALLBACK DlgXidControllerConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) @@ -284,6 +302,13 @@ INT_PTR CALLBACK DlgXidControllerConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wPar } break; + case IDC_DEVICE_LIST_TOP_SLOT: { + if (HIWORD(wParam) == CBN_SELCHANGE) { + g_InputWindow->UpdateProfile(std::string(), SLOTS_CHANGED); + } + } + break; + case IDC_PROFILE_NAME: { if (HIWORD(wParam) == CBN_SELCHANGE) { char name[50]; diff --git a/src/gui/controllers/DlgSBControllerConfig.cpp b/src/gui/controllers/DlgSBControllerConfig.cpp index e7a640c6c..37db7bd8c 100644 --- a/src/gui/controllers/DlgSBControllerConfig.cpp +++ b/src/gui/controllers/DlgSBControllerConfig.cpp @@ -81,34 +81,6 @@ void SbcInputWindow::ClearBindings() m_bHasChanges = true; } -void SbcInputWindow::UpdateProfile(const std::string &name, int command) -{ - switch (command) - { - case PROFILE_LOAD: { - LoadProfile(name); - } - break; - - case PROFILE_SAVE: { - SaveProfile(name); - } - break; - - case PROFILE_DELETE: { - DeleteProfile(name); - } - break; - - case BUTTON_CLEAR: - case BUTTON_SWAP: { - m_bHasChanges = true; - } - break; - - } -} - int SbcInputWindow::EnableDefaultButton() { // The SBC window does not have a default button, so we return a dummy value here diff --git a/src/gui/resource/Cxbx.rc b/src/gui/resource/Cxbx.rc index 75bb11375..e54afd15b 100644 --- a/src/gui/resource/Cxbx.rc +++ b/src/gui/resource/Cxbx.rc @@ -31,6 +31,10 @@ BEGIN BEGIN END + IDD_XID_DUKE_CFG, DIALOG + BEGIN + END + IDD_SBC_CFG, DIALOG BEGIN BOTTOMMARGIN, 269 @@ -113,7 +117,7 @@ BEGIN "Button",BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP,23,166,139,10 END -IDD_XID_DUKE_CFG DIALOGEX 0, 0, 528, 280 +IDD_XID_DUKE_CFG DIALOGEX 0, 0, 528, 300 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU FONT 8, "Verdana", 0, 0, 0x1 BEGIN @@ -180,8 +184,12 @@ BEGIN GROUPBOX "Rumble",IDC_RUMBLE,396,212,121,34,WS_GROUP PUSHBUTTON "",IDC_SET_MOTOR,443,224,57,14,BS_FLAT LTEXT "Motor",IDC_STATIC,412,224,26,14,SS_CENTERIMAGE - PUSHBUTTON "Default Bindings",IDC_DEFAULT,362,256,69,14,BS_FLAT - PUSHBUTTON "Clear",IDC_CLEAR,443,256,50,14,BS_FLAT + PUSHBUTTON "Default Bindings",IDC_DEFAULT,362,265,69,14,BS_FLAT + PUSHBUTTON "Clear",IDC_CLEAR,443,265,50,14,BS_FLAT + GROUPBOX "Top Slot",IDC_DEVICE_TOP_SLOT,12,254,97,35,WS_GROUP + COMBOBOX IDC_DEVICE_LIST_TOP_SLOT,21,267,79,15,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + GROUPBOX "Bottom Slot",IDC_DEVICE_BOTTOM_SLOT,117,254,97,35,WS_GROUP + COMBOBOX IDC_DEVICE_LIST_BOTTOM_SLOT,126,267,79,15,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP END IDD_RUMBLE_CFG DIALOGEX 0, 0, 155, 35 @@ -566,6 +574,11 @@ BEGIN 0 END +IDD_XID_DUKE_CFG AFX_DIALOG_LAYOUT +BEGIN + 0 +END + ///////////////////////////////////////////////////////////////////////////// // @@ -687,7 +700,7 @@ BEGIN MENUITEM "&Clear entire Symbol Cache", ID_CACHE_CLEARHLECACHE_ALL,MFT_STRING,MFS_ENABLED MENUITEM "&Rescan title Symbol Cache", ID_CACHE_CLEARHLECACHE_CURRENT,MFT_STRING,MFS_ENABLED END - MENUITEM "Clear Cache Partitions", ID_SETTINGS_CLEAR_PARTITIONS,MFT_STRING,MFS_ENABLED + MENUITEM "Clear Cache Partitions", ID_SETTINGS_CLEAR_PARTITIONS,MFT_STRING,MFS_ENABLED MENUITEM "", -1, MFT_SEPARATOR POPUP "Experimental", 65535,MFT_STRING,MFS_ENABLED BEGIN diff --git a/src/gui/resource/ResCxbx.h b/src/gui/resource/ResCxbx.h index 727aeb028..7d121167e 100644 --- a/src/gui/resource/ResCxbx.h +++ b/src/gui/resource/ResCxbx.h @@ -1,4 +1,4 @@ -//{{NO_DEPENDENCIES}} +//{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. // Used by Cxbx.rc // @@ -94,6 +94,10 @@ #define IDC_LOG_VSHCACHE 962 #define IDC_LOG_RINP 963 #define IDC_LOG_JVS 964 +#define IDC_DEVICE_LIST_TOP_SLOT 995 +#define IDC_DEVICE_LIST_BOTTOM_SLOT 996 +#define IDC_DEVICE_TOP_SLOT 997 +#define IDC_DEVICE_BOTTOM_SLOT 998 #define IDC_SET_MOTOR 999 #define IDC_SET_X 1000 #define IDC_SET_Y 1001 From 9307f816baecfd0ef95001690b9da11dda5bc478 Mon Sep 17 00:00:00 2001 From: ergo720 <45463469+ergo720@users.noreply.github.com> Date: Mon, 14 Jun 2021 07:34:46 +0200 Subject: [PATCH 3/9] Fixed some bugs in the mu handling of the gui + added XUnmountMU patch --- src/common/Settings.cpp | 4 +- src/common/input/Button.h | 2 +- src/common/input/InputManager.h | 9 ++- src/common/input/InputWindow.cpp | 17 +++-- src/common/input/InputWindow.h | 15 ++-- src/common/win32/EmuShared.h | 2 +- src/core/hle/Patches.cpp | 1 + src/core/hle/XAPI/Xapi.cpp | 21 ++++++ src/core/hle/XAPI/Xapi.h | 9 +++ src/gui/DlgInputConfig.cpp | 4 +- .../controllers/DlgDukeControllerConfig.cpp | 70 ++++++++++++------- 11 files changed, 108 insertions(+), 46 deletions(-) diff --git a/src/common/Settings.cpp b/src/common/Settings.cpp index 60bf628b8..cd3082f88 100644 --- a/src/common/Settings.cpp +++ b/src/common/Settings.cpp @@ -783,8 +783,8 @@ void Settings::SyncToEmulator() // register xbox device input settings for (int i = 0; i < 4; i++) { g_EmuShared->SetInputDevTypeSettings(&m_input_port[i].Type, i); - g_EmuShared->SetInputSlotTypeSettings(&m_input_port[i].TopSlotType, i, MU_SLOT_TOP); - g_EmuShared->SetInputSlotTypeSettings(&m_input_port[i].BottomSlotType, i, MU_SLOT_BOTTOM); + g_EmuShared->SetInputSlotTypeSettings(&m_input_port[i].TopSlotType, i, SLOT_TOP); + g_EmuShared->SetInputSlotTypeSettings(&m_input_port[i].BottomSlotType, i, SLOT_BOTTOM); if (m_input_port[i].Type != to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)) { g_EmuShared->SetInputDevNameSettings(m_input_port[i].DeviceName.c_str(), i); auto it = std::find_if(m_input_profiles[m_input_port[i].Type].begin(), diff --git a/src/common/input/Button.h b/src/common/input/Button.h index ac0658bfe..efd71b959 100644 --- a/src/common/input/Button.h +++ b/src/common/input/Button.h @@ -35,7 +35,7 @@ #define SBC_NUM_BUTTONS 56 #define HIGHEST_NUM_BUTTONS SBC_NUM_BUTTONS -#define MU_NUM_SLOTS 2 +#define XBOX_CTRL_NUM_SLOTS 2 #define XBOX_BUTTON_NAME_LENGTH 30 #define HOST_BUTTON_NAME_LENGTH 30 diff --git a/src/common/input/InputManager.h b/src/common/input/InputManager.h index 15ce595d7..9b288d8ba 100644 --- a/src/common/input/InputManager.h +++ b/src/common/input/InputManager.h @@ -37,8 +37,8 @@ #undef SetPort #endif -#define MU_SLOT_TOP 0 -#define MU_SLOT_BOTTOM 1 +#define SLOT_TOP 0 +#define SLOT_BOTTOM 1 extern int dev_num_buttons[to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX)]; @@ -50,6 +50,11 @@ inline XBOX_INPUT_DEVICE input_support_list[] = { XBOX_INPUT_DEVICE::ARCADE_STICK, }; +inline XBOX_INPUT_DEVICE slot_support_list[] = { + XBOX_INPUT_DEVICE::DEVICE_INVALID, + XBOX_INPUT_DEVICE::MEMORY_UNIT, +}; + #pragma pack(1) // xpad in/out buffers stripped of the first two bytes diff --git a/src/common/input/InputWindow.cpp b/src/common/input/InputWindow.cpp index 485265758..05b0bad3f 100644 --- a/src/common/input/InputWindow.cpp +++ b/src/common/input/InputWindow.cpp @@ -43,7 +43,7 @@ InputWindow::~InputWindow() m_DeviceConfig = nullptr; } -bool InputWindow::IsProfileSaved() +int InputWindow::IsProfileSaved() { if (m_bHasChanges) { PopupReturn ret = PopupQuestion(m_hwnd_window, "Current configuration is not saved. Save before closing?"); @@ -53,23 +53,24 @@ bool InputWindow::IsProfileSaved() char name[50]; SendMessage(m_hwnd_profile_list, WM_GETTEXT, sizeof(name), reinterpret_cast(name)); if (SaveProfile(std::string(name))) { - return true; + return EXIT_SAVE; } - return false; + return EXIT_ABORT; } case PopupReturn::No: { - return true; + return EXIT_IGNORE; } case PopupReturn::Cancel: default: { - return false; + return EXIT_ABORT; } } } - return true; + + return EXIT_IGNORE; } void InputWindow::UpdateDeviceList() @@ -259,6 +260,10 @@ bool InputWindow::SaveProfile(const std::string& name) g_Settings->m_input_port[m_port_num].DeviceName = profile.DeviceName; g_Settings->m_input_port[m_port_num].ProfileName = profile.ProfileName; g_Settings->m_input_profiles[m_dev_type].push_back(std::move(profile)); + if (auto duke_wnd = dynamic_cast(this)) { + duke_wnd->SaveSlotConfig(); + } + m_bHasChanges = false; return true; } diff --git a/src/common/input/InputWindow.h b/src/common/input/InputWindow.h index 025c0c8a5..cbad576d4 100644 --- a/src/common/input/InputWindow.h +++ b/src/common/input/InputWindow.h @@ -42,6 +42,10 @@ #define BUTTON_SWAP 9 #define SLOTS_CHANGED 10 +#define EXIT_ABORT 0 +#define EXIT_SAVE 1 +#define EXIT_IGNORE 2 + #define XINPUT_DEFAULT 0 #define DINPUT_DEFAULT 1 @@ -61,7 +65,7 @@ public: virtual void ClearBindings() = 0; virtual void UpdateProfile(const std::string& name, int command); void UpdateCurrentDevice(); - virtual bool IsProfileSaved(); + virtual int IsProfileSaved(); void SwapMoCursorAxis(Button *button); @@ -107,7 +111,8 @@ public: void BindDefault(); void ClearBindings() override; void UpdateProfile(const std::string &name, int command) override; - bool IsProfileSaved() override; + int IsProfileSaved() override; + void SaveSlotConfig(); private: @@ -120,10 +125,8 @@ private: HWND m_hwnd_rumble; // handle of the rumble combobox HWND m_hwnd_rumble_list; - // handle of the top slot combobox - HWND m_hwnd_top_slot_list; - // handle of the bottom slot combobox - HWND m_hwnd_bottom_slot_list; + // handles of the slot combobox + HWND m_hwnd_slot_list[2]; // currently selected rumble control std::string m_rumble; }; diff --git a/src/common/win32/EmuShared.h b/src/common/win32/EmuShared.h index 1b36b352b..aff5a810e 100644 --- a/src/common/win32/EmuShared.h +++ b/src/common/win32/EmuShared.h @@ -368,7 +368,7 @@ class EmuShared : public Mutex bool m_bClipCursor; unsigned int m_dwKrnlProcID; // Only used for kernel mode level. int m_DeviceType[4]; - int m_SlotDeviceType[4][MU_NUM_SLOTS]; + int m_SlotDeviceType[4][XBOX_CTRL_NUM_SLOTS]; char m_DeviceControlNames[4][HIGHEST_NUM_BUTTONS][HOST_BUTTON_NAME_LENGTH]; char m_DeviceName[4][50]; char m_TitleMountPath[xbox::max_path]; diff --git a/src/core/hle/Patches.cpp b/src/core/hle/Patches.cpp index 7fa2bb3f3..9e113068e 100644 --- a/src/core/hle/Patches.cpp +++ b/src/core/hle/Patches.cpp @@ -365,6 +365,7 @@ std::map g_PatchTable = { PATCH_ENTRY("XSetProcessQuantumLength", xbox::EMUPATCH(XSetProcessQuantumLength), PATCH_ALWAYS), PATCH_ENTRY("timeKillEvent", xbox::EMUPATCH(timeKillEvent), PATCH_ALWAYS), PATCH_ENTRY("timeSetEvent", xbox::EMUPATCH(timeSetEvent), PATCH_ALWAYS), + PATCH_ENTRY("XUnmountMU", xbox::EMUPATCH(XUnmountMU), PATCH_ALWAYS), }; std::unordered_map g_FunctionHooks; diff --git a/src/core/hle/XAPI/Xapi.cpp b/src/core/hle/XAPI/Xapi.cpp index 6498d6e51..39d5ca233 100644 --- a/src/core/hle/XAPI/Xapi.cpp +++ b/src/core/hle/XAPI/Xapi.cpp @@ -1238,6 +1238,27 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(XMountMURootA) RETURN(ERROR_SUCCESS); } +// ****************************************************************** +// * patch: XUnmountMU +// ****************************************************************** +xbox::dword_xt WINAPI xbox::EMUPATCH(XUnmountMU) +( + dword_xt dwPort, + dword_xt dwSlot +) +{ + + + LOG_FUNC_BEGIN + LOG_FUNC_ARG(dwPort) + LOG_FUNC_ARG(dwSlot) + LOG_FUNC_END; + + LOG_UNIMPLEMENTED(); + + RETURN(ERROR_SUCCESS); +} + // ****************************************************************** // * patch: OutputDebugStringA // ****************************************************************** diff --git a/src/core/hle/XAPI/Xapi.h b/src/core/hle/XAPI/Xapi.h index 6beb91c8a..3902fd71e 100644 --- a/src/core/hle/XAPI/Xapi.h +++ b/src/core/hle/XAPI/Xapi.h @@ -684,6 +684,15 @@ xbox::dword_xt WINAPI EMUPATCH(XMountMURootA) PCHAR pchDrive ); +// ****************************************************************** +// * patch: XUnmountMU +// ****************************************************************** +xbox::dword_xt WINAPI EMUPATCH(XUnmountMU) +( + dword_xt dwPort, + dword_xt dwSlot +); + // ****************************************************************** // * patch: XMountAlternateTitleA // ****************************************************************** diff --git a/src/gui/DlgInputConfig.cpp b/src/gui/DlgInputConfig.cpp index f3a782ec7..744e809ad 100644 --- a/src/gui/DlgInputConfig.cpp +++ b/src/gui/DlgInputConfig.cpp @@ -51,8 +51,8 @@ void SyncInputSettings(int port_num, int dev_type, bool is_opt) if (!is_opt) { // Sync updated input to kernel process to use run-time settings. g_EmuShared->SetInputDevTypeSettings(&g_Settings->m_input_port[port_num].Type, port_num); - g_EmuShared->SetInputSlotTypeSettings(&g_Settings->m_input_port[port_num].TopSlotType, port_num, MU_SLOT_TOP); - g_EmuShared->SetInputSlotTypeSettings(&g_Settings->m_input_port[port_num].BottomSlotType, port_num, MU_SLOT_BOTTOM); + g_EmuShared->SetInputSlotTypeSettings(&g_Settings->m_input_port[port_num].TopSlotType, port_num, SLOT_TOP); + g_EmuShared->SetInputSlotTypeSettings(&g_Settings->m_input_port[port_num].BottomSlotType, port_num, SLOT_BOTTOM); if (dev_type != to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)) { std::string dev_name = g_Settings->m_input_port[port_num].DeviceName; diff --git a/src/gui/controllers/DlgDukeControllerConfig.cpp b/src/gui/controllers/DlgDukeControllerConfig.cpp index 9acbcac51..09576cca4 100644 --- a/src/gui/controllers/DlgDukeControllerConfig.cpp +++ b/src/gui/controllers/DlgDukeControllerConfig.cpp @@ -49,8 +49,8 @@ void DukeInputWindow::Initialize(HWND hwnd, int port_num, int dev_type) m_hwnd_device_list = GetDlgItem(m_hwnd_window, IDC_DEVICE_LIST); m_hwnd_profile_list = GetDlgItem(m_hwnd_window, IDC_PROFILE_NAME); m_hwnd_default = GetDlgItem(m_hwnd_window, IDC_DEFAULT); - m_hwnd_top_slot_list = GetDlgItem(hwnd, IDC_DEVICE_LIST_TOP_SLOT); - m_hwnd_bottom_slot_list = GetDlgItem(hwnd, IDC_DEVICE_LIST_BOTTOM_SLOT); + m_hwnd_slot_list[SLOT_TOP] = GetDlgItem(hwnd, IDC_DEVICE_LIST_TOP_SLOT); + m_hwnd_slot_list[SLOT_BOTTOM] = GetDlgItem(hwnd, IDC_DEVICE_LIST_BOTTOM_SLOT); m_dev_type = dev_type; m_max_num_buttons = dev_num_buttons[dev_type]; m_port_num = port_num; @@ -86,22 +86,27 @@ void DukeInputWindow::Initialize(HWND hwnd, int port_num, int dev_type) // Set the maximum profile name lenght the user can enter in the profile combobox SendMessage(m_hwnd_profile_list, CB_LIMITTEXT, 49, 0); - // Set up the device types we support in the slot ports - SendMessage(m_hwnd_top_slot_list, CB_ADDSTRING, 0, - reinterpret_cast(GetInputDeviceName(to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)).c_str())); - SendMessage(m_hwnd_bottom_slot_list, CB_ADDSTRING, 0, - reinterpret_cast(GetInputDeviceName(to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)).c_str())); - - if (m_dev_type != to_underlying(XBOX_INPUT_DEVICE::ARCADE_STICK)) { - SendMessage(m_hwnd_top_slot_list, CB_ADDSTRING, 0, - reinterpret_cast(GetInputDeviceName(to_underlying(XBOX_INPUT_DEVICE::MEMORY_UNIT)).c_str())); - SendMessage(m_hwnd_bottom_slot_list, CB_ADDSTRING, 0, - reinterpret_cast(GetInputDeviceName(to_underlying(XBOX_INPUT_DEVICE::MEMORY_UNIT)).c_str())); + if (m_dev_type == to_underlying(XBOX_INPUT_DEVICE::ARCADE_STICK)) { + // The arcade joystick does not have slot ports so we always disable the corresponding options + EnableWindow(m_hwnd_slot_list[SLOT_TOP], FALSE); + EnableWindow(m_hwnd_slot_list[SLOT_BOTTOM], FALSE); } else { - // The arcade joystick does not have slot ports so always disable the corresponding options - EnableWindow(m_hwnd_top_slot_list, FALSE); - EnableWindow(m_hwnd_bottom_slot_list, FALSE); + // Set up the device types we support in the slot ports + for (auto slot_type : slot_support_list) { + LRESULT index_top = SendMessage(m_hwnd_slot_list[SLOT_TOP], CB_ADDSTRING, 0, + reinterpret_cast(GetInputDeviceName(to_underlying(slot_type)).c_str())); + LRESULT index_bottom = SendMessage(m_hwnd_slot_list[SLOT_BOTTOM], CB_ADDSTRING, 0, + reinterpret_cast(GetInputDeviceName(to_underlying(slot_type)).c_str())); + SendMessage(m_hwnd_slot_list[SLOT_TOP], CB_SETITEMDATA, index_top, to_underlying(slot_type)); + SendMessage(m_hwnd_slot_list[SLOT_BOTTOM], CB_SETITEMDATA, index_bottom, to_underlying(slot_type)); + if (g_Settings->m_input_port[m_port_num].TopSlotType == to_underlying(slot_type)) { + SendMessage(m_hwnd_slot_list[SLOT_TOP], CB_SETCURSEL, index_top, 0); + } + if (g_Settings->m_input_port[m_port_num].BottomSlotType == to_underlying(slot_type)) { + SendMessage(m_hwnd_slot_list[SLOT_BOTTOM], CB_SETCURSEL, index_bottom, 0); + } + } } // construct emu device @@ -210,7 +215,7 @@ void DukeInputWindow::UpdateProfile(const std::string &name, int command) break; default: - dynamic_cast(this)->UpdateProfile(name, command); + InputWindow::UpdateProfile(name, command); } } @@ -243,18 +248,30 @@ void DukeInputWindow::DetectOutput(int ms) } } -bool DukeInputWindow::IsProfileSaved() +int DukeInputWindow::IsProfileSaved() { - if (dynamic_cast(this)->IsProfileSaved()) { - int DeviceType = SendMessage(m_hwnd_top_slot_list, CB_GETITEMDATA, SendMessage(m_hwnd_top_slot_list, CB_GETCURSEL, 0, 0), 0); - g_Settings->m_input_port[m_port_num].TopSlotType = DeviceType; - DeviceType = SendMessage(m_hwnd_bottom_slot_list, CB_GETITEMDATA, SendMessage(m_hwnd_bottom_slot_list, CB_GETCURSEL, 0, 0), 0); - g_Settings->m_input_port[m_port_num].BottomSlotType = DeviceType; + if (int ret = InputWindow::IsProfileSaved()) { + if (ret == EXIT_IGNORE) { + return EXIT_IGNORE; + } + else { + if (m_dev_type != to_underlying(XBOX_INPUT_DEVICE::ARCADE_STICK)) { + SaveSlotConfig(); + } - return true; + return EXIT_SAVE; + } } - return false; + return EXIT_ABORT; +} + +void DukeInputWindow::SaveSlotConfig() +{ + int DeviceType = SendMessage(m_hwnd_slot_list[SLOT_TOP], CB_GETITEMDATA, SendMessage(m_hwnd_slot_list[SLOT_TOP], CB_GETCURSEL, 0, 0), 0); + g_Settings->m_input_port[m_port_num].TopSlotType = DeviceType; + DeviceType = SendMessage(m_hwnd_slot_list[SLOT_BOTTOM], CB_GETITEMDATA, SendMessage(m_hwnd_slot_list[SLOT_BOTTOM], CB_GETCURSEL, 0, 0), 0); + g_Settings->m_input_port[m_port_num].BottomSlotType = DeviceType; } static INT_PTR CALLBACK DlgRumbleConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); @@ -302,7 +319,8 @@ INT_PTR CALLBACK DlgXidControllerConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wPar } break; - case IDC_DEVICE_LIST_TOP_SLOT: { + case IDC_DEVICE_LIST_TOP_SLOT: + case IDC_DEVICE_LIST_BOTTOM_SLOT: { if (HIWORD(wParam) == CBN_SELCHANGE) { g_InputWindow->UpdateProfile(std::string(), SLOTS_CHANGED); } From 2e9546a20aebced34fb064d38f81b5e9f60ef64d Mon Sep 17 00:00:00 2001 From: ergo720 <45463469+ergo720@users.noreply.github.com> Date: Wed, 16 Jun 2021 16:47:08 +0200 Subject: [PATCH 4/9] Added support to MUs to input manager --- import/XbSymbolDatabase | 2 +- src/common/input/InputDevice.cpp | 56 ++ src/common/input/InputDevice.h | 17 +- src/common/input/InputManager.cpp | 296 +++++----- src/common/input/InputManager.h | 88 +-- src/common/input/SdlJoystick.cpp | 10 +- src/common/input/SdlJoystick.h | 6 + src/core/hle/XAPI/Xapi.cpp | 532 ++++++++++++------ src/gui/DlgInputConfig.cpp | 13 +- .../controllers/DlgDukeControllerConfig.cpp | 2 +- src/gui/controllers/DlgSBControllerConfig.cpp | 2 +- 11 files changed, 629 insertions(+), 395 deletions(-) diff --git a/import/XbSymbolDatabase b/import/XbSymbolDatabase index c2fe7365a..9a411fea5 160000 --- a/import/XbSymbolDatabase +++ b/import/XbSymbolDatabase @@ -1 +1 @@ -Subproject commit c2fe7365adae51ffabd9fe318ecdfaeac2cbe097 +Subproject commit 9a411fea58d97f4abe49e08893c57d6d9ff7f666 diff --git a/src/common/input/InputDevice.cpp b/src/common/input/InputDevice.cpp index f00ec285d..dd39cdeb1 100644 --- a/src/common/input/InputDevice.cpp +++ b/src/common/input/InputDevice.cpp @@ -35,6 +35,7 @@ #include "InputDevice.h" #include "common\util\CxbxUtil.h" #include +#include std::string GetInputDeviceName(int dev_type) @@ -90,6 +91,33 @@ std::string GetInputDeviceName(int dev_type) return str; } +std::string PortUserFormat(std::string_view port) +{ + int port1, slot; + PortStr2Int(port, &port1, &slot); + ++port1; + if (slot != PORT_INVALID) { + ++slot; + return std::to_string(port1) + "." + std::to_string(slot); + } + else { + return std::to_string(port1); + } +} + +void PortStr2Int(std::string_view port, int *port1, int *slot) +{ + *slot = PORT_INVALID; + auto &ret = std::from_chars(port.data(), port.data() + port.size(), *port1); + assert(ret.ec != std::errc::invalid_argument); + if (ret.ptr != port.data() + port.size()) { + ++ret.ptr; + ret = std::from_chars(ret.ptr, port.data() + port.size(), *slot); + assert(ret.ec != std::errc::invalid_argument); + assert(ret.ptr == port.data() + port.size()); + } +} + // Destructor, delete all inputs/outputs on device destruction InputDevice::~InputDevice() { @@ -130,3 +158,31 @@ const std::vector InputDevice::GetIoControls() }); return vec; } + +void InputDevice::SetPort(std::string_view Port, bool Connect) +{ + if (Connect) { + m_XboxPort.emplace_back(Port); + } + else { + const auto &it = FindPort(Port); + if (it != m_XboxPort.end()) { + m_XboxPort.erase(it); + } + } +} + +bool InputDevice::GetPort(std::string_view Port) const +{ + return FindPort(Port) != m_XboxPort.end() ? true : false; +} + +const auto InputDevice::FindPort(std::string_view Port) const +{ + return std::find_if(m_XboxPort.begin(), m_XboxPort.end(), [Port](std::string_view Port1) { + if (Port1 == Port) { + return true; + } + return false; + }); +} diff --git a/src/common/input/InputDevice.h b/src/common/input/InputDevice.h index c0c8cbcef..1438d61e2 100644 --- a/src/common/input/InputDevice.h +++ b/src/common/input/InputDevice.h @@ -42,9 +42,6 @@ #define PORT_3 2 #define PORT_4 3 -#define PORT_INC(port) ((port) + 1) -#define PORT_DEC(port) ((port) - 1) - #define DIRECTION_IN 0 #define DIRECTION_OUT 1 @@ -75,8 +72,12 @@ inline bool g_bIsTrackingMoMove = false; // Lookup array used to translate a gui port to an xbox usb port and vice versa extern int Gui2XboxPortArray[4]; -// Global function used to retrieve the printable name of a xid type +// Retrieves the printable name of a xid type std::string GetInputDeviceName(int dev_type); +// Converts the port number in the user format +std::string PortUserFormat(std::string_view); +// Extracts port and slot number from a port formatted as a string +void PortStr2Int(std::string_view port, int *port1, int *slot); /* Abstract class which represents a host device usable for input/output */ class InputDevice @@ -124,9 +125,9 @@ public: // sets the ID of this device void SetId(int ID) { m_ID = ID; } // retrieves the port this device is attached to - bool GetPort(int Port) const { return m_XboxPort[Port]; } + bool GetPort(std::string_view Port) const; // sets the port this device is attached to - void SetPort(int Port, bool Connect) { m_XboxPort[Port] = Connect; } + void SetPort(std::string_view Port, bool Connect); protected: @@ -134,6 +135,8 @@ protected: void AddInput(Input* const In); // adds an output control to the device void AddOutput(Output* const Out); + // searches for a port + const auto FindPort(std::string_view Port) const; // indicates that the device has new input data available bool m_bDirty; // lock for the bindings map @@ -159,7 +162,7 @@ private: // all the output controls detected and usable on this device std::vector m_Outputs; // xbox port(s) this device is attached to - bool m_XboxPort[4] = { false, false, false, false }; + std::vector m_XboxPort; // button bindings to the xbox device buttons std::map m_Bindings; }; diff --git a/src/common/input/InputManager.cpp b/src/common/input/InputManager.cpp index 7bab6f1b5..3167d554b 100644 --- a/src/common/input/InputManager.cpp +++ b/src/common/input/InputManager.cpp @@ -47,6 +47,7 @@ #include "EmuShared.h" #include "devices\usb\OHCI.h" #include "core/common/video/RenderBase.hpp" +#include // hle input specific #include "core\hle\XAPI\Xapi.h" @@ -69,7 +70,7 @@ int dev_num_buttons[to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX)] = { XBOX_CTRL_NUM_BUTTONS, // ARCADE_STICK }; -extern CXBX_CONTROLLER_HOST_BRIDGE g_XboxControllerHostBridge[4]; // hle xinput +void UpdateXppState(DeviceState *dev, XBOX_INPUT_DEVICE type, std::string_view port); InputDeviceManager g_InputDeviceManager; @@ -108,10 +109,41 @@ void InputDeviceManager::Initialize(bool is_gui, HWND hwnd) RefreshDevices(); if (!is_gui) { - UpdateDevices(PORT_1, false); - UpdateDevices(PORT_2, false); - UpdateDevices(PORT_3, false); - UpdateDevices(PORT_4, false); + for (unsigned i = 0; i < 12; ++i) { + g_devs[i].type = XBOX_INPUT_DEVICE::DEVICE_INVALID; + g_devs[i].port = std::to_string(PORT_INVALID); + } + + for (unsigned i = 0; i < 4; ++i) { + int type; + g_EmuShared->GetInputDevTypeSettings(&type, i); + std::string port = std::to_string(i); + if (type != to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)) { + switch (type) + { + case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE): + case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_S): { + ConstructHleInputDevice(&g_devs[CTRL_OFFSET + i], nullptr, type, port); + for (unsigned slot = 0; slot < XBOX_CTRL_NUM_SLOTS; ++slot) { + g_EmuShared->GetInputSlotTypeSettings(&type, i, slot); + if (type != to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)) { + assert(type == to_underlying(XBOX_INPUT_DEVICE::MEMORY_UNIT)); + ConstructHleInputDevice(&g_devs[MU_OFFSET + slot], &g_devs[CTRL_OFFSET + i], type, port + std::to_string(slot)); + } + } + } + break; + + case to_underlying(XBOX_INPUT_DEVICE::ARCADE_STICK): + case to_underlying(XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER): + ConstructHleInputDevice(&g_devs[CTRL_OFFSET + i], nullptr, type, port); + break; + + default: + assert(0); + } + } + } } RawInput::IgnoreHotplug = false; @@ -188,164 +220,107 @@ void InputDeviceManager::RemoveDevice(std::function Ca } } -void InputDeviceManager::UpdateDevices(int port, bool ack) +void InputDeviceManager::UpdateDevices(std::string_view port, bool ack) { - if (port > PORT_4 || port < PORT_1) { - EmuLog(LOG_LEVEL::WARNING, "Invalid port number. The port was %d", PORT_INC(port)); - return; - } - int type; -#if 0 // lle usb - int usb_port = PORT_DEC(Gui2XboxPortArray[port]); -#else - int usb_port = port; -#endif - g_EmuShared->GetInputDevTypeSettings(&type, port); + DeviceState *dev, *upstream; + int port1, type, slot; + dev = &g_devs[port1]; + PortStr2Int(port, &port1, &slot); + if (slot == PORT_INVALID) { // Port references a device attached to an xbox port + upstream = nullptr; + g_EmuShared->GetInputDevTypeSettings(&type, port1); + } + else { // Port references a device attached to a slot port + assert(dev->type == XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE || + dev->type == XBOX_INPUT_DEVICE::MS_CONTROLLER_S); + upstream = dev; + dev = dev->info.ctrl.slots[slot]; + g_EmuShared->GetInputSlotTypeSettings(&type, port1, slot); + } + + // connect slot + if (dev == nullptr) { + ConnectDevice(&g_devs[MU_OFFSET + port1 + slot], upstream, type, port); + } // connect - if (type != to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID) && - //g_XidDeviceObjArray[usb_port].xid_dev == nullptr) { lle usb - g_XboxControllerHostBridge[usb_port].XboxType == XBOX_INPUT_DEVICE::DEVICE_INVALID) { - ConnectDevice(port, usb_port, type); + else if (type != to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID) && + dev->type == XBOX_INPUT_DEVICE::DEVICE_INVALID) { + ConnectDevice(dev, upstream, type, port); } // disconnect else if (type == to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID) && - //g_XidDeviceObjArray[usb_port].xid_dev != nullptr) { lle usb - g_XboxControllerHostBridge[usb_port].XboxType != XBOX_INPUT_DEVICE::DEVICE_INVALID) { - DisconnectDevice(port, usb_port, ack); + dev->type != XBOX_INPUT_DEVICE::DEVICE_INVALID) { + // We don't need to check of we need to destroy child devices because the UpdateInputEvent_t message always + // calls us on the entire slot connectivity if the device has slots available + DisconnectDevice(dev, port, ack); } // update bindings else { - auto dev = g_InputDeviceManager.FindDevice(usb_port, 0); - if (dev != nullptr) { - dev->SetPort(usb_port, false); + auto dev1 = g_InputDeviceManager.FindDevice(port); + if (dev1 != nullptr) { + dev1->SetPort(port, false); } if (type != to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)) { - if (type != to_underlying(g_XboxControllerHostBridge[port].XboxType)) { - // this will happen when the user changes the type of an existing xbox device type connected to a port - if (g_XboxControllerHostBridge[port].bPendingRemoval == false) { - g_XboxControllerHostBridge[port].bPendingRemoval = true; + if (type != to_underlying(dev->type)) { + // This will happen when the user changes the type of an existing xbox device type connected to a port. + // We don't need to check of we need to destroy child devices because the UpdateInputEvent_t message always + // calls us on the entire slot connectivity if the device has slots available + if (dev->bPendingRemoval == false) { + dev->bPendingRemoval = true; return; } else { - DestructHleInputDevice(port); - if (!ConstructHleInputDevice(type, port)) { - return; - } + DestructHleInputDevice(dev); + ConstructHleInputDevice(dev, upstream, type, port); } } - BindHostDevice(port, usb_port, type); + BindHostDevice(type, port); } } } -void InputDeviceManager::ConnectDevice(int port, int usb_port, int type) +void InputDeviceManager::ConnectDevice(DeviceState *dev, DeviceState *upstream, int type, std::string_view port) { -#if 0 // lle usb - switch (type) - { - case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE): { - if (ConstructHub(usb_port)) { - if (!ConstructXpadDuke(usb_port)) { - DestructHub(usb_port); - return; - } - g_XidDeviceObjArray[usb_port].xid_type = type; - EmuLog(LOG_LEVEL::INFO, "Attached device %s to port %d", GetInputDeviceName(type).c_str(), PORT_INC(port)); - } - } - break; - - case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_S): - case to_underlying(XBOX_INPUT_DEVICE::LIGHT_GUN): - case to_underlying(XBOX_INPUT_DEVICE::STEERING_WHEEL): - case to_underlying(XBOX_INPUT_DEVICE::MEMORY_UNIT): - case to_underlying(XBOX_INPUT_DEVICE::IR_DONGLE): - case to_underlying(XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER): { - EmuLog(LOG_LEVEL::INFO, "%s: device %s is not yet supported", __func__, GetInputDeviceName(type).c_str()); - return; - } - - default: - EmuLog(LOG_LEVEL::WARNING, "Attempted to attach an unknown device type (type was %d)", type); - return; - } -#else - if (!ConstructHleInputDevice(type, port)) { - return; - } - EmuLog(LOG_LEVEL::INFO, "Attached device %s to port %d", GetInputDeviceName(type).c_str(), PORT_INC(port)); -#endif - BindHostDevice(port, usb_port, type); + ConstructHleInputDevice(dev, upstream, type, port); + BindHostDevice(type, port); + EmuLog(LOG_LEVEL::INFO, "Attached device %s to port %d", GetInputDeviceName(type).c_str(), + PortUserFormat(port).c_str()); } -void InputDeviceManager::DisconnectDevice(int port, int usb_port, bool ack) +void InputDeviceManager::DisconnectDevice(DeviceState *dev, std::string_view port, bool ack) { -#if 0 // lle usb - if (g_XidDeviceObjArray[usb_port].xid_dev != nullptr) { - int type = g_XidDeviceObjArray[usb_port].xid_type; - - switch (type) - { - case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE): { - if (ack) { - assert(g_HubObjArray[usb_port] != nullptr); - DestructHub(usb_port); - DestructXpadDuke(usb_port); - g_HostController->OHCI_SetRemovalFlag(usb_port, false); - EmuLog(LOG_LEVEL::INFO, "Detached device %s from port %d", GetInputDeviceName(type).c_str(), PORT_INC(port)); - } - else { - g_HostController->OHCI_SetRemovalFlag(usb_port, true); - } - } - break; - - case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_S): - case to_underlying(XBOX_INPUT_DEVICE::LIGHT_GUN): - case to_underlying(XBOX_INPUT_DEVICE::STEERING_WHEEL): - case to_underlying(XBOX_INPUT_DEVICE::MEMORY_UNIT): - case to_underlying(XBOX_INPUT_DEVICE::IR_DONGLE): - case to_underlying(XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER): { - EmuLog(LOG_LEVEL::INFO, "%s: device %s is not yet supported", __func__, GetInputDeviceName(type).c_str()); - return; - } - - default: - EmuLog(LOG_LEVEL::WARNING, "Attempted to detach an unknown device type (type was %d)", type); - return; - } -#endif - if (g_XboxControllerHostBridge[port].XboxType != XBOX_INPUT_DEVICE::DEVICE_INVALID) { - if (ack) { - int type = to_underlying(g_XboxControllerHostBridge[port].XboxType); - DestructHleInputDevice(port); - EmuLog(LOG_LEVEL::INFO, "Detached device %s from port %d", GetInputDeviceName(type).c_str(), PORT_INC(port)); - } - else { - g_XboxControllerHostBridge[port].bPendingRemoval = true; - } - auto dev = g_InputDeviceManager.FindDevice(usb_port, 0); - if (dev != nullptr) { - dev->SetPort(usb_port, false); - } + if (ack) { + int type = to_underlying(dev->type); + DestructHleInputDevice(dev); + EmuLog(LOG_LEVEL::INFO, "Detached device %s from port %d", GetInputDeviceName(type).c_str(), PortUserFormat(port).c_str()); } else { - EmuLog(LOG_LEVEL::WARNING, "Attempted to detach a device not attached to the emulated machine"); + dev->bPendingRemoval = true; + } + auto dev1 = g_InputDeviceManager.FindDevice(port); + if (dev1 != nullptr) { + dev1->SetPort(port, false); } } -void InputDeviceManager::BindHostDevice(int port, int usb_port, int type) +void InputDeviceManager::BindHostDevice(int type, std::string_view port) { + if (type == to_underlying(XBOX_INPUT_DEVICE::MEMORY_UNIT)) { + // MUs don't have any host device bound, so we just return + return; + } + char dev_name[50]; char dev_control_names[HIGHEST_NUM_BUTTONS][HOST_BUTTON_NAME_LENGTH]; - - g_EmuShared->GetInputDevNameSettings(dev_name, port); - g_EmuShared->GetInputBindingsSettings(dev_control_names, dev_num_buttons[type], port); + int port1, slot; + PortStr2Int(port, &port1, &slot); + g_EmuShared->GetInputDevNameSettings(dev_name, port1); + g_EmuShared->GetInputBindingsSettings(dev_control_names, dev_num_buttons[type], port1); auto dev = FindDevice(std::string(dev_name)); if (dev != nullptr) { - std::vector controls = dev->GetIoControls(); + std::vector controls = dev->GetIoControls(); for (int index = 0; index < dev_num_buttons[type]; index++) { std::string dev_button(dev_control_names[index]); auto it = std::find_if(controls.begin(), controls.end(), [&dev_button](const auto control) { @@ -356,54 +331,53 @@ void InputDeviceManager::BindHostDevice(int port, int usb_port, int type) }); dev->SetBindings(index, (it != controls.end()) ? *it : nullptr); } - dev->SetPort(usb_port, true); + dev->SetPort(port, true); } } -bool InputDeviceManager::UpdateXboxPortInput(int usb_port, void* Buffer, int Direction, int xid_type) +bool InputDeviceManager::UpdateXboxPortInput(int port, void* buffer, int direction, int type) { - assert(Direction == DIRECTION_IN || Direction == DIRECTION_OUT); - assert(xid_type > to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID) && - xid_type < to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX)); + assert(direction == DIRECTION_IN || direction == DIRECTION_OUT); + assert(type > to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID) && + type < to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX)); bool has_changed = false; // First check if ImGui is focus, then ignore any input update occur. // If somebody else is currently holding the lock, we won't wait and instead report no input changes if (!g_renderbase->IsImGuiFocus() && m_Mtx.try_lock()) { - for (auto &dev_ptr : m_Devices) { - if (dev_ptr->GetPort(usb_port)) { - switch (xid_type) + for (auto &dev : m_Devices) { + if (dev->GetPort(std::to_string(port))) { + switch (type) { case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE): case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_S): - case to_underlying(XBOX_INPUT_DEVICE::ARCADE_STICK): { - has_changed = UpdateInputXpad(dev_ptr, Buffer, Direction); - } - break; + case to_underlying(XBOX_INPUT_DEVICE::ARCADE_STICK): + has_changed = UpdateInputXpad(dev, buffer, direction); + m_Mtx.unlock(); + return has_changed; - case to_underlying(XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER): { - has_changed = UpdateInputSBC(dev_ptr, Buffer, Direction, usb_port); - } - break; + case to_underlying(XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER): + has_changed = UpdateInputSBC(dev, buffer, direction, port); + m_Mtx.unlock(); + return has_changed; + + case to_underlying(XBOX_INPUT_DEVICE::MEMORY_UNIT): + assert(0); + break; case to_underlying(XBOX_INPUT_DEVICE::LIGHT_GUN): case to_underlying(XBOX_INPUT_DEVICE::STEERING_WHEEL): - case to_underlying(XBOX_INPUT_DEVICE::MEMORY_UNIT): - case to_underlying(XBOX_INPUT_DEVICE::IR_DONGLE): { - EmuLog(LOG_LEVEL::WARNING, "An unsupported device is attached at port %d! The device was %s", - Gui2XboxPortArray[usb_port], GetInputDeviceName(xid_type).c_str()); - } - break; + case to_underlying(XBOX_INPUT_DEVICE::IR_DONGLE): + EmuLog(LOG_LEVEL::ERROR2, "An unsupported device is attached at port %d! The device was %s", + Gui2XboxPortArray[port], GetInputDeviceName(type).c_str()); + break; - default: { - EmuLog(LOG_LEVEL::WARNING, "An unknown device attached at port %d! The type was %s", - Gui2XboxPortArray[usb_port], GetInputDeviceName(xid_type).c_str()); - } } } } m_Mtx.unlock(); } + return has_changed; } @@ -690,18 +664,12 @@ std::shared_ptr InputDeviceManager::FindDevice(SDL_JoystickID id) c } } -std::shared_ptr InputDeviceManager::FindDevice(int usb_port, int dummy) const +std::shared_ptr InputDeviceManager::FindDevice(std::string_view port) const { - // Ignore dummy, it's just used to overload the function - - if (usb_port == PORT_INVALID) { - return nullptr; - } - std::lock_guard lck(m_Mtx); - auto it = std::find_if(m_Devices.begin(), m_Devices.end(), [usb_port](const auto& Device) { - return Device->GetPort(usb_port); + auto it = std::find_if(m_Devices.begin(), m_Devices.end(), [port](const auto& Device) { + return Device->GetPort(port); }); if (it != m_Devices.end()) { return *it; @@ -762,7 +730,7 @@ void InputDeviceManager::HotplugHandler(bool is_sdl) int type; g_EmuShared->GetInputDevTypeSettings(&type, port); if (type != to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)) { - BindHostDevice(port, port, type); + BindHostDevice(type, std::to_string(port)); } } } diff --git a/src/common/input/InputManager.h b/src/common/input/InputManager.h index 9b288d8ba..e3ae3c5a0 100644 --- a/src/common/input/InputManager.h +++ b/src/common/input/InputManager.h @@ -40,6 +40,9 @@ #define SLOT_TOP 0 #define SLOT_BOTTOM 1 +#define CTRL_OFFSET 0 +#define MU_OFFSET 4 + extern int dev_num_buttons[to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX)]; inline XBOX_INPUT_DEVICE input_support_list[] = { @@ -100,36 +103,51 @@ struct SBCOutput { #pragma pack() - -// hle specific input types -typedef struct _CXBX_XINPUT_DEVICE_INFO { - uint8_t ucType; // xbox controller type - uint8_t ucSubType; // xbox controller subtype - uint8_t ucInputStateSize; // xbox controller input state size in bytes, not include dwPacketNumber - uint8_t ucFeedbackSize; // xbox controller feedback size in bytes, not include FeedbackHeader +struct CommonCtrlInfo { + xbox::HANDLE hhandle; // device handle returned by xapi + bool bAutoPoll; // autopoll on/off, as instructed by the title in XInputOpen + bool bAutoPollDefault; // default autopoll value, depending on device type + uint8_t ucType; // xapi type + uint8_t ucSubType; // xapi subtype + uint8_t ucInputStateSize; // input state size in bytes, does not include dwPacketNumber + uint8_t ucFeedbackSize; // feedback size in bytes, does not include FeedbackHeader uint32_t dwPacketNumber; -} -CXBX_XINPUT_DEVICE_INFO, *PCXBX_XINPUT_DEVICE_INFO; - -union CXBX_XINPUT_IN_STATE { - XpadInput Gamepad; - SBCInput SBC; }; -// this structure is for use of tracking the xbox controllers assigned to 4 ports. -typedef struct _CXBX_CONTROLLER_HOST_BRIDGE { - HANDLE hXboxDevice; // xbox device handle to this device, we use the address of this bridge as the handle, only set after opened. cleared after closed. - int XboxPort; // xbox port# for this xbox controller - XBOX_INPUT_DEVICE XboxType; // xbox device type - CXBX_XINPUT_IN_STATE *InState; - bool bPendingRemoval; - bool bSignaled; - bool bIoInProgress; - bool bAutoPoll; // autopoll on/off, as instructed by the title in XInputOpen - bool bAutoPollDefault; // default autopoll value, depending on device type - CXBX_XINPUT_DEVICE_INFO XboxDeviceInfo; -} -CXBX_CONTROLLER_HOST_BRIDGE, *PCXBX_CONTROLLER_HOST_BRIDGE; +struct DeviceState; +struct CtrlInfo { + CommonCtrlInfo common; + XpadInput in_buffer; + DeviceState *slots[XBOX_CTRL_NUM_SLOTS]; +}; + +struct ArcadeCtrlInfo { + CommonCtrlInfo common; + XpadInput in_buffer; +}; + +struct SbcInfo { + CommonCtrlInfo common; + SBCInput in_buffer; +}; + +union DeviceInfo { + CtrlInfo ctrl; + ArcadeCtrlInfo arcade; + SbcInfo sbc; +}; + +struct DeviceState { + DeviceState *upstream; + std::string port; + XBOX_INPUT_DEVICE type; + bool bPendingRemoval; + bool bSignaled; + DeviceInfo info; +}; + +extern DeviceState g_devs[4 + 8]; + class InputDeviceManager { @@ -137,7 +155,7 @@ public: void Initialize(bool is_gui, HWND hwnd); void Shutdown(); // read/write the input/output from/to the device attached to the supplied xbox port - bool UpdateXboxPortInput(int usb_port, void* Buffer, int Direction, int xid_type); + bool UpdateXboxPortInput(int port, void *buffer, int direction, int type); // add the device to the list of availble devices void AddDevice(std::shared_ptr Device); // remove the device from the list of availble devices @@ -151,9 +169,9 @@ public: // find device from its sdl id std::shared_ptr FindDevice(SDL_JoystickID id) const; // find device from its xbox port - std::shared_ptr FindDevice(int usb_port, int dummy) const; + std::shared_ptr FindDevice(std::string_view port) const; // attach/detach guest devices to the emulated machine - void UpdateDevices(int port, bool ack); + void UpdateDevices(std::string_view port, bool ack); // update input options void UpdateOpt(bool is_gui); // device hotplug event handler @@ -166,11 +184,11 @@ private: // update input for a Steel Battalion controller bool UpdateInputSBC(std::shared_ptr& Device, void* Buffer, int Direction, int Port); // bind a host device to an emulated device - void BindHostDevice(int port, int usb_port, int type); + void BindHostDevice(int type, std::string_view port); // connect a device to the emulated machine - void ConnectDevice(int port, int usb_port, int type); + void ConnectDevice(DeviceState *dev, DeviceState *upstream, int type, std::string_view port); // disconnect a device from the emulated machine - void DisconnectDevice(int port, int usb_port, bool ack); + void DisconnectDevice(DeviceState *dev, std::string_view port, bool ack); // all enumerated devices currently detected and supported std::vector> m_Devices; @@ -189,7 +207,7 @@ private: extern InputDeviceManager g_InputDeviceManager; // hle input functions -bool ConstructHleInputDevice(int Type, int Port); -void DestructHleInputDevice(int Port); +void ConstructHleInputDevice(DeviceState *dev, DeviceState *upstream, int type, std::string_view port); +void DestructHleInputDevice(DeviceState *dev); #endif diff --git a/src/common/input/SdlJoystick.cpp b/src/common/input/SdlJoystick.cpp index 530686f5f..7c0f22461 100644 --- a/src/common/input/SdlJoystick.cpp +++ b/src/common/input/SdlJoystick.cpp @@ -160,7 +160,15 @@ namespace Sdl else { XInput::GetDeviceChanges(); DInput::GetDeviceChanges(); - g_InputDeviceManager.UpdateDevices(*static_cast(Event.user.data1), false); + std::string port = std::to_string(*static_cast(Event.user.data1)); + int port1, slot; + PortStr2Int(port, &port1, &slot); + if (g_devs[port1].type == XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE || g_devs[port1].type == XBOX_INPUT_DEVICE::MS_CONTROLLER_S) { + // Force an update of the entire slot connectivity of this port + g_InputDeviceManager.UpdateDevices(port + ".0", false); + g_InputDeviceManager.UpdateDevices(port + ".1", false); + } + g_InputDeviceManager.UpdateDevices(port, false); } delete Event.user.data1; diff --git a/src/common/input/SdlJoystick.h b/src/common/input/SdlJoystick.h index b6d18008e..05055f7a9 100644 --- a/src/common/input/SdlJoystick.h +++ b/src/common/input/SdlJoystick.h @@ -43,6 +43,12 @@ namespace Sdl } SDL_INIT_STATUS; + struct UPDATE_INPUT_DATA { + int Port; + int Slot; + bool Opt; + }; + extern uint32_t ExitEvent_t; extern uint32_t PopulateEvent_t; extern uint32_t UpdateInputEvent_t; diff --git a/src/core/hle/XAPI/Xapi.cpp b/src/core/hle/XAPI/Xapi.cpp index 39d5ca233..b325ebc87 100644 --- a/src/core/hle/XAPI/Xapi.cpp +++ b/src/core/hle/XAPI/Xapi.cpp @@ -43,23 +43,25 @@ #include "Windef.h" #include #include "core\hle\XAPI\Xapi.h" +#include "distorm.h" +#include "mnemonics.h" +#include xbox::PXPP_DEVICE_TYPE g_DeviceType_Gamepad = nullptr; xbox::PXPP_DEVICE_TYPE g_DeviceType_SBC = nullptr; +xbox::PXPP_DEVICE_TYPE g_DeviceType_MU = nullptr; // Flag is unset after initialize devices is done by simulate LLE USB thread. std::atomic g_bIsDevicesInitializing = true; std::atomic g_bIsDevicesEmulating = false; -static CXBX_XINPUT_IN_STATE g_InState[4]; -// Global bridge for xbox controller to host, 4 elements for 4 ports. -CXBX_CONTROLLER_HOST_BRIDGE g_XboxControllerHostBridge[4] = { - { NULL, PORT_INVALID, XBOX_INPUT_DEVICE::DEVICE_INVALID, &g_InState[0], false, false, false, false, false, { 0, 0, 0, 0, 0 } }, - { NULL, PORT_INVALID, XBOX_INPUT_DEVICE::DEVICE_INVALID, &g_InState[1], false, false, false, false, false, { 0, 0, 0, 0, 0 } }, - { NULL, PORT_INVALID, XBOX_INPUT_DEVICE::DEVICE_INVALID, &g_InState[2], false, false, false, false, false, { 0, 0, 0, 0, 0 } }, - { NULL, PORT_INVALID, XBOX_INPUT_DEVICE::DEVICE_INVALID, &g_InState[3], false, false, false, false, false, { 0, 0, 0, 0, 0 } }, -}; +// Protects access to xpp types +std::atomic g_bXppGuard = false; + +// allocate enough memory for the max number of devices we can support simultaneously +// 4 duke / S / sbc / arcade jpystick (mutually exclusive) + 8 memory units +DeviceState g_devs[4 + 8]; bool operator==(xbox::PXPP_DEVICE_TYPE XppType, XBOX_INPUT_DEVICE XidType) @@ -82,9 +84,15 @@ bool operator==(xbox::PXPP_DEVICE_TYPE XppType, XBOX_INPUT_DEVICE XidType) } break; + case XBOX_INPUT_DEVICE::MEMORY_UNIT: { + if (XppType == g_DeviceType_MU) { + return true; + } + } + break; + case XBOX_INPUT_DEVICE::LIGHT_GUN: case XBOX_INPUT_DEVICE::STEERING_WHEEL: - case XBOX_INPUT_DEVICE::MEMORY_UNIT: case XBOX_INPUT_DEVICE::IR_DONGLE: default: break; @@ -93,15 +101,9 @@ bool operator==(xbox::PXPP_DEVICE_TYPE XppType, XBOX_INPUT_DEVICE XidType) return false; } -bool operator!=(xbox::PXPP_DEVICE_TYPE XppType, XBOX_INPUT_DEVICE XidType) -{ - return !(XppType == XidType); -} - -bool ConstructHleInputDevice(int Type, int Port) +void ConstructHleInputDevice(DeviceState *dev, DeviceState *upstream, int type, std::string_view port) { g_bIsDevicesEmulating = true; - bool ret = true; if (g_bIsChihiro) { // Don't emulate XID devices during Chihiro Emulation @@ -110,105 +112,153 @@ bool ConstructHleInputDevice(int Type, int Port) } // NOTE: initialize bAutoPollDefault to its default state, which varies depending on the device type - switch (Type) + switch (type) { - case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE): { - g_XboxControllerHostBridge[Port].XboxPort = Port; - g_XboxControllerHostBridge[Port].XboxType = XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE; - g_XboxControllerHostBridge[Port].bPendingRemoval = false; - g_XboxControllerHostBridge[Port].bSignaled = false; - g_XboxControllerHostBridge[Port].bIoInProgress = false; - g_XboxControllerHostBridge[Port].bAutoPollDefault = true; - g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucType = XINPUT_DEVTYPE_GAMEPAD; - g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucSubType = XINPUT_DEVSUBTYPE_GC_GAMEPAD; - g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucInputStateSize = sizeof(XpadInput); - g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucFeedbackSize = sizeof(XpadOutput); - g_XboxControllerHostBridge[Port].XboxDeviceInfo.dwPacketNumber = 0; - } - break; - - case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_S): { - g_XboxControllerHostBridge[Port].XboxPort = Port; - g_XboxControllerHostBridge[Port].XboxType = XBOX_INPUT_DEVICE::MS_CONTROLLER_S; - g_XboxControllerHostBridge[Port].bPendingRemoval = false; - g_XboxControllerHostBridge[Port].bSignaled = false; - g_XboxControllerHostBridge[Port].bIoInProgress = false; - g_XboxControllerHostBridge[Port].bAutoPollDefault = true; - g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucType = XINPUT_DEVTYPE_GAMEPAD; - g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucSubType = XINPUT_DEVSUBTYPE_GC_GAMEPAD_ALT; - g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucInputStateSize = sizeof(XpadInput); - g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucFeedbackSize = sizeof(XpadOutput); - g_XboxControllerHostBridge[Port].XboxDeviceInfo.dwPacketNumber = 0; - } - break; - - case to_underlying(XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER): { - g_XboxControllerHostBridge[Port].XboxPort = Port; - g_XboxControllerHostBridge[Port].XboxType = XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER; - g_XboxControllerHostBridge[Port].InState->SBC.ucGearLever = 8; - g_XboxControllerHostBridge[Port].InState->SBC.sAimingX = static_cast(0x7F); - g_XboxControllerHostBridge[Port].InState->SBC.sAimingY = static_cast(0x7F); - g_XboxControllerHostBridge[Port].bPendingRemoval = false; - g_XboxControllerHostBridge[Port].bSignaled = false; - g_XboxControllerHostBridge[Port].bIoInProgress = false; - g_XboxControllerHostBridge[Port].bAutoPollDefault = true; - g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucType = XINPUT_DEVTYPE_STEELBATTALION; - g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucSubType = XINPUT_DEVSUBTYPE_GC_GAMEPAD_ALT; - g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucInputStateSize = sizeof(SBCInput); - g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucFeedbackSize = sizeof(SBCOutput); - g_XboxControllerHostBridge[Port].XboxDeviceInfo.dwPacketNumber = 0; - } - break; - - case to_underlying(XBOX_INPUT_DEVICE::ARCADE_STICK): { - g_XboxControllerHostBridge[Port].XboxPort = Port; - g_XboxControllerHostBridge[Port].XboxType = XBOX_INPUT_DEVICE::ARCADE_STICK; - g_XboxControllerHostBridge[Port].bPendingRemoval = false; - g_XboxControllerHostBridge[Port].bSignaled = false; - g_XboxControllerHostBridge[Port].bIoInProgress = false; - g_XboxControllerHostBridge[Port].bAutoPollDefault = true; - g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucType = XINPUT_DEVTYPE_GAMEPAD; - g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucSubType = XINPUT_DEVSUBTYPE_GC_ARCADE_STICK; - g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucInputStateSize = sizeof(XpadInput); - g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucFeedbackSize = sizeof(XpadOutput); - g_XboxControllerHostBridge[Port].XboxDeviceInfo.dwPacketNumber = 0; - } - break; - - case to_underlying(XBOX_INPUT_DEVICE::LIGHT_GUN): - case to_underlying(XBOX_INPUT_DEVICE::STEERING_WHEEL): - case to_underlying(XBOX_INPUT_DEVICE::MEMORY_UNIT): - case to_underlying(XBOX_INPUT_DEVICE::IR_DONGLE): - EmuLog(LOG_LEVEL::INFO, "%s: device %s is not yet supported", __func__, GetInputDeviceName(Type).c_str()); - ret = false; + case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE): + dev->upstream = nullptr; + dev->port = port; + dev->type = XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE; + dev->bPendingRemoval = false; + dev->bSignaled = false; + dev->info.ctrl.common.bAutoPollDefault = true; + dev->info.ctrl.common.ucType = XINPUT_DEVTYPE_GAMEPAD; + dev->info.ctrl.common.ucSubType = XINPUT_DEVSUBTYPE_GC_GAMEPAD; + dev->info.ctrl.common.ucInputStateSize = sizeof(XpadInput); + dev->info.ctrl.common.ucFeedbackSize = sizeof(XpadOutput); + dev->info.ctrl.common.dwPacketNumber = 0; + dev->info.ctrl.slots[SLOT_TOP] = dev->info.ctrl.slots[SLOT_BOTTOM] = nullptr; break; + case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_S): + dev->upstream = nullptr; + dev->port = port; + dev->type = XBOX_INPUT_DEVICE::MS_CONTROLLER_S; + dev->bPendingRemoval = false; + dev->bSignaled = false; + dev->info.ctrl.common.bAutoPollDefault = true; + dev->info.ctrl.common.ucType = XINPUT_DEVTYPE_GAMEPAD; + dev->info.ctrl.common.ucSubType = XINPUT_DEVSUBTYPE_GC_GAMEPAD_ALT; + dev->info.ctrl.common.ucInputStateSize = sizeof(XpadInput); + dev->info.ctrl.common.ucFeedbackSize = sizeof(XpadOutput); + dev->info.ctrl.common.dwPacketNumber = 0; + dev->info.ctrl.slots[SLOT_TOP] = dev->info.ctrl.slots[SLOT_BOTTOM] = nullptr; + break; + + case to_underlying(XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER): + dev->upstream = nullptr; + dev->port = port; + dev->type = XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER; + dev->bPendingRemoval = false; + dev->bSignaled = false; + dev->info.sbc.in_buffer.ucGearLever = 8; + dev->info.sbc.in_buffer.sAimingX = static_cast(0x7F); + dev->info.sbc.in_buffer.sAimingY = static_cast(0x7F); + dev->info.sbc.common.bAutoPollDefault = true; + dev->info.sbc.common.ucType = XINPUT_DEVTYPE_STEELBATTALION; + dev->info.sbc.common.ucSubType = XINPUT_DEVSUBTYPE_GC_GAMEPAD_ALT; + dev->info.sbc.common.ucInputStateSize = sizeof(SBCInput); + dev->info.sbc.common.ucFeedbackSize = sizeof(SBCOutput); + dev->info.sbc.common.dwPacketNumber = 0; + break; + + case to_underlying(XBOX_INPUT_DEVICE::ARCADE_STICK): + dev->upstream = nullptr; + dev->port = port; + dev->type = XBOX_INPUT_DEVICE::ARCADE_STICK; + dev->bPendingRemoval = false; + dev->bSignaled = false; + dev->info.arcade.common.bAutoPollDefault = true; + dev->info.arcade.common.ucType = XINPUT_DEVTYPE_GAMEPAD; + dev->info.arcade.common.ucSubType = XINPUT_DEVSUBTYPE_GC_ARCADE_STICK; + dev->info.arcade.common.ucInputStateSize = sizeof(XpadInput); + dev->info.arcade.common.ucFeedbackSize = sizeof(XpadOutput); + dev->info.arcade.common.dwPacketNumber = 0; + break; + + case to_underlying(XBOX_INPUT_DEVICE::MEMORY_UNIT): { + assert(upstream != nullptr); + dev->upstream = upstream; + dev->port = port; + dev->type = XBOX_INPUT_DEVICE::MEMORY_UNIT; + dev->bPendingRemoval = false; + dev->bSignaled = false; + int port1, slot; + PortStr2Int(port, &port1, &slot); + assert(slot != PORT_INVALID); + dev->upstream->info.ctrl.slots[slot] = dev; + } + break; + default: - EmuLog(LOG_LEVEL::WARNING, "Attempted to attach an unknown device type (type was %d)", Type); - ret = false; + assert(0); } + UpdateXppState(dev, static_cast(type), port); + g_bIsDevicesEmulating = false; - return ret; } -void DestructHleInputDevice(int Port) +void DestructHleInputDevice(DeviceState *dev) { g_bIsDevicesEmulating = true; - g_XboxControllerHostBridge[Port].XboxType = XBOX_INPUT_DEVICE::DEVICE_INVALID; - g_XboxControllerHostBridge[Port].XboxPort = PORT_INVALID; - while (g_XboxControllerHostBridge[Port].bIoInProgress) {} - g_XboxControllerHostBridge[Port].bPendingRemoval = false; - g_XboxControllerHostBridge[Port].bSignaled = false; - g_XboxControllerHostBridge[Port].bIoInProgress = false; - g_XboxControllerHostBridge[Port].bAutoPollDefault = false; - g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucType = 0; - g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucSubType = 0; - g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucInputStateSize = 0; - g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucFeedbackSize = 0; - g_XboxControllerHostBridge[Port].XboxDeviceInfo.dwPacketNumber = 0; - std::memset(&g_InState[Port], 0, sizeof(CXBX_XINPUT_IN_STATE)); + XBOX_INPUT_DEVICE type = dev->type; + std::string port = dev->port; + dev->type = XBOX_INPUT_DEVICE::DEVICE_INVALID; + dev->port = std::to_string(PORT_INVALID); + dev->bPendingRemoval = false; + dev->bSignaled = false; + + switch (dev->type) + { + case XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE: + case XBOX_INPUT_DEVICE::MS_CONTROLLER_S: + dev->info.ctrl.common.bAutoPollDefault = false; + dev->info.ctrl.common.ucType = 0; + dev->info.ctrl.common.ucSubType = 0; + dev->info.ctrl.common.ucInputStateSize = 0; + dev->info.ctrl.common.ucFeedbackSize = 0; + dev->info.ctrl.common.dwPacketNumber = 0; + dev->info.ctrl.slots[SLOT_TOP] = dev->info.ctrl.slots[SLOT_BOTTOM] = nullptr; + std::memset(&dev->info.sbc.in_buffer, 0, sizeof(XpadInput)); + break; + + case XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER: + dev->info.sbc.common.bAutoPollDefault = false; + dev->info.sbc.common.ucType = 0; + dev->info.sbc.common.ucSubType = 0; + dev->info.sbc.common.ucInputStateSize = 0; + dev->info.sbc.common.ucFeedbackSize = 0; + dev->info.sbc.common.dwPacketNumber = 0; + std::memset(&dev->info.sbc.in_buffer, 0, sizeof(SBCInput)); + break; + + case XBOX_INPUT_DEVICE::ARCADE_STICK: + dev->info.arcade.common.bAutoPollDefault = false; + dev->info.arcade.common.ucType = 0; + dev->info.arcade.common.ucSubType = 0; + dev->info.arcade.common.ucInputStateSize = 0; + dev->info.arcade.common.ucFeedbackSize = 0; + dev->info.arcade.common.dwPacketNumber = 0; + std::memset(&dev->info.sbc.in_buffer, 0, sizeof(XpadInput)); + break; + + case XBOX_INPUT_DEVICE::MEMORY_UNIT: { + assert(dev->upstream != nullptr && (dev->upstream->type == XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE || + dev->upstream->type == XBOX_INPUT_DEVICE::MS_CONTROLLER_S)); + int port1, slot; + PortStr2Int(port, &port1, &slot); + assert(slot != PORT_INVALID); + dev->upstream->info.ctrl.slots[slot] = nullptr; + } + break; + + default: + assert(0); + } + + UpdateXppState(dev, type, port); + dev->upstream = nullptr; g_bIsDevicesEmulating = false; } @@ -280,8 +330,143 @@ void SetupXboxDeviceTypes() return; } - EmuLog(LOG_LEVEL::INFO, "XDEVICE_TYPE_GAMEPAD Found at 0x%08X", (uintptr_t)g_DeviceType_Gamepad); + EmuLog(LOG_LEVEL::INFO, "XDEVICE_TYPE_GAMEPAD found at 0x%08X", (uintptr_t)g_DeviceType_Gamepad); } + + // The MU device type is not present in the xpp table, because that only holds the types that XInputOpen supports, and MUs are not + // one of those. Insted, this type is referenced by MU_Init, the main MU initialization function, so we can derive it from that. + // Unfortunately, the offset of the MU type varies slightly between xdk revisions, so we cannot just read from a fixed offset. What's + // constant is that the type is always hardcoded in a push instruction immediately followed by a call, and there are no other push - call + // instructions between the start of MU_Init and the offset of interest. + + if (uint8_t *start = reinterpret_cast(g_SymbolAddresses["MU_Init"])) { + _CodeInfo ci; + ci.code = start; + ci.codeLen = 100; + ci.codeOffset = 0; + ci.dt = Decode32Bits; + ci.features = DF_NONE; + std::array<_DInst, 50> info; + unsigned i; + + distorm_decompose(&ci, info.data(), 50, &i); + + i = 0; + const auto &it = std::find_if(info.begin(), info.end(), [&info, &i](_DInst &op) { + if (!(op.opcode == I_PUSH)) { + ++i; + return false; + } + + if (((i + 1) <= 49) && (info[i + 1].opcode == I_CALL)) { + return true; + } + + ++i; + return false; + }); + + if (it == info.end()) { + EmuLog(LOG_LEVEL::WARNING, "XDEVICE_TYPE_MEMORY_UNIT was not found inside MU_Init"); + } + else { + g_DeviceType_MU = reinterpret_cast(*reinterpret_cast((it->addr + start + 1))); + EmuLog(LOG_LEVEL::INFO, "XDEVICE_TYPE_MEMORY_UNIT found at 0x%08X", reinterpret_cast(g_DeviceType_MU)); + } + } + else { + EmuLog(LOG_LEVEL::INFO, "XDEVICE_TYPE_MEMORY_UNIT was not found because MU_Init could not be found"); + } +} + +void UpdateXppState(DeviceState *dev, XBOX_INPUT_DEVICE type, std::string_view port) +{ + xbox::PXPP_DEVICE_TYPE xpp; + switch (type) + { + case XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE: + case XBOX_INPUT_DEVICE::MS_CONTROLLER_S: + case XBOX_INPUT_DEVICE::ARCADE_STICK: + xpp = g_DeviceType_Gamepad; + break; + + case XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER: + xpp = g_DeviceType_SBC; + break; + + case XBOX_INPUT_DEVICE::MEMORY_UNIT: + xpp = g_DeviceType_MU; + break; + + default: + xpp = nullptr; + } + + assert(xpp != nullptr); + + int port1, slot; + PortStr2Int(port, &port1, &slot); + xbox::ulong_xt port_mask = 1 << port1; + + // Guard against the unfortunate case where XGetDevices or XGetDeviceChanges have already checked for g_bIsDevicesInitializing + // and g_bIsDevicesEmulating and a thread switch happens to this function + while (g_bXppGuard) {} + + if (xpp == g_DeviceType_MU) { + if ((dev->upstream->type != XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE) || + (dev->upstream->type != XBOX_INPUT_DEVICE::MS_CONTROLLER_S) || + dev->upstream->bPendingRemoval) { + xpp->CurrentConnected &= ~port_mask; + xpp->CurrentConnected &= ~(port_mask << 16); + } + else { + for (unsigned i = 0, j = 0; i < XBOX_CTRL_NUM_SLOTS; ++i, j += 16) { + if (xpp == dev->type && !dev->bPendingRemoval) { + xpp->CurrentConnected |= (port_mask << j); + } + else { + xpp->CurrentConnected &= ~(port_mask << j); + } + } + } + } + else { + if (xpp == dev->type && !dev->bPendingRemoval) { + xpp->CurrentConnected |= port_mask; + } + else { + xpp->CurrentConnected &= ~port_mask; + } + } + + xpp->ChangeConnected = xpp->PreviousConnected ^ xpp->CurrentConnected; +} + +template +xbox::dword_xt CxbxImpl_XInputHandler(xbox::HANDLE hDevice, xbox::PXINPUT_STATE pState) +{ + xbox::dword_xt status = ERROR_DEVICE_NOT_CONNECTED; + PXBOX_DEV_CONNECTIVITY Device = (PXBOX_DEV_CONNECTIVITY)hDevice; + int Port = Device->XboxPort; + + if ((g_XboxDevices[Port].hXboxDevice == hDevice) && !g_XboxDevices[Port].bPendingRemoval) { + if (g_XboxDevices[Port].bAutoPoll != IsXInputPoll) { + g_XboxDevices[Port].bIoInProgress = true; + if (g_InputDeviceManager.UpdateXboxPortInput(Port, g_XboxDevices[Port].InState, DIRECTION_IN, to_underlying(g_XboxDevices[Port].XboxType))) { + g_XboxDevices[Port].XboxDeviceInfo.dwPacketNumber++; + } + g_XboxDevices[Port].bIoInProgress = false; + } + + if constexpr (!IsXInputPoll) { + std::memcpy((void *)&pState->Gamepad, g_XboxDevices[Port].InState, g_XboxDevices[Port].XboxDeviceInfo.ucInputStateSize); + pState->dwPacketNumber = g_XboxDevices[Port].XboxDeviceInfo.dwPacketNumber; + } + + status = ERROR_SUCCESS; + } + + return status; } // ****************************************************************** @@ -312,63 +497,6 @@ xbox::void_xt WINAPI xbox::EMUPATCH(XInitDevices) }).detach(); } -// This is called to emulate async for both XGetDevices and XGetDeviceChanges -void UpdateConnectedDeviceState(xbox::PXPP_DEVICE_TYPE DeviceType) { - - // Do not process the queries until initialize delay and device emulating are complete. - if (g_bIsDevicesInitializing || g_bIsDevicesEmulating){ - return; - } - - int Port, PortMask; - for (Port = PORT_1, PortMask = 1; Port <= PORT_4; Port++, PortMask <<= 1) { - if (DeviceType == g_XboxControllerHostBridge[Port].XboxType && !g_XboxControllerHostBridge[Port].bPendingRemoval) { - DeviceType->CurrentConnected |= PortMask; - } - else { - DeviceType->CurrentConnected &= ~PortMask; - } - - if (static_cast(g_XboxControllerHostBridge[Port].bPendingRemoval) & - ~(static_cast(g_XboxControllerHostBridge[Port].bSignaled))) { - g_XboxControllerHostBridge[Port].bSignaled = true; - SDL_Event DeviceRemoveEvent; - SDL_memset(&DeviceRemoveEvent, 0, sizeof(SDL_Event)); - DeviceRemoveEvent.type = Sdl::DeviceRemoveAck_t; - DeviceRemoveEvent.user.data1 = new int(Port); - SDL_PushEvent(&DeviceRemoveEvent); - } - } - DeviceType->ChangeConnected = DeviceType->PreviousConnected ^ DeviceType->CurrentConnected; -} - -template -xbox::dword_xt CxbxImpl_XInputHandler(xbox::HANDLE hDevice, xbox::PXINPUT_STATE pState) -{ - xbox::dword_xt status = ERROR_DEVICE_NOT_CONNECTED; - PCXBX_CONTROLLER_HOST_BRIDGE Device = (PCXBX_CONTROLLER_HOST_BRIDGE)hDevice; - int Port = Device->XboxPort; - - if ((g_XboxControllerHostBridge[Port].hXboxDevice == hDevice) && !g_XboxControllerHostBridge[Port].bPendingRemoval) { - if (g_XboxControllerHostBridge[Port].bAutoPoll != IsXInputPoll) { - g_XboxControllerHostBridge[Port].bIoInProgress = true; - if (g_InputDeviceManager.UpdateXboxPortInput(Port, g_XboxControllerHostBridge[Port].InState, DIRECTION_IN, to_underlying(g_XboxControllerHostBridge[Port].XboxType))) { - g_XboxControllerHostBridge[Port].XboxDeviceInfo.dwPacketNumber++; - } - g_XboxControllerHostBridge[Port].bIoInProgress = false; - } - - if constexpr (!IsXInputPoll) { - std::memcpy((void *)&pState->Gamepad, g_XboxControllerHostBridge[Port].InState, g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucInputStateSize); - pState->dwPacketNumber = g_XboxControllerHostBridge[Port].XboxDeviceInfo.dwPacketNumber; - } - - status = ERROR_SUCCESS; - } - - return status; -} - // ****************************************************************** // * patch: XGetDevices // * Note: This could be unpatched however, @@ -383,18 +511,38 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(XGetDevices) { LOG_FUNC_ONE_ARG(DeviceType); - UpdateConnectedDeviceState(DeviceType); + g_bXppGuard = true; + static dword_xt last_connected = 0; + if (g_bIsDevicesInitializing || g_bIsDevicesEmulating) { + g_bXppGuard = false; + RETURN(last_connected); + } + + for (unsigned i = 0; i < 12; ++i) { + if (static_cast(g_devs[i].bPendingRemoval) & + ~(static_cast(g_devs[i].bSignaled))) { + g_devs[i].bSignaled = true; + SDL_Event DeviceRemoveEvent; + SDL_memset(&DeviceRemoveEvent, 0, sizeof(SDL_Event)); + DeviceRemoveEvent.type = Sdl::DeviceRemoveAck_t; + DeviceRemoveEvent.user.data1 = new char[g_devs[i].port.size()]; + std::strcpy(static_cast(DeviceRemoveEvent.user.data1), g_devs[i].port.c_str()); + SDL_PushEvent(&DeviceRemoveEvent); + } + } UCHAR oldIrql = xbox::KeRaiseIrqlToDpcLevel(); - dword_xt ret = DeviceType->CurrentConnected; + last_connected = DeviceType->CurrentConnected; DeviceType->ChangeConnected = 0; DeviceType->PreviousConnected = DeviceType->CurrentConnected; xbox::KfLowerIrql(oldIrql); - RETURN(ret); + g_bXppGuard = false; + + RETURN(last_connected); } // ****************************************************************** @@ -417,11 +565,29 @@ xbox::bool_xt WINAPI xbox::EMUPATCH(XGetDeviceChanges) LOG_FUNC_ARG(pdwRemovals) LOG_FUNC_END; - UpdateConnectedDeviceState(DeviceType); + g_bXppGuard = true; + if (g_bIsDevicesInitializing || g_bIsDevicesEmulating) { + *pdwInsertions = 0; + *pdwRemovals = 0; + g_bXppGuard = false; + RETURN(FALSE); + } + + for (unsigned i = 0; i < 12; ++i) { + if (static_cast(g_devs[i].bPendingRemoval) & + ~(static_cast(g_devs[i].bSignaled))) { + g_devs[i].bSignaled = true; + SDL_Event DeviceRemoveEvent; + SDL_memset(&DeviceRemoveEvent, 0, sizeof(SDL_Event)); + DeviceRemoveEvent.type = Sdl::DeviceRemoveAck_t; + DeviceRemoveEvent.user.data1 = new char[g_devs[i].port.size()]; + std::strcpy(static_cast(DeviceRemoveEvent.user.data1), g_devs[i].port.c_str()); + SDL_PushEvent(&DeviceRemoveEvent); + } + } BOOL ret = FALSE; - if(!DeviceType->ChangeConnected) { *pdwInsertions = 0; @@ -448,6 +614,7 @@ xbox::bool_xt WINAPI xbox::EMUPATCH(XGetDeviceChanges) xbox::KfLowerIrql(oldIrql); } + g_bXppGuard = false; RETURN(ret); } @@ -470,12 +637,17 @@ xbox::HANDLE WINAPI xbox::EMUPATCH(XInputOpen) LOG_FUNC_ARG(pPollingParameters) LOG_FUNC_END; + if (DeviceType == g_DeviceType_MU) { + // MUs cannot be opened with XInputOpen + RETURN(NULL); + } + if (dwPort >= PORT_1 && dwPort <= PORT_4) { - if (DeviceType == g_XboxControllerHostBridge[dwPort].XboxType) { - g_XboxControllerHostBridge[dwPort].bAutoPoll = pPollingParameters != xbox::zeroptr ? - pPollingParameters->fAutoPoll : g_XboxControllerHostBridge[dwPort].bAutoPollDefault; - g_XboxControllerHostBridge[dwPort].hXboxDevice = &g_XboxControllerHostBridge[dwPort]; - RETURN(g_XboxControllerHostBridge[dwPort].hXboxDevice); + if (DeviceType == g_XboxDevices[dwPort].XboxType) { + g_XboxDevices[dwPort].bAutoPoll = pPollingParameters != xbox::zeroptr ? + pPollingParameters->fAutoPoll : g_XboxDevices[dwPort].bAutoPollDefault; + g_XboxDevices[dwPort].hXboxDevice = &g_XboxDevices[dwPort]; + RETURN(g_XboxDevices[dwPort].hXboxDevice); } } @@ -492,9 +664,9 @@ xbox::void_xt WINAPI xbox::EMUPATCH(XInputClose) { LOG_FUNC_ONE_ARG(hDevice); - PCXBX_CONTROLLER_HOST_BRIDGE Device = (PCXBX_CONTROLLER_HOST_BRIDGE)hDevice; + PXBOX_DEV_CONNECTIVITY Device = (PXBOX_DEV_CONNECTIVITY)hDevice; int Port = Device->XboxPort; - if (g_XboxControllerHostBridge[Port].hXboxDevice == hDevice) { + if (g_XboxDevices[Port].hXboxDevice == hDevice) { Device->hXboxDevice = NULL; } } @@ -530,12 +702,12 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(XInputGetCapabilities) LOG_FUNC_END; dword_xt ret = ERROR_DEVICE_NOT_CONNECTED; - PCXBX_CONTROLLER_HOST_BRIDGE Device = (PCXBX_CONTROLLER_HOST_BRIDGE)hDevice; + PXBOX_DEV_CONNECTIVITY Device = (PXBOX_DEV_CONNECTIVITY)hDevice; int Port = Device->XboxPort; - if (g_XboxControllerHostBridge[Port].hXboxDevice == hDevice && !g_XboxControllerHostBridge[Port].bPendingRemoval) { - pCapabilities->SubType = g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucSubType; + if (g_XboxDevices[Port].hXboxDevice == hDevice && !g_XboxDevices[Port].bPendingRemoval) { + pCapabilities->SubType = g_XboxDevices[Port].XboxDeviceInfo.ucSubType; UCHAR* pCap = (UCHAR*)(&pCapabilities->In); - memset(pCap, 0xFF, g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucInputStateSize + g_XboxControllerHostBridge[Port].XboxDeviceInfo.ucFeedbackSize); + memset(pCap, 0xFF, g_XboxDevices[Port].XboxDeviceInfo.ucInputStateSize + g_XboxDevices[Port].XboxDeviceInfo.ucFeedbackSize); ret = ERROR_SUCCESS; } @@ -579,11 +751,11 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(XInputSetState) LOG_FUNC_ARG(pFeedback) LOG_FUNC_END; - PCXBX_CONTROLLER_HOST_BRIDGE Device = (PCXBX_CONTROLLER_HOST_BRIDGE)hDevice; + PXBOX_DEV_CONNECTIVITY Device = (PXBOX_DEV_CONNECTIVITY)hDevice; int Port = Device->XboxPort; - if (g_XboxControllerHostBridge[Port].hXboxDevice == hDevice && !g_XboxControllerHostBridge[Port].bPendingRemoval) { + if (g_XboxDevices[Port].hXboxDevice == hDevice && !g_XboxDevices[Port].bPendingRemoval) { pFeedback->Header.dwStatus = ERROR_IO_PENDING; - g_InputDeviceManager.UpdateXboxPortInput(Port, (void*)&pFeedback->Rumble, DIRECTION_OUT, to_underlying(g_XboxControllerHostBridge[Port].XboxType)); + g_InputDeviceManager.UpdateXboxPortInput(Port, (void*)&pFeedback->Rumble, DIRECTION_OUT, to_underlying(g_XboxDevices[Port].XboxType)); pFeedback->Header.dwStatus = ERROR_SUCCESS; if (pFeedback->Header.hEvent != NULL && ObReferenceObjectByHandle(pFeedback->Header.hEvent, &xbox::ExEventObjectType, (PVOID*)&pFeedback->Header.IoCompletedEvent) == ERROR_SUCCESS) { diff --git a/src/gui/DlgInputConfig.cpp b/src/gui/DlgInputConfig.cpp index 744e809ad..03d567291 100644 --- a/src/gui/DlgInputConfig.cpp +++ b/src/gui/DlgInputConfig.cpp @@ -79,12 +79,8 @@ void SyncInputSettings(int port_num, int dev_type, bool is_opt) g_EmuShared->SetInputGeneralSettings(&g_Settings->m_input_general); port_num = PORT_INVALID; } -#if 0 // lle usb - ipc_send_kernel_update(IPC_UPDATE_KERNEL::CONFIG_INPUT_SYNC, PORT_DEC(Gui2XboxPortArray[port_num]), - reinterpret_cast(g_ChildWnd)); -#else + ipc_send_kernel_update(IPC_UPDATE_KERNEL::CONFIG_INPUT_SYNC, port_num, reinterpret_cast(g_ChildWnd)); -#endif } } @@ -165,6 +161,13 @@ INT_PTR CALLBACK DlgInputConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPAR HWND hHandle = GetDlgItem(hWndDlg, IDC_DEVICE_PORT1 + port); int DeviceType = SendMessage(hHandle, CB_GETITEMDATA, SendMessage(hHandle, CB_GETCURSEL, 0, 0), 0); g_Settings->m_input_port[port].Type = DeviceType; + if (DeviceType != to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE) || + DeviceType != to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_S)) { + // Forcefully set the child devices to none. This will happen if the user sets MUs in the controller dialog but + // then they set the parent device to a device that cannot support them in the input dialog + g_Settings->m_input_port[port].TopSlotType = to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID); + g_Settings->m_input_port[port].BottomSlotType = to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID); + } SyncInputSettings(port, DeviceType, false); } } diff --git a/src/gui/controllers/DlgDukeControllerConfig.cpp b/src/gui/controllers/DlgDukeControllerConfig.cpp index 09576cca4..ccbfe3ed5 100644 --- a/src/gui/controllers/DlgDukeControllerConfig.cpp +++ b/src/gui/controllers/DlgDukeControllerConfig.cpp @@ -81,7 +81,7 @@ void DukeInputWindow::Initialize(HWND hwnd, int port_num, int dev_type) } SendMessage(m_hwnd_window, WM_SETTEXT, 0, - reinterpret_cast((title + std::to_string(PORT_INC(m_port_num))).c_str())); + reinterpret_cast((title + PortUserFormat(std::to_string(m_port_num))).c_str())); // Set the maximum profile name lenght the user can enter in the profile combobox SendMessage(m_hwnd_profile_list, CB_LIMITTEXT, 49, 0); diff --git a/src/gui/controllers/DlgSBControllerConfig.cpp b/src/gui/controllers/DlgSBControllerConfig.cpp index 37db7bd8c..4627c879e 100644 --- a/src/gui/controllers/DlgSBControllerConfig.cpp +++ b/src/gui/controllers/DlgSBControllerConfig.cpp @@ -54,7 +54,7 @@ void SbcInputWindow::Initialize(HWND hwnd, int port_num, int dev_type) // Set window title std::string title("Steel Battalion Controller at port "); SendMessage(m_hwnd_window, WM_SETTEXT, 0, - reinterpret_cast((title + std::to_string(PORT_INC(m_port_num))).c_str())); + reinterpret_cast((title + PortUserFormat(std::to_string(m_port_num))).c_str())); // Set the maximum profile name lenght the user can enter in the profile combobox SendMessage(m_hwnd_profile_list, CB_LIMITTEXT, 49, 0); From 4cf90a6170a784f10de78624b3e164dcaaac0063 Mon Sep 17 00:00:00 2001 From: ergo720 <45463469+ergo720@users.noreply.github.com> Date: Wed, 16 Jun 2021 19:07:51 +0200 Subject: [PATCH 5/9] Updated xinput apis + fixed compiler errors --- src/common/input/InputDevice.cpp | 20 +- src/common/input/InputManager.cpp | 2 +- src/common/input/InputManager.h | 33 +-- src/common/input/SdlJoystick.cpp | 2 +- src/core/hle/XAPI/Xapi.cpp | 320 ++++++++++++++---------------- 5 files changed, 172 insertions(+), 205 deletions(-) diff --git a/src/common/input/InputDevice.cpp b/src/common/input/InputDevice.cpp index dd39cdeb1..2d2596483 100644 --- a/src/common/input/InputDevice.cpp +++ b/src/common/input/InputDevice.cpp @@ -159,6 +159,16 @@ const std::vector InputDevice::GetIoControls() return vec; } +const auto InputDevice::FindPort(std::string_view Port) const +{ + return std::find_if(m_XboxPort.begin(), m_XboxPort.end(), [Port](std::string_view Port1) { + if (Port1 == Port) { + return true; + } + return false; + }); +} + void InputDevice::SetPort(std::string_view Port, bool Connect) { if (Connect) { @@ -176,13 +186,3 @@ bool InputDevice::GetPort(std::string_view Port) const { return FindPort(Port) != m_XboxPort.end() ? true : false; } - -const auto InputDevice::FindPort(std::string_view Port) const -{ - return std::find_if(m_XboxPort.begin(), m_XboxPort.end(), [Port](std::string_view Port1) { - if (Port1 == Port) { - return true; - } - return false; - }); -} diff --git a/src/common/input/InputManager.cpp b/src/common/input/InputManager.cpp index 3167d554b..5dd8321c0 100644 --- a/src/common/input/InputManager.cpp +++ b/src/common/input/InputManager.cpp @@ -235,7 +235,7 @@ void InputDeviceManager::UpdateDevices(std::string_view port, bool ack) assert(dev->type == XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE || dev->type == XBOX_INPUT_DEVICE::MS_CONTROLLER_S); upstream = dev; - dev = dev->info.ctrl.slots[slot]; + dev = dev->slots[slot]; g_EmuShared->GetInputSlotTypeSettings(&type, port1, slot); } diff --git a/src/common/input/InputManager.h b/src/common/input/InputManager.h index e3ae3c5a0..c1acc856d 100644 --- a/src/common/input/InputManager.h +++ b/src/common/input/InputManager.h @@ -103,7 +103,12 @@ struct SBCOutput { #pragma pack() -struct CommonCtrlInfo { +union InputBuff { + XpadInput ctrl; + SBCInput sbc; +}; + +struct DeviceInfo { xbox::HANDLE hhandle; // device handle returned by xapi bool bAutoPoll; // autopoll on/off, as instructed by the title in XInputOpen bool bAutoPollDefault; // default autopoll value, depending on device type @@ -112,38 +117,18 @@ struct CommonCtrlInfo { uint8_t ucInputStateSize; // input state size in bytes, does not include dwPacketNumber uint8_t ucFeedbackSize; // feedback size in bytes, does not include FeedbackHeader uint32_t dwPacketNumber; -}; - -struct DeviceState; -struct CtrlInfo { - CommonCtrlInfo common; - XpadInput in_buffer; - DeviceState *slots[XBOX_CTRL_NUM_SLOTS]; -}; - -struct ArcadeCtrlInfo { - CommonCtrlInfo common; - XpadInput in_buffer; -}; - -struct SbcInfo { - CommonCtrlInfo common; - SBCInput in_buffer; -}; - -union DeviceInfo { - CtrlInfo ctrl; - ArcadeCtrlInfo arcade; - SbcInfo sbc; + InputBuff buff; }; struct DeviceState { DeviceState *upstream; std::string port; + int port_idx; XBOX_INPUT_DEVICE type; bool bPendingRemoval; bool bSignaled; DeviceInfo info; + DeviceState *slots[XBOX_CTRL_NUM_SLOTS]; }; extern DeviceState g_devs[4 + 8]; diff --git a/src/common/input/SdlJoystick.cpp b/src/common/input/SdlJoystick.cpp index 7c0f22461..bb4a0bf9d 100644 --- a/src/common/input/SdlJoystick.cpp +++ b/src/common/input/SdlJoystick.cpp @@ -175,7 +175,7 @@ namespace Sdl Event.user.data1 = nullptr; } else if (Event.type == DeviceRemoveAck_t) { - g_InputDeviceManager.UpdateDevices(*static_cast(Event.user.data1), true); + g_InputDeviceManager.UpdateDevices(std::string(static_cast(Event.user.data1)), true); delete Event.user.data1; Event.user.data1 = nullptr; } diff --git a/src/core/hle/XAPI/Xapi.cpp b/src/core/hle/XAPI/Xapi.cpp index b325ebc87..8878746da 100644 --- a/src/core/hle/XAPI/Xapi.cpp +++ b/src/core/hle/XAPI/Xapi.cpp @@ -60,7 +60,7 @@ std::atomic g_bIsDevicesEmulating = false; std::atomic g_bXppGuard = false; // allocate enough memory for the max number of devices we can support simultaneously -// 4 duke / S / sbc / arcade jpystick (mutually exclusive) + 8 memory units +// 4 duke / S / sbc / arcade joystick (mutually exclusive) + 8 memory units DeviceState g_devs[4 + 8]; @@ -101,6 +101,69 @@ bool operator==(xbox::PXPP_DEVICE_TYPE XppType, XBOX_INPUT_DEVICE XidType) return false; } +void UpdateXppState(DeviceState *dev, XBOX_INPUT_DEVICE type, std::string_view port) +{ + xbox::PXPP_DEVICE_TYPE xpp; + switch (type) + { + case XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE: + case XBOX_INPUT_DEVICE::MS_CONTROLLER_S: + case XBOX_INPUT_DEVICE::ARCADE_STICK: + xpp = g_DeviceType_Gamepad; + break; + + case XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER: + xpp = g_DeviceType_SBC; + break; + + case XBOX_INPUT_DEVICE::MEMORY_UNIT: + xpp = g_DeviceType_MU; + break; + + default: + xpp = nullptr; + } + + assert(xpp != nullptr); + + int port1, slot; + PortStr2Int(port, &port1, &slot); + xbox::ulong_xt port_mask = 1 << port1; + + // Guard against the unfortunate case where XGetDevices or XGetDeviceChanges have already checked for g_bIsDevicesInitializing + // and g_bIsDevicesEmulating and a thread switch happens to this function + while (g_bXppGuard) {} + + if (xpp == g_DeviceType_MU) { + if ((dev->upstream->type != XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE) || + (dev->upstream->type != XBOX_INPUT_DEVICE::MS_CONTROLLER_S) || + dev->upstream->bPendingRemoval) { + xpp->CurrentConnected &= ~port_mask; + xpp->CurrentConnected &= ~(port_mask << 16); + } + else { + for (unsigned i = 0, j = 0; i < XBOX_CTRL_NUM_SLOTS; ++i, j += 16) { + if (xpp == dev->type && !dev->bPendingRemoval) { + xpp->CurrentConnected |= (port_mask << j); + } + else { + xpp->CurrentConnected &= ~(port_mask << j); + } + } + } + } + else { + if (xpp == dev->type && !dev->bPendingRemoval) { + xpp->CurrentConnected |= port_mask; + } + else { + xpp->CurrentConnected &= ~port_mask; + } + } + + xpp->ChangeConnected = xpp->PreviousConnected ^ xpp->CurrentConnected; +} + void ConstructHleInputDevice(DeviceState *dev, DeviceState *upstream, int type, std::string_view port) { g_bIsDevicesEmulating = true; @@ -110,84 +173,67 @@ void ConstructHleInputDevice(DeviceState *dev, DeviceState *upstream, int type, g_bIsDevicesEmulating = false; return ret; } + // Set up common device state + int port1, slot; + PortStr2Int(port, &port1, &slot); + dev->upstream = nullptr; + dev->port = port; + dev->port_idx = port1; + dev->bPendingRemoval = false; + dev->bSignaled = false; + dev->info.dwPacketNumber = 0; + dev->slots[SLOT_TOP] = dev->slots[SLOT_BOTTOM] = nullptr; // NOTE: initialize bAutoPollDefault to its default state, which varies depending on the device type switch (type) { case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE): - dev->upstream = nullptr; - dev->port = port; dev->type = XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE; - dev->bPendingRemoval = false; - dev->bSignaled = false; - dev->info.ctrl.common.bAutoPollDefault = true; - dev->info.ctrl.common.ucType = XINPUT_DEVTYPE_GAMEPAD; - dev->info.ctrl.common.ucSubType = XINPUT_DEVSUBTYPE_GC_GAMEPAD; - dev->info.ctrl.common.ucInputStateSize = sizeof(XpadInput); - dev->info.ctrl.common.ucFeedbackSize = sizeof(XpadOutput); - dev->info.ctrl.common.dwPacketNumber = 0; - dev->info.ctrl.slots[SLOT_TOP] = dev->info.ctrl.slots[SLOT_BOTTOM] = nullptr; + dev->info.bAutoPollDefault = true; + dev->info.ucType = XINPUT_DEVTYPE_GAMEPAD; + dev->info.ucSubType = XINPUT_DEVSUBTYPE_GC_GAMEPAD; + dev->info.ucInputStateSize = sizeof(XpadInput); + dev->info.ucFeedbackSize = sizeof(XpadOutput); break; case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_S): - dev->upstream = nullptr; - dev->port = port; dev->type = XBOX_INPUT_DEVICE::MS_CONTROLLER_S; - dev->bPendingRemoval = false; - dev->bSignaled = false; - dev->info.ctrl.common.bAutoPollDefault = true; - dev->info.ctrl.common.ucType = XINPUT_DEVTYPE_GAMEPAD; - dev->info.ctrl.common.ucSubType = XINPUT_DEVSUBTYPE_GC_GAMEPAD_ALT; - dev->info.ctrl.common.ucInputStateSize = sizeof(XpadInput); - dev->info.ctrl.common.ucFeedbackSize = sizeof(XpadOutput); - dev->info.ctrl.common.dwPacketNumber = 0; - dev->info.ctrl.slots[SLOT_TOP] = dev->info.ctrl.slots[SLOT_BOTTOM] = nullptr; + dev->info.bAutoPollDefault = true; + dev->info.ucType = XINPUT_DEVTYPE_GAMEPAD; + dev->info.ucSubType = XINPUT_DEVSUBTYPE_GC_GAMEPAD_ALT; + dev->info.ucInputStateSize = sizeof(XpadInput); + dev->info.ucFeedbackSize = sizeof(XpadOutput); break; case to_underlying(XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER): - dev->upstream = nullptr; - dev->port = port; dev->type = XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER; - dev->bPendingRemoval = false; - dev->bSignaled = false; - dev->info.sbc.in_buffer.ucGearLever = 8; - dev->info.sbc.in_buffer.sAimingX = static_cast(0x7F); - dev->info.sbc.in_buffer.sAimingY = static_cast(0x7F); - dev->info.sbc.common.bAutoPollDefault = true; - dev->info.sbc.common.ucType = XINPUT_DEVTYPE_STEELBATTALION; - dev->info.sbc.common.ucSubType = XINPUT_DEVSUBTYPE_GC_GAMEPAD_ALT; - dev->info.sbc.common.ucInputStateSize = sizeof(SBCInput); - dev->info.sbc.common.ucFeedbackSize = sizeof(SBCOutput); - dev->info.sbc.common.dwPacketNumber = 0; + dev->info.buff.sbc.ucGearLever = 8; + dev->info.buff.sbc.sAimingX = static_cast(0x7F); + dev->info.buff.sbc.sAimingY = static_cast(0x7F); + dev->info.bAutoPollDefault = true; + dev->info.ucType = XINPUT_DEVTYPE_STEELBATTALION; + dev->info.ucSubType = XINPUT_DEVSUBTYPE_GC_GAMEPAD_ALT; + dev->info.ucInputStateSize = sizeof(SBCInput); + dev->info.ucFeedbackSize = sizeof(SBCOutput); break; case to_underlying(XBOX_INPUT_DEVICE::ARCADE_STICK): - dev->upstream = nullptr; - dev->port = port; dev->type = XBOX_INPUT_DEVICE::ARCADE_STICK; - dev->bPendingRemoval = false; - dev->bSignaled = false; - dev->info.arcade.common.bAutoPollDefault = true; - dev->info.arcade.common.ucType = XINPUT_DEVTYPE_GAMEPAD; - dev->info.arcade.common.ucSubType = XINPUT_DEVSUBTYPE_GC_ARCADE_STICK; - dev->info.arcade.common.ucInputStateSize = sizeof(XpadInput); - dev->info.arcade.common.ucFeedbackSize = sizeof(XpadOutput); - dev->info.arcade.common.dwPacketNumber = 0; + dev->info.bAutoPollDefault = true; + dev->info.ucType = XINPUT_DEVTYPE_GAMEPAD; + dev->info.ucSubType = XINPUT_DEVSUBTYPE_GC_ARCADE_STICK; + dev->info.ucInputStateSize = sizeof(XpadInput); + dev->info.ucFeedbackSize = sizeof(XpadOutput); break; - case to_underlying(XBOX_INPUT_DEVICE::MEMORY_UNIT): { + case to_underlying(XBOX_INPUT_DEVICE::MEMORY_UNIT): assert(upstream != nullptr); dev->upstream = upstream; - dev->port = port; dev->type = XBOX_INPUT_DEVICE::MEMORY_UNIT; - dev->bPendingRemoval = false; - dev->bSignaled = false; - int port1, slot; - PortStr2Int(port, &port1, &slot); + dev->port_idx = PORT_INVALID; assert(slot != PORT_INVALID); - dev->upstream->info.ctrl.slots[slot] = dev; - } - break; + dev->upstream->slots[slot] = dev; + break; default: assert(0); @@ -202,45 +248,47 @@ void DestructHleInputDevice(DeviceState *dev) { g_bIsDevicesEmulating = true; + // Clear common device state XBOX_INPUT_DEVICE type = dev->type; std::string port = dev->port; + dev->port_idx = PORT_INVALID; dev->type = XBOX_INPUT_DEVICE::DEVICE_INVALID; dev->port = std::to_string(PORT_INVALID); dev->bPendingRemoval = false; dev->bSignaled = false; + dev->slots[SLOT_TOP] = dev->slots[SLOT_BOTTOM] = nullptr; switch (dev->type) { case XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE: case XBOX_INPUT_DEVICE::MS_CONTROLLER_S: - dev->info.ctrl.common.bAutoPollDefault = false; - dev->info.ctrl.common.ucType = 0; - dev->info.ctrl.common.ucSubType = 0; - dev->info.ctrl.common.ucInputStateSize = 0; - dev->info.ctrl.common.ucFeedbackSize = 0; - dev->info.ctrl.common.dwPacketNumber = 0; - dev->info.ctrl.slots[SLOT_TOP] = dev->info.ctrl.slots[SLOT_BOTTOM] = nullptr; - std::memset(&dev->info.sbc.in_buffer, 0, sizeof(XpadInput)); + dev->info.bAutoPollDefault = false; + dev->info.ucType = 0; + dev->info.ucSubType = 0; + dev->info.ucInputStateSize = 0; + dev->info.ucFeedbackSize = 0; + dev->info.dwPacketNumber = 0; + std::memset(&dev->info.buff.ctrl, 0, sizeof(XpadInput)); break; case XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER: - dev->info.sbc.common.bAutoPollDefault = false; - dev->info.sbc.common.ucType = 0; - dev->info.sbc.common.ucSubType = 0; - dev->info.sbc.common.ucInputStateSize = 0; - dev->info.sbc.common.ucFeedbackSize = 0; - dev->info.sbc.common.dwPacketNumber = 0; - std::memset(&dev->info.sbc.in_buffer, 0, sizeof(SBCInput)); + dev->info.bAutoPollDefault = false; + dev->info.ucType = 0; + dev->info.ucSubType = 0; + dev->info.ucInputStateSize = 0; + dev->info.ucFeedbackSize = 0; + dev->info.dwPacketNumber = 0; + std::memset(&dev->info.buff.sbc, 0, sizeof(SBCInput)); break; case XBOX_INPUT_DEVICE::ARCADE_STICK: - dev->info.arcade.common.bAutoPollDefault = false; - dev->info.arcade.common.ucType = 0; - dev->info.arcade.common.ucSubType = 0; - dev->info.arcade.common.ucInputStateSize = 0; - dev->info.arcade.common.ucFeedbackSize = 0; - dev->info.arcade.common.dwPacketNumber = 0; - std::memset(&dev->info.sbc.in_buffer, 0, sizeof(XpadInput)); + dev->info.bAutoPollDefault = false; + dev->info.ucType = 0; + dev->info.ucSubType = 0; + dev->info.ucInputStateSize = 0; + dev->info.ucFeedbackSize = 0; + dev->info.dwPacketNumber = 0; + std::memset(&dev->info.buff.ctrl, 0, sizeof(XpadInput)); break; case XBOX_INPUT_DEVICE::MEMORY_UNIT: { @@ -249,7 +297,7 @@ void DestructHleInputDevice(DeviceState *dev) int port1, slot; PortStr2Int(port, &port1, &slot); assert(slot != PORT_INVALID); - dev->upstream->info.ctrl.slots[slot] = nullptr; + dev->upstream->slots[slot] = nullptr; } break; @@ -379,88 +427,23 @@ void SetupXboxDeviceTypes() } } -void UpdateXppState(DeviceState *dev, XBOX_INPUT_DEVICE type, std::string_view port) -{ - xbox::PXPP_DEVICE_TYPE xpp; - switch (type) - { - case XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE: - case XBOX_INPUT_DEVICE::MS_CONTROLLER_S: - case XBOX_INPUT_DEVICE::ARCADE_STICK: - xpp = g_DeviceType_Gamepad; - break; - - case XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER: - xpp = g_DeviceType_SBC; - break; - - case XBOX_INPUT_DEVICE::MEMORY_UNIT: - xpp = g_DeviceType_MU; - break; - - default: - xpp = nullptr; - } - - assert(xpp != nullptr); - - int port1, slot; - PortStr2Int(port, &port1, &slot); - xbox::ulong_xt port_mask = 1 << port1; - - // Guard against the unfortunate case where XGetDevices or XGetDeviceChanges have already checked for g_bIsDevicesInitializing - // and g_bIsDevicesEmulating and a thread switch happens to this function - while (g_bXppGuard) {} - - if (xpp == g_DeviceType_MU) { - if ((dev->upstream->type != XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE) || - (dev->upstream->type != XBOX_INPUT_DEVICE::MS_CONTROLLER_S) || - dev->upstream->bPendingRemoval) { - xpp->CurrentConnected &= ~port_mask; - xpp->CurrentConnected &= ~(port_mask << 16); - } - else { - for (unsigned i = 0, j = 0; i < XBOX_CTRL_NUM_SLOTS; ++i, j += 16) { - if (xpp == dev->type && !dev->bPendingRemoval) { - xpp->CurrentConnected |= (port_mask << j); - } - else { - xpp->CurrentConnected &= ~(port_mask << j); - } - } - } - } - else { - if (xpp == dev->type && !dev->bPendingRemoval) { - xpp->CurrentConnected |= port_mask; - } - else { - xpp->CurrentConnected &= ~port_mask; - } - } - - xpp->ChangeConnected = xpp->PreviousConnected ^ xpp->CurrentConnected; -} - template xbox::dword_xt CxbxImpl_XInputHandler(xbox::HANDLE hDevice, xbox::PXINPUT_STATE pState) { xbox::dword_xt status = ERROR_DEVICE_NOT_CONNECTED; - PXBOX_DEV_CONNECTIVITY Device = (PXBOX_DEV_CONNECTIVITY)hDevice; - int Port = Device->XboxPort; + DeviceState *dev = static_cast(hDevice); + int port = dev->port_idx; - if ((g_XboxDevices[Port].hXboxDevice == hDevice) && !g_XboxDevices[Port].bPendingRemoval) { - if (g_XboxDevices[Port].bAutoPoll != IsXInputPoll) { - g_XboxDevices[Port].bIoInProgress = true; - if (g_InputDeviceManager.UpdateXboxPortInput(Port, g_XboxDevices[Port].InState, DIRECTION_IN, to_underlying(g_XboxDevices[Port].XboxType))) { - g_XboxDevices[Port].XboxDeviceInfo.dwPacketNumber++; + if ((g_devs[port].info.hhandle == hDevice) && !g_devs[port].bPendingRemoval) { + if (g_devs[port].info.bAutoPoll != IsXInputPoll) { + if (g_InputDeviceManager.UpdateXboxPortInput(port, &g_devs[port].info.buff, DIRECTION_IN, to_underlying(g_devs[port].type))) { + g_devs[port].info.dwPacketNumber++; } - g_XboxDevices[Port].bIoInProgress = false; } if constexpr (!IsXInputPoll) { - std::memcpy((void *)&pState->Gamepad, g_XboxDevices[Port].InState, g_XboxDevices[Port].XboxDeviceInfo.ucInputStateSize); - pState->dwPacketNumber = g_XboxDevices[Port].XboxDeviceInfo.dwPacketNumber; + std::memcpy((void *)&pState->Gamepad, &g_devs[port].info.buff, g_devs[port].info.ucInputStateSize); + pState->dwPacketNumber = g_devs[port].info.dwPacketNumber; } status = ERROR_SUCCESS; @@ -643,11 +626,11 @@ xbox::HANDLE WINAPI xbox::EMUPATCH(XInputOpen) } if (dwPort >= PORT_1 && dwPort <= PORT_4) { - if (DeviceType == g_XboxDevices[dwPort].XboxType) { - g_XboxDevices[dwPort].bAutoPoll = pPollingParameters != xbox::zeroptr ? - pPollingParameters->fAutoPoll : g_XboxDevices[dwPort].bAutoPollDefault; - g_XboxDevices[dwPort].hXboxDevice = &g_XboxDevices[dwPort]; - RETURN(g_XboxDevices[dwPort].hXboxDevice); + if (DeviceType == g_devs[dwPort].type) { + g_devs[dwPort].info.bAutoPoll = pPollingParameters != xbox::zeroptr ? + pPollingParameters->fAutoPoll : g_devs[dwPort].info.bAutoPollDefault; + g_devs[dwPort].info.hhandle = &g_devs[dwPort]; + RETURN(g_devs[dwPort].info.hhandle); } } @@ -664,10 +647,9 @@ xbox::void_xt WINAPI xbox::EMUPATCH(XInputClose) { LOG_FUNC_ONE_ARG(hDevice); - PXBOX_DEV_CONNECTIVITY Device = (PXBOX_DEV_CONNECTIVITY)hDevice; - int Port = Device->XboxPort; - if (g_XboxDevices[Port].hXboxDevice == hDevice) { - Device->hXboxDevice = NULL; + DeviceState *dev = static_cast(hDevice); + if (g_devs[dev->port_idx].info.hhandle == hDevice) { + dev->info.hhandle = NULL; } } @@ -702,12 +684,12 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(XInputGetCapabilities) LOG_FUNC_END; dword_xt ret = ERROR_DEVICE_NOT_CONNECTED; - PXBOX_DEV_CONNECTIVITY Device = (PXBOX_DEV_CONNECTIVITY)hDevice; - int Port = Device->XboxPort; - if (g_XboxDevices[Port].hXboxDevice == hDevice && !g_XboxDevices[Port].bPendingRemoval) { - pCapabilities->SubType = g_XboxDevices[Port].XboxDeviceInfo.ucSubType; + DeviceState *dev = static_cast(hDevice); + int port = dev->port_idx; + if (g_devs[port].info.hhandle == hDevice && !g_devs[port].bPendingRemoval) { + pCapabilities->SubType = g_devs[port].info.ucSubType; UCHAR* pCap = (UCHAR*)(&pCapabilities->In); - memset(pCap, 0xFF, g_XboxDevices[Port].XboxDeviceInfo.ucInputStateSize + g_XboxDevices[Port].XboxDeviceInfo.ucFeedbackSize); + std::memset(pCap, 0xFF, g_devs[port].info.ucInputStateSize + g_devs[port].info.ucFeedbackSize); ret = ERROR_SUCCESS; } @@ -751,11 +733,11 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(XInputSetState) LOG_FUNC_ARG(pFeedback) LOG_FUNC_END; - PXBOX_DEV_CONNECTIVITY Device = (PXBOX_DEV_CONNECTIVITY)hDevice; - int Port = Device->XboxPort; - if (g_XboxDevices[Port].hXboxDevice == hDevice && !g_XboxDevices[Port].bPendingRemoval) { + DeviceState *dev = static_cast(hDevice); + int port = dev->port_idx; + if (g_devs[port].info.hhandle == hDevice && !g_devs[port].bPendingRemoval) { pFeedback->Header.dwStatus = ERROR_IO_PENDING; - g_InputDeviceManager.UpdateXboxPortInput(Port, (void*)&pFeedback->Rumble, DIRECTION_OUT, to_underlying(g_XboxDevices[Port].XboxType)); + g_InputDeviceManager.UpdateXboxPortInput(port, (void*)&pFeedback->Rumble, DIRECTION_OUT, to_underlying(g_devs[port].type)); pFeedback->Header.dwStatus = ERROR_SUCCESS; if (pFeedback->Header.hEvent != NULL && ObReferenceObjectByHandle(pFeedback->Header.hEvent, &xbox::ExEventObjectType, (PVOID*)&pFeedback->Header.IoCompletedEvent) == ERROR_SUCCESS) { From 88a786b700f1a962c89a3773b38d726afb47a7df Mon Sep 17 00:00:00 2001 From: ergo720 <45463469+ergo720@users.noreply.github.com> Date: Fri, 18 Jun 2021 01:37:31 +0200 Subject: [PATCH 6/9] Implemented MU support to xapi functions --- src/common/input/InputManager.cpp | 8 +- src/core/hle/XAPI/Xapi.cpp | 174 ++++++++++++++++++++------ src/core/kernel/exports/EmuKrnlNt.cpp | 49 ++++++-- src/core/kernel/init/CxbxKrnl.cpp | 19 ++- src/core/kernel/support/EmuFile.cpp | 33 +++-- src/core/kernel/support/EmuFile.h | 11 ++ src/gui/DlgInputConfig.cpp | 2 +- 7 files changed, 225 insertions(+), 71 deletions(-) diff --git a/src/common/input/InputManager.cpp b/src/common/input/InputManager.cpp index 5dd8321c0..0c3346190 100644 --- a/src/common/input/InputManager.cpp +++ b/src/common/input/InputManager.cpp @@ -117,18 +117,19 @@ void InputDeviceManager::Initialize(bool is_gui, HWND hwnd) for (unsigned i = 0; i < 4; ++i) { int type; g_EmuShared->GetInputDevTypeSettings(&type, i); - std::string port = std::to_string(i); if (type != to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)) { + std::string port = std::to_string(i); switch (type) { case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE): case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_S): { ConstructHleInputDevice(&g_devs[CTRL_OFFSET + i], nullptr, type, port); + BindHostDevice(type, port); for (unsigned slot = 0; slot < XBOX_CTRL_NUM_SLOTS; ++slot) { g_EmuShared->GetInputSlotTypeSettings(&type, i, slot); if (type != to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)) { assert(type == to_underlying(XBOX_INPUT_DEVICE::MEMORY_UNIT)); - ConstructHleInputDevice(&g_devs[MU_OFFSET + slot], &g_devs[CTRL_OFFSET + i], type, port + std::to_string(slot)); + ConstructHleInputDevice(&g_devs[MU_OFFSET + slot], &g_devs[CTRL_OFFSET + i], type, port + "." + std::to_string(slot)); } } } @@ -137,6 +138,7 @@ void InputDeviceManager::Initialize(bool is_gui, HWND hwnd) case to_underlying(XBOX_INPUT_DEVICE::ARCADE_STICK): case to_underlying(XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER): ConstructHleInputDevice(&g_devs[CTRL_OFFSET + i], nullptr, type, port); + BindHostDevice(type, port); break; default: @@ -224,8 +226,8 @@ void InputDeviceManager::UpdateDevices(std::string_view port, bool ack) { DeviceState *dev, *upstream; int port1, type, slot; - dev = &g_devs[port1]; PortStr2Int(port, &port1, &slot); + dev = &g_devs[port1]; if (slot == PORT_INVALID) { // Port references a device attached to an xbox port upstream = nullptr; diff --git a/src/core/hle/XAPI/Xapi.cpp b/src/core/hle/XAPI/Xapi.cpp index 8878746da..a335e80ef 100644 --- a/src/core/hle/XAPI/Xapi.cpp +++ b/src/core/hle/XAPI/Xapi.cpp @@ -59,10 +59,38 @@ std::atomic g_bIsDevicesEmulating = false; // Protects access to xpp types std::atomic g_bXppGuard = false; -// allocate enough memory for the max number of devices we can support simultaneously +// Allocate enough memory for the max number of devices we can support simultaneously // 4 duke / S / sbc / arcade joystick (mutually exclusive) + 8 memory units DeviceState g_devs[4 + 8]; +xbox::ulong_xt g_Mounted_MUs = 0; // fallback if XapiMountedMUs is not found +xbox::ulong_xt *g_XapiMountedMUs = &g_Mounted_MUs; +std::mutex g_MuLock; + +static inline xbox::char_xt MuPort2Lett(xbox::dword_xt port, xbox::dword_xt slot) +{ + return 'F' + (XBOX_CTRL_NUM_SLOTS * port) + slot; +} + +static inline int MuPort2Idx(xbox::dword_xt port, xbox::dword_xt slot) +{ + return (port << 1) + slot; +} + +static inline bool MuIsMounted(xbox::char_xt lett) +{ + return *g_XapiMountedMUs & (1 << (lett - 'F')); +} + +static inline void MuSetMounted(xbox::char_xt lett) +{ + *g_XapiMountedMUs |= (1 << (lett - 'F')); +} + +static inline void MuClearMounted(xbox::char_xt lett) +{ + *g_XapiMountedMUs &= ~(1 << (lett - 'F')); +} bool operator==(xbox::PXPP_DEVICE_TYPE XppType, XBOX_INPUT_DEVICE XidType) { @@ -103,7 +131,7 @@ bool operator==(xbox::PXPP_DEVICE_TYPE XppType, XBOX_INPUT_DEVICE XidType) void UpdateXppState(DeviceState *dev, XBOX_INPUT_DEVICE type, std::string_view port) { - xbox::PXPP_DEVICE_TYPE xpp; + xbox::PXPP_DEVICE_TYPE xpp = nullptr; switch (type) { case XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE: @@ -121,44 +149,38 @@ void UpdateXppState(DeviceState *dev, XBOX_INPUT_DEVICE type, std::string_view p break; default: - xpp = nullptr; + assert(0); } - assert(xpp != nullptr); + if (xpp == nullptr) { + // This will happen with xbes that act like launchers, and don't link against the xinput libraries, which results in all the global + // xpp types being nullptr. Test case: Innocent Tears + return; + } int port1, slot; PortStr2Int(port, &port1, &slot); xbox::ulong_xt port_mask = 1 << port1; + xbox::ulong_xt slot_mask = 0; // Guard against the unfortunate case where XGetDevices or XGetDeviceChanges have already checked for g_bIsDevicesInitializing // and g_bIsDevicesEmulating and a thread switch happens to this function while (g_bXppGuard) {} if (xpp == g_DeviceType_MU) { - if ((dev->upstream->type != XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE) || - (dev->upstream->type != XBOX_INPUT_DEVICE::MS_CONTROLLER_S) || - dev->upstream->bPendingRemoval) { - xpp->CurrentConnected &= ~port_mask; - xpp->CurrentConnected &= ~(port_mask << 16); - } - else { - for (unsigned i = 0, j = 0; i < XBOX_CTRL_NUM_SLOTS; ++i, j += 16) { - if (xpp == dev->type && !dev->bPendingRemoval) { - xpp->CurrentConnected |= (port_mask << j); - } - else { - xpp->CurrentConnected &= ~(port_mask << j); - } - } + assert((dev->upstream->type == XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE) || + (dev->upstream->type == XBOX_INPUT_DEVICE::MS_CONTROLLER_S)); + assert(slot != PORT_INVALID); + if (slot == 1) { + slot_mask = 16; } } + + if (xpp == dev->type && !dev->bPendingRemoval) { + xpp->CurrentConnected |= (port_mask << slot_mask); + } else { - if (xpp == dev->type && !dev->bPendingRemoval) { - xpp->CurrentConnected |= port_mask; - } - else { - xpp->CurrentConnected &= ~port_mask; - } + xpp->CurrentConnected &= ~(port_mask << slot_mask); } xpp->ChangeConnected = xpp->PreviousConnected ^ xpp->CurrentConnected; @@ -425,6 +447,34 @@ void SetupXboxDeviceTypes() else { EmuLog(LOG_LEVEL::INFO, "XDEVICE_TYPE_MEMORY_UNIT was not found because MU_Init could not be found"); } + + // Temporary code until XapiMountedMUs is derived by XbSymbolDatabase + Xbe::LibraryVersion *pLibraryVersion = reinterpret_cast(CxbxKrnl_Xbe->m_Header.dwLibraryVersionsAddr); + if (pLibraryVersion != nullptr) { + if (uint8_t *start = reinterpret_cast(g_SymbolAddresses["XUnmountMU"])) { + uint32_t offset = 0; + for (unsigned v = 0; v < CxbxKrnl_Xbe->m_Header.dwLibraryVersions; ++v) { + if (std::strcmp(pLibraryVersion[v].szName, "XAPILIB") == 0) { + if (pLibraryVersion[v].wBuildVersion < 4242) { + offset = 0x1D; + } + else { + offset = 0x2A; + } + break; + } + } + // skip 2 because the address is hard-coded inside a test instruction + g_XapiMountedMUs = reinterpret_cast(*reinterpret_cast((g_SymbolAddresses["XUnmountMU"] + offset + 2))); + EmuLog(LOG_LEVEL::INFO, "XapiMountedMUs found at 0x%08X", reinterpret_cast(g_XapiMountedMUs)); + } + else { + EmuLog(LOG_LEVEL::WARNING, "XapiMountedMUs was not found because XUnmountMU could not be found"); + } + } + else { + EmuLog(LOG_LEVEL::WARNING, "XapiMountedMUs was not found because this xbe does not have a library version address"); + } } template @@ -1318,18 +1368,28 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(XMountMUA) PCHAR pchDrive ) { - - LOG_FUNC_BEGIN LOG_FUNC_ARG(dwPort) LOG_FUNC_ARG(dwSlot) LOG_FUNC_ARG(pchDrive) LOG_FUNC_END; - // TODO: Actually allow memory card emulation? This might make transferring - // game saves a bit easier if the memory card directory was configurable. =] + std::lock_guard lock(g_MuLock); - RETURN(E_FAIL); + char lett = MuPort2Lett(dwPort, dwSlot); + if (MuIsMounted(lett)) { + if (pchDrive != zeroptr) { + *pchDrive = lett; + } + RETURN(ERROR_ALREADY_ASSIGNED); + } + + MuSetMounted(lett); + if (pchDrive != zeroptr) { + *pchDrive = lett; + } + + RETURN(ERROR_SUCCESS); } // ****************************************************************** @@ -1378,16 +1438,41 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(XMountMURootA) PCHAR pchDrive ) { - - LOG_FUNC_BEGIN LOG_FUNC_ARG(dwPort) LOG_FUNC_ARG(dwSlot) LOG_FUNC_ARG(pchDrive) LOG_FUNC_END; - // TODO: The params are probably wrong... - LOG_UNIMPLEMENTED(); + std::lock_guard lock(g_MuLock); + + char_xt lett = MuPort2Lett(dwPort, dwSlot); + if (MuIsMounted(lett)) { + if (pchDrive != zeroptr) { + *pchDrive = lett; + } + RETURN(ERROR_ALREADY_ASSIGNED); + } + + std::string mu_path_str(DrivePrefix + lett + ":"); + std::string mu_dev_str(DeviceMU + std::to_string(MuPort2Idx(dwPort, dwSlot))); + ANSI_STRING mu_dev, mu_path; + RtlInitAnsiString(&mu_path, mu_path_str.data()); + RtlInitAnsiString(&mu_dev, mu_dev_str.data()); + ntstatus_xt status = IoCreateSymbolicLink(&mu_path, &mu_dev); + + if (!nt_success(status)) { + if (pchDrive != zeroptr) { + *pchDrive = 0; + } + RtlNtStatusToDosError(status); + RETURN(status); + } + + MuSetMounted(lett); + if (pchDrive != zeroptr) { + *pchDrive = lett; + } RETURN(ERROR_SUCCESS); } @@ -1401,14 +1486,29 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(XUnmountMU) dword_xt dwSlot ) { - - LOG_FUNC_BEGIN LOG_FUNC_ARG(dwPort) LOG_FUNC_ARG(dwSlot) LOG_FUNC_END; - LOG_UNIMPLEMENTED(); + std::lock_guard lock(g_MuLock); + + char_xt lett = MuPort2Lett(dwPort, dwSlot); + if (!MuIsMounted(lett)) { + RETURN(ERROR_INVALID_DRIVE); + } + + std::string mu_path_str(DrivePrefix + lett + ":"); + ANSI_STRING mu_path; + RtlInitAnsiString(&mu_path, mu_path_str.data()); + ntstatus_xt status = IoDeleteSymbolicLink(&mu_path); + + if (!nt_success(status)) { + RtlNtStatusToDosError(status); + RETURN(status); + } + + MuClearMounted(lett); RETURN(ERROR_SUCCESS); } diff --git a/src/core/kernel/exports/EmuKrnlNt.cpp b/src/core/kernel/exports/EmuKrnlNt.cpp index a8c7d9bfe..633b826a1 100644 --- a/src/core/kernel/exports/EmuKrnlNt.cpp +++ b/src/core/kernel/exports/EmuKrnlNt.cpp @@ -1501,25 +1501,48 @@ XBSYSAPI EXPORTNUM(218) xbox::ntstatus_xt NTAPI xbox::NtQueryVolumeInformationFi if ((DWORD)FileInformationClass == FileFsSizeInformation) { PFILE_FS_SIZE_INFORMATION XboxSizeInfo = (PFILE_FS_SIZE_INFORMATION)FileInformation; - XboxPartitionTable partitionTable = CxbxGetPartitionTable(); - int partitionNumber = CxbxGetPartitionNumberFromHandle(FileHandle); - FATX_SUPERBLOCK superBlock = CxbxGetFatXSuperBlock(partitionNumber); + // This might access the HDD or a MU, so we need to figure out the correct one first + const std::wstring path = CxbxGetFinalPathNameByHandle(FileHandle); + size_t pos = path.rfind(L"\\EmuDisk\\Partition"); + if (pos != std::string::npos) { + // We are accessing a disk partition - XboxSizeInfo->BytesPerSector = 512; + XboxPartitionTable partitionTable = CxbxGetPartitionTable(); + int partitionNumber = CxbxGetPartitionNumberFromPath(path); + FATX_SUPERBLOCK superBlock = CxbxGetFatXSuperBlock(partitionNumber); - // In some cases, the emulated partition hasn't been formatted yet, as these are forwarded to a real folder, this doesn't actually matter. - // We just pretend they are valid by defaulting the SectorsPerAllocationUnit value to the most common for system partitions - XboxSizeInfo->SectorsPerAllocationUnit = 32; + XboxSizeInfo->BytesPerSector = 512; - // If there is a valid cluster size, we calculate SectorsPerAllocationUnit from that instead - if (superBlock.ClusterSize > 0) { - XboxSizeInfo->SectorsPerAllocationUnit = superBlock.ClusterSize; + // In some cases, the emulated partition hasn't been formatted yet, as these are forwarded to a real folder, this doesn't actually matter. + // We just pretend they are valid by defaulting the SectorsPerAllocationUnit value to the most common for system partitions + XboxSizeInfo->SectorsPerAllocationUnit = 32; + + // If there is a valid cluster size, we calculate SectorsPerAllocationUnit from that instead + if (superBlock.ClusterSize > 0) { + XboxSizeInfo->SectorsPerAllocationUnit = superBlock.ClusterSize; + } + + XboxSizeInfo->TotalAllocationUnits.QuadPart = partitionTable.TableEntries[partitionNumber - 1].LBASize / XboxSizeInfo->SectorsPerAllocationUnit; + XboxSizeInfo->AvailableAllocationUnits.QuadPart = partitionTable.TableEntries[partitionNumber - 1].LBASize / XboxSizeInfo->SectorsPerAllocationUnit; + + RETURN(xbox::status_success); } - XboxSizeInfo->TotalAllocationUnits.QuadPart = partitionTable.TableEntries[partitionNumber - 1].LBASize / XboxSizeInfo->SectorsPerAllocationUnit; - XboxSizeInfo->AvailableAllocationUnits.QuadPart = partitionTable.TableEntries[partitionNumber - 1].LBASize / XboxSizeInfo->SectorsPerAllocationUnit; + pos = path.rfind(L"\\EmuMu"); + if (pos != std::string::npos) { + // We are accessing a MU - RETURN(xbox::status_success); + XboxSizeInfo->BytesPerSector = 512; + XboxSizeInfo->SectorsPerAllocationUnit = 32; + XboxSizeInfo->TotalAllocationUnits.QuadPart = 512; // 8MB -> ((1024)^2 * 8) / (BytesPerSector * SectorsPerAllocationUnit) + XboxSizeInfo->AvailableAllocationUnits.QuadPart = 512; // constant, so there's always free space available to write stuff + + RETURN(xbox::status_success); + } + + EmuLog(LOG_LEVEL::WARNING, "%s: Unrecongnized handle 0x%X with class FileFsSizeInformation", __func__, FileHandle); + + RETURN(xbox::status_invalid_handle); } // Get the required size for the host buffer diff --git a/src/core/kernel/init/CxbxKrnl.cpp b/src/core/kernel/init/CxbxKrnl.cpp index 00111d56a..99dfb5dcf 100644 --- a/src/core/kernel/init/CxbxKrnl.cpp +++ b/src/core/kernel/init/CxbxKrnl.cpp @@ -1509,16 +1509,15 @@ __declspec(noreturn) void CxbxKrnlInit CxbxRegisterDeviceHostPath(DeviceHarddisk0Partition7, CxbxBasePath + "Partition7"); CxbxRegisterDeviceHostPath(DevicePrefix + "\\Chihiro", CxbxBasePath + "Chihiro"); - // Create MU directories - for (unsigned i = 0; i < 8; ++i) { - std::error_code error; - static char mu_letter = 'F'; - std::string mu_path = MuBasePath + mu_letter; - if (!(std::filesystem::exists(mu_path) || std::filesystem::create_directory(mu_path, error))) { - CxbxKrnlCleanup("Failed to create memory unit directories"); - } - ++mu_letter; - } + // Create the MU directories + CxbxRegisterDeviceHostPath(DeviceMU0, MuBasePath + "F"); + CxbxRegisterDeviceHostPath(DeviceMU1, MuBasePath + "G"); + CxbxRegisterDeviceHostPath(DeviceMU2, MuBasePath + "H"); + CxbxRegisterDeviceHostPath(DeviceMU3, MuBasePath + "I"); + CxbxRegisterDeviceHostPath(DeviceMU4, MuBasePath + "J"); + CxbxRegisterDeviceHostPath(DeviceMU5, MuBasePath + "K"); + CxbxRegisterDeviceHostPath(DeviceMU6, MuBasePath + "L"); + CxbxRegisterDeviceHostPath(DeviceMU7, MuBasePath + "M"); // Create default symbolic links : EmuLogInit(LOG_LEVEL::DEBUG, "Creating default symbolic links."); diff --git a/src/core/kernel/support/EmuFile.cpp b/src/core/kernel/support/EmuFile.cpp index c10e0cbb3..846b6c651 100644 --- a/src/core/kernel/support/EmuFile.cpp +++ b/src/core/kernel/support/EmuFile.cpp @@ -139,7 +139,7 @@ FATX_SUPERBLOCK CxbxGetFatXSuperBlock(int partitionNumber) return superblock; } -static std::wstring CxbxGetFinalPathNameByHandle(HANDLE hFile) +std::wstring CxbxGetFinalPathNameByHandle(HANDLE hFile) { constexpr size_t INITIAL_BUF_SIZE = MAX_PATH; std::wstring path(INITIAL_BUF_SIZE, '\0'); @@ -173,20 +173,30 @@ static bool CxbxIsPathInsideEmuDisk(const std::filesystem::path& path) return match.first == rootPath.end(); } -int CxbxGetPartitionNumberFromHandle(HANDLE hFile) +static int CxbxGetPartitionNumber(const std::wstring_view path) { - // Get which partition number is being accessed, by parsing the filename and extracting the last portion - const std::wstring path = CxbxGetFinalPathNameByHandle(hFile); - const std::wstring_view partitionString = L"\\EmuDisk\\Partition"; const size_t pos = path.rfind(partitionString); if (pos == std::string::npos) { return 0; } - const std::wstring partitionNumberString = path.substr(pos + partitionString.length(), 1); + const std::wstring_view partitionNumberString = path.substr(pos + partitionString.length(), 1); // wcstol returns 0 on non-numeric characters, so we don't need to error check here - return wcstol(partitionNumberString.c_str(), nullptr, 0); + return wcstol(partitionNumberString.data(), nullptr, 0); +} + +int CxbxGetPartitionNumberFromPath(const std::wstring_view path) +{ + return CxbxGetPartitionNumber(path); +} + +int CxbxGetPartitionNumberFromHandle(HANDLE hFile) +{ + // Get which partition number is being accessed, by parsing the filename and extracting the last portion + const std::wstring path = CxbxGetFinalPathNameByHandle(hFile); + + return CxbxGetPartitionNumber(path); } std::filesystem::path CxbxGetPartitionDataPathFromHandle(HANDLE hFile) @@ -267,6 +277,7 @@ const std::string DriveZ = DrivePrefix + "Z:"; // Z: is Title utility data regio const std::string DevicePrefix = "\\Device"; const std::string DeviceCdrom0 = DevicePrefix + "\\CdRom0"; const std::string DeviceHarddisk0 = DevicePrefix + "\\Harddisk0"; +const std::string DeviceMU = DevicePrefix + "\\MU_"; const std::string DeviceHarddisk0PartitionPrefix = DevicePrefix + "\\Harddisk0\\partition"; const std::string DeviceHarddisk0Partition0 = DeviceHarddisk0PartitionPrefix + "0"; // Contains raw config sectors (like XBOX_REFURB_INFO) + entire hard disk const std::string DeviceHarddisk0Partition1 = DeviceHarddisk0PartitionPrefix + "1"; // Data partition. Contains TDATA and UDATA folders. @@ -289,6 +300,14 @@ const std::string DeviceHarddisk0Partition17 = DeviceHarddisk0PartitionPrefix + const std::string DeviceHarddisk0Partition18 = DeviceHarddisk0PartitionPrefix + "18"; const std::string DeviceHarddisk0Partition19 = DeviceHarddisk0PartitionPrefix + "19"; const std::string DeviceHarddisk0Partition20 = DeviceHarddisk0PartitionPrefix + "20"; // 20 = Largest possible partition number +const std::string DeviceMU0 = DeviceMU + "0"; +const std::string DeviceMU1 = DeviceMU + "1"; +const std::string DeviceMU2 = DeviceMU + "2"; +const std::string DeviceMU3 = DeviceMU + "3"; +const std::string DeviceMU4 = DeviceMU + "4"; +const std::string DeviceMU5 = DeviceMU + "5"; +const std::string DeviceMU6 = DeviceMU + "6"; +const std::string DeviceMU7 = DeviceMU + "7"; // 7 = Largest possible mu number EmuNtSymbolicLinkObject* NtSymbolicLinkObjects['Z' - 'A' + 1]; std::vector Devices; diff --git a/src/core/kernel/support/EmuFile.h b/src/core/kernel/support/EmuFile.h index 33c11bf3e..487d33949 100644 --- a/src/core/kernel/support/EmuFile.h +++ b/src/core/kernel/support/EmuFile.h @@ -73,6 +73,7 @@ extern const std::string DriveZ; extern const std::string DevicePrefix; extern const std::string DeviceCdrom0; extern const std::string DeviceHarddisk0; +extern const std::string DeviceMU; extern const std::string DeviceHarddisk0PartitionPrefix; extern const std::string DeviceHarddisk0Partition0; extern const std::string DeviceHarddisk0Partition1; @@ -95,6 +96,14 @@ extern const std::string DeviceHarddisk0Partition17; extern const std::string DeviceHarddisk0Partition18; extern const std::string DeviceHarddisk0Partition19; extern const std::string DeviceHarddisk0Partition20; +extern const std::string DeviceMU0; +extern const std::string DeviceMU1; +extern const std::string DeviceMU2; +extern const std::string DeviceMU3; +extern const std::string DeviceMU4; +extern const std::string DeviceMU5; +extern const std::string DeviceMU6; +extern const std::string DeviceMU7; constexpr char CxbxAutoMountDriveLetter = 'D'; extern std::string CxbxBasePath; @@ -318,6 +327,8 @@ typedef struct _FATX_SUPERBLOCK XboxPartitionTable CxbxGetPartitionTable(); FATX_SUPERBLOCK CxbxGetFatXSuperBlock(int partitionNumber); int CxbxGetPartitionNumberFromHandle(HANDLE hFile); +int CxbxGetPartitionNumberFromPath(const std::wstring_view path); +std::wstring CxbxGetFinalPathNameByHandle(HANDLE hFile); std::filesystem::path CxbxGetPartitionDataPathFromHandle(HANDLE hFile); void CxbxFormatPartitionByHandle(HANDLE hFile); diff --git a/src/gui/DlgInputConfig.cpp b/src/gui/DlgInputConfig.cpp index 03d567291..3530a9c96 100644 --- a/src/gui/DlgInputConfig.cpp +++ b/src/gui/DlgInputConfig.cpp @@ -161,7 +161,7 @@ INT_PTR CALLBACK DlgInputConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPAR HWND hHandle = GetDlgItem(hWndDlg, IDC_DEVICE_PORT1 + port); int DeviceType = SendMessage(hHandle, CB_GETITEMDATA, SendMessage(hHandle, CB_GETCURSEL, 0, 0), 0); g_Settings->m_input_port[port].Type = DeviceType; - if (DeviceType != to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE) || + if (DeviceType != to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE) && DeviceType != to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_S)) { // Forcefully set the child devices to none. This will happen if the user sets MUs in the controller dialog but // then they set the parent device to a device that cannot support them in the input dialog From 3e60c31d26f1f68525c7784ad9aaa3ecccce47dc Mon Sep 17 00:00:00 2001 From: ergo720 <45463469+ergo720@users.noreply.github.com> Date: Tue, 22 Jun 2021 00:38:59 +0200 Subject: [PATCH 7/9] Updated kernel file nt functions to support MUs + fixed bugs in xapi functions and input gui related to MUs --- import/XbSymbolDatabase | 2 +- src/common/input/InputDevice.h | 19 +- src/common/input/InputManager.cpp | 48 ++-- src/common/input/InputManager.h | 4 +- src/common/input/InputWindow.cpp | 12 +- src/common/input/InputWindow.h | 7 +- src/common/input/SdlJoystick.cpp | 15 +- src/common/input/SdlJoystick.h | 6 - src/core/hle/D3D8/Direct3D9/Direct3D9.cpp | 2 +- src/core/hle/D3D8/Direct3D9/Direct3D9.h | 3 +- src/core/hle/Patches.cpp | 4 +- src/core/hle/XAPI/Xapi.cpp | 239 +++++++++++------- src/core/hle/XAPI/Xapi.h | 12 + src/core/kernel/common/types.h | 1 + src/core/kernel/exports/EmuKrnlNt.cpp | 166 ++++++++---- src/core/kernel/init/CxbxKrnl.cpp | 29 ++- src/core/kernel/support/EmuFile.cpp | 127 +++++++++- src/core/kernel/support/EmuFile.h | 61 ++++- .../controllers/DlgDukeControllerConfig.cpp | 26 +- 19 files changed, 551 insertions(+), 232 deletions(-) diff --git a/import/XbSymbolDatabase b/import/XbSymbolDatabase index 9a411fea5..8b000c0ca 160000 --- a/import/XbSymbolDatabase +++ b/import/XbSymbolDatabase @@ -1 +1 @@ -Subproject commit 9a411fea58d97f4abe49e08893c57d6d9ff7f666 +Subproject commit 8b000c0ca7f20d88dddd95e80ad257ba2a0cffaa diff --git a/src/common/input/InputDevice.h b/src/common/input/InputDevice.h index 1438d61e2..a56ab1f9b 100644 --- a/src/common/input/InputDevice.h +++ b/src/common/input/InputDevice.h @@ -144,18 +144,23 @@ protected: public: // retrieves the map of input bindings - const std::map GetBindings() const { + const std::map GetBindings(const std::string &Port) const { std::lock_guard lck(m_BindingsMtx); - return m_Bindings; + return m_Bindings.find(Port)->second; } // sets a pair in the map of the input bindings - void SetBindings(int XButton, IoControl* Control) { + void SetBindings(int XButton, IoControl* Control, const std::string &Port) { std::lock_guard lck(m_BindingsMtx); - m_Bindings[XButton] = Control; + m_Bindings[Port][XButton] = Control; + } + // clears all input bindings for the specified xbox port + void ClearBindings(const std::string &Port) { + std::lock_guard lck(m_BindingsMtx); + m_Bindings[Port].clear(); } private: - // arbitrary ID assigned by to the device + // arbitrary ID assigned to the device int m_ID; // all the input controls detected and usable on this device std::vector m_Inputs; @@ -163,8 +168,8 @@ private: std::vector m_Outputs; // xbox port(s) this device is attached to std::vector m_XboxPort; - // button bindings to the xbox device buttons - std::map m_Bindings; + // per xbox port button bindings to the xbox device buttons + std::unordered_map> m_Bindings; }; #endif diff --git a/src/common/input/InputManager.cpp b/src/common/input/InputManager.cpp index 0c3346190..6bde93123 100644 --- a/src/common/input/InputManager.cpp +++ b/src/common/input/InputManager.cpp @@ -129,7 +129,7 @@ void InputDeviceManager::Initialize(bool is_gui, HWND hwnd) g_EmuShared->GetInputSlotTypeSettings(&type, i, slot); if (type != to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)) { assert(type == to_underlying(XBOX_INPUT_DEVICE::MEMORY_UNIT)); - ConstructHleInputDevice(&g_devs[MU_OFFSET + slot], &g_devs[CTRL_OFFSET + i], type, port + "." + std::to_string(slot)); + ConstructHleInputDevice(&g_devs[MU_OFFSET + (XBOX_CTRL_NUM_SLOTS * i) + slot], &g_devs[CTRL_OFFSET + i], type, port + "." + std::to_string(slot)); } } } @@ -225,7 +225,7 @@ void InputDeviceManager::RemoveDevice(std::function Ca void InputDeviceManager::UpdateDevices(std::string_view port, bool ack) { DeviceState *dev, *upstream; - int port1, type, slot; + int port1, slot, type; PortStr2Int(port, &port1, &slot); dev = &g_devs[port1]; @@ -234,16 +234,27 @@ void InputDeviceManager::UpdateDevices(std::string_view port, bool ack) g_EmuShared->GetInputDevTypeSettings(&type, port1); } else { // Port references a device attached to a slot port - assert(dev->type == XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE || - dev->type == XBOX_INPUT_DEVICE::MS_CONTROLLER_S); upstream = dev; dev = dev->slots[slot]; g_EmuShared->GetInputSlotTypeSettings(&type, port1, slot); } - // connect slot + // updating a slot if (dev == nullptr) { - ConnectDevice(&g_devs[MU_OFFSET + port1 + slot], upstream, type, port); + // connect slot + if (type != to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID) && + g_devs[MU_OFFSET + (XBOX_CTRL_NUM_SLOTS * port1) + slot].type == XBOX_INPUT_DEVICE::DEVICE_INVALID) { + ConnectDevice(&g_devs[MU_OFFSET + (XBOX_CTRL_NUM_SLOTS * port1) + slot], upstream, type, port); + } + // disconnect slot + else if (type == to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID) && + g_devs[MU_OFFSET + (XBOX_CTRL_NUM_SLOTS * port1) + slot].type != XBOX_INPUT_DEVICE::DEVICE_INVALID) { + DisconnectDevice(&g_devs[MU_OFFSET + (XBOX_CTRL_NUM_SLOTS * port1) + slot], port, ack); + } + // update bindings slot + else { + // MUs don't have any host devices attached, so this is a nop for now + } } // connect else if (type != to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID) && @@ -253,8 +264,8 @@ void InputDeviceManager::UpdateDevices(std::string_view port, bool ack) // disconnect else if (type == to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID) && dev->type != XBOX_INPUT_DEVICE::DEVICE_INVALID) { - // We don't need to check of we need to destroy child devices because the UpdateInputEvent_t message always - // calls us on the entire slot connectivity if the device has slots available + // We don't need to check if we need to destroy child devices because the UpdateInputEvent_t message always + // calls us on the entire slot connectivity of a port DisconnectDevice(dev, port, ack); } // update bindings @@ -309,7 +320,7 @@ void InputDeviceManager::DisconnectDevice(DeviceState *dev, std::string_view por void InputDeviceManager::BindHostDevice(int type, std::string_view port) { if (type == to_underlying(XBOX_INPUT_DEVICE::MEMORY_UNIT)) { - // MUs don't have any host device bound, so we just return + // MUs don't have any host devices bound, so we just return return; } @@ -322,6 +333,8 @@ void InputDeviceManager::BindHostDevice(int type, std::string_view port) auto dev = FindDevice(std::string(dev_name)); if (dev != nullptr) { + std::string port1(port); + dev->ClearBindings(port1); std::vector controls = dev->GetIoControls(); for (int index = 0; index < dev_num_buttons[type]; index++) { std::string dev_button(dev_control_names[index]); @@ -331,7 +344,7 @@ void InputDeviceManager::BindHostDevice(int type, std::string_view port) } return false; }); - dev->SetBindings(index, (it != controls.end()) ? *it : nullptr); + dev->SetBindings(index, (it != controls.end()) ? *it : nullptr, port1); } dev->SetPort(port, true); } @@ -348,18 +361,19 @@ bool InputDeviceManager::UpdateXboxPortInput(int port, void* buffer, int directi // If somebody else is currently holding the lock, we won't wait and instead report no input changes if (!g_renderbase->IsImGuiFocus() && m_Mtx.try_lock()) { for (auto &dev : m_Devices) { - if (dev->GetPort(std::to_string(port))) { + std::string port1 = std::to_string(port); + if (dev->GetPort(port1)) { switch (type) { case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE): case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_S): case to_underlying(XBOX_INPUT_DEVICE::ARCADE_STICK): - has_changed = UpdateInputXpad(dev, buffer, direction); + has_changed = UpdateInputXpad(dev, buffer, direction, port1); m_Mtx.unlock(); return has_changed; case to_underlying(XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER): - has_changed = UpdateInputSBC(dev, buffer, direction, port); + has_changed = UpdateInputSBC(dev, buffer, direction, port, port1); m_Mtx.unlock(); return has_changed; @@ -383,9 +397,9 @@ bool InputDeviceManager::UpdateXboxPortInput(int port, void* buffer, int directi return has_changed; } -bool InputDeviceManager::UpdateInputXpad(std::shared_ptr& Device, void* Buffer, int Direction) +bool InputDeviceManager::UpdateInputXpad(std::shared_ptr& Device, void* Buffer, int Direction, const std::string &Port1) { - std::map bindings = Device->GetBindings(); + std::map bindings = Device->GetBindings(Port1); assert(bindings.size() == static_cast(dev_num_buttons[to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE)])); if (Direction == DIRECTION_IN) { @@ -447,9 +461,9 @@ bool InputDeviceManager::UpdateInputXpad(std::shared_ptr& Device, v return true; } -bool InputDeviceManager::UpdateInputSBC(std::shared_ptr& Device, void* Buffer, int Direction, int Port) +bool InputDeviceManager::UpdateInputSBC(std::shared_ptr& Device, void* Buffer, int Direction, int Port, const std::string &Port1) { - std::map bindings = Device->GetBindings(); + std::map bindings = Device->GetBindings(Port1); assert(bindings.size() == static_cast(dev_num_buttons[to_underlying(XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER)])); // NOTE: the output state is not supported diff --git a/src/common/input/InputManager.h b/src/common/input/InputManager.h index c1acc856d..56605a806 100644 --- a/src/common/input/InputManager.h +++ b/src/common/input/InputManager.h @@ -165,9 +165,9 @@ public: private: // update input for an xbox controller - bool UpdateInputXpad(std::shared_ptr& Device, void* Buffer, int Direction); + bool UpdateInputXpad(std::shared_ptr& Device, void* Buffer, int Direction, const std::string &Port1); // update input for a Steel Battalion controller - bool UpdateInputSBC(std::shared_ptr& Device, void* Buffer, int Direction, int Port); + bool UpdateInputSBC(std::shared_ptr& Device, void* Buffer, int Direction, int Port, const std::string &Port1); // bind a host device to an emulated device void BindHostDevice(int type, std::string_view port); // connect a device to the emulated machine diff --git a/src/common/input/InputWindow.cpp b/src/common/input/InputWindow.cpp index 05b0bad3f..12d617037 100644 --- a/src/common/input/InputWindow.cpp +++ b/src/common/input/InputWindow.cpp @@ -43,7 +43,7 @@ InputWindow::~InputWindow() m_DeviceConfig = nullptr; } -int InputWindow::IsProfileSaved() +bool InputWindow::IsProfileSaved() { if (m_bHasChanges) { PopupReturn ret = PopupQuestion(m_hwnd_window, "Current configuration is not saved. Save before closing?"); @@ -53,24 +53,24 @@ int InputWindow::IsProfileSaved() char name[50]; SendMessage(m_hwnd_profile_list, WM_GETTEXT, sizeof(name), reinterpret_cast(name)); if (SaveProfile(std::string(name))) { - return EXIT_SAVE; + return true; } - return EXIT_ABORT; + return false; } case PopupReturn::No: { - return EXIT_IGNORE; + return true; } case PopupReturn::Cancel: default: { - return EXIT_ABORT; + return false; } } } - return EXIT_IGNORE; + return true; } void InputWindow::UpdateDeviceList() diff --git a/src/common/input/InputWindow.h b/src/common/input/InputWindow.h index cbad576d4..b0fcbdbff 100644 --- a/src/common/input/InputWindow.h +++ b/src/common/input/InputWindow.h @@ -42,10 +42,6 @@ #define BUTTON_SWAP 9 #define SLOTS_CHANGED 10 -#define EXIT_ABORT 0 -#define EXIT_SAVE 1 -#define EXIT_IGNORE 2 - #define XINPUT_DEFAULT 0 #define DINPUT_DEFAULT 1 @@ -65,7 +61,7 @@ public: virtual void ClearBindings() = 0; virtual void UpdateProfile(const std::string& name, int command); void UpdateCurrentDevice(); - virtual int IsProfileSaved(); + bool IsProfileSaved(); void SwapMoCursorAxis(Button *button); @@ -111,7 +107,6 @@ public: void BindDefault(); void ClearBindings() override; void UpdateProfile(const std::string &name, int command) override; - int IsProfileSaved() override; void SaveSlotConfig(); diff --git a/src/common/input/SdlJoystick.cpp b/src/common/input/SdlJoystick.cpp index bb4a0bf9d..e571ee3a7 100644 --- a/src/common/input/SdlJoystick.cpp +++ b/src/common/input/SdlJoystick.cpp @@ -163,20 +163,19 @@ namespace Sdl std::string port = std::to_string(*static_cast(Event.user.data1)); int port1, slot; PortStr2Int(port, &port1, &slot); - if (g_devs[port1].type == XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE || g_devs[port1].type == XBOX_INPUT_DEVICE::MS_CONTROLLER_S) { - // Force an update of the entire slot connectivity of this port - g_InputDeviceManager.UpdateDevices(port + ".0", false); - g_InputDeviceManager.UpdateDevices(port + ".1", false); - } + g_InputDeviceManager.UpdateDevices(port, false); + // Force an update of the entire slot connectivity of this port + g_InputDeviceManager.UpdateDevices(port + ".0", false); + g_InputDeviceManager.UpdateDevices(port + ".1", false); } - delete Event.user.data1; + delete static_cast(Event.user.data1); Event.user.data1 = nullptr; } else if (Event.type == DeviceRemoveAck_t) { - g_InputDeviceManager.UpdateDevices(std::string(static_cast(Event.user.data1)), true); - delete Event.user.data1; + g_InputDeviceManager.UpdateDevices(*static_cast(Event.user.data1), true); + delete static_cast(Event.user.data1); Event.user.data1 = nullptr; } } diff --git a/src/common/input/SdlJoystick.h b/src/common/input/SdlJoystick.h index 05055f7a9..b6d18008e 100644 --- a/src/common/input/SdlJoystick.h +++ b/src/common/input/SdlJoystick.h @@ -43,12 +43,6 @@ namespace Sdl } SDL_INIT_STATUS; - struct UPDATE_INPUT_DATA { - int Port; - int Slot; - bool Opt; - }; - extern uint32_t ExitEvent_t; extern uint32_t PopulateEvent_t; extern uint32_t UpdateInputEvent_t; diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index a4c759001..8a8daba8a 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -352,7 +352,7 @@ g_EmuCDPD; XB_TRAMPOLINES(XB_trampoline_declare); -void LookupTrampolines() +void LookupTrampolinesD3D() { XB_TRAMPOLINES(XB_trampoline_lookup); } diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.h b/src/core/hle/D3D8/Direct3D9/Direct3D9.h index eb402c85f..9d5a68fe5 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.h +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.h @@ -37,7 +37,8 @@ #define DIRECTDRAW_VERSION 0x0700 #include -extern void LookupTrampolines(); +extern void LookupTrampolinesD3D(); +extern void LookupTrampolinesXAPI(); // initialize render window extern void CxbxInitWindow(bool bFullInit); diff --git a/src/core/hle/Patches.cpp b/src/core/hle/Patches.cpp index 9e113068e..ad76ad3d4 100644 --- a/src/core/hle/Patches.cpp +++ b/src/core/hle/Patches.cpp @@ -365,6 +365,7 @@ std::map g_PatchTable = { PATCH_ENTRY("XSetProcessQuantumLength", xbox::EMUPATCH(XSetProcessQuantumLength), PATCH_ALWAYS), PATCH_ENTRY("timeKillEvent", xbox::EMUPATCH(timeKillEvent), PATCH_ALWAYS), PATCH_ENTRY("timeSetEvent", xbox::EMUPATCH(timeSetEvent), PATCH_ALWAYS), + PATCH_ENTRY("XReadMUMetaData", xbox::EMUPATCH(XReadMUMetaData), PATCH_ALWAYS), PATCH_ENTRY("XUnmountMU", xbox::EMUPATCH(XUnmountMU), PATCH_ALWAYS), }; @@ -445,7 +446,8 @@ void EmuInstallPatches() EmuInstallPatch(it.first, it.second); } - LookupTrampolines(); + LookupTrampolinesD3D(); + LookupTrampolinesXAPI(); } void* GetPatchedFunctionTrampoline(const std::string functionName) diff --git a/src/core/hle/XAPI/Xapi.cpp b/src/core/hle/XAPI/Xapi.cpp index a335e80ef..7949b86b1 100644 --- a/src/core/hle/XAPI/Xapi.cpp +++ b/src/core/hle/XAPI/Xapi.cpp @@ -43,8 +43,6 @@ #include "Windef.h" #include #include "core\hle\XAPI\Xapi.h" -#include "distorm.h" -#include "mnemonics.h" #include @@ -63,9 +61,26 @@ std::atomic g_bXppGuard = false; // 4 duke / S / sbc / arcade joystick (mutually exclusive) + 8 memory units DeviceState g_devs[4 + 8]; -xbox::ulong_xt g_Mounted_MUs = 0; // fallback if XapiMountedMUs is not found +xbox::ulong_xt g_Mounted_MUs = 0; +xbox::char_xt g_AltLett_MU = 0; xbox::ulong_xt *g_XapiMountedMUs = &g_Mounted_MUs; -std::mutex g_MuLock; +xbox::char_xt *g_XapiAltLett_MU = &g_AltLett_MU; +std::recursive_mutex g_MuLock; + +// Declare trampolines +#define XB_TRAMPOLINES(XB_MACRO) \ + XB_MACRO(xbox::dword_xt, WINAPI, XUnmountAlternateTitleA, (xbox::char_xt) ); \ + XB_MACRO(xbox::ntstatus_xt, WINAPI, XapiMapLetterToDirectory, (xbox::PSTRING, xbox::PSTRING, const xbox::PCHAR, xbox::bool_xt, xbox::PCWSTR, xbox::bool_xt) ); \ + +XB_TRAMPOLINES(XB_trampoline_declare); + +void LookupTrampolinesXAPI() +{ + XB_TRAMPOLINES(XB_trampoline_lookup); +} + +#undef XB_TRAMPOLINES + static inline xbox::char_xt MuPort2Lett(xbox::dword_xt port, xbox::dword_xt slot) { @@ -168,8 +183,6 @@ void UpdateXppState(DeviceState *dev, XBOX_INPUT_DEVICE type, std::string_view p while (g_bXppGuard) {} if (xpp == g_DeviceType_MU) { - assert((dev->upstream->type == XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE) || - (dev->upstream->type == XBOX_INPUT_DEVICE::MS_CONTROLLER_S)); assert(slot != PORT_INVALID); if (slot == 1) { slot_mask = 16; @@ -193,7 +206,7 @@ void ConstructHleInputDevice(DeviceState *dev, DeviceState *upstream, int type, if (g_bIsChihiro) { // Don't emulate XID devices during Chihiro Emulation g_bIsDevicesEmulating = false; - return ret; + return; } // Set up common device state int port1, slot; @@ -280,7 +293,7 @@ void DestructHleInputDevice(DeviceState *dev) dev->bSignaled = false; dev->slots[SLOT_TOP] = dev->slots[SLOT_BOTTOM] = nullptr; - switch (dev->type) + switch (type) { case XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE: case XBOX_INPUT_DEVICE::MS_CONTROLLER_S: @@ -314,8 +327,7 @@ void DestructHleInputDevice(DeviceState *dev) break; case XBOX_INPUT_DEVICE::MEMORY_UNIT: { - assert(dev->upstream != nullptr && (dev->upstream->type == XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE || - dev->upstream->type == XBOX_INPUT_DEVICE::MS_CONTROLLER_S)); + assert(dev->upstream != nullptr); int port1, slot; PortStr2Int(port, &port1, &slot); assert(slot != PORT_INVALID); @@ -403,77 +415,23 @@ void SetupXboxDeviceTypes() EmuLog(LOG_LEVEL::INFO, "XDEVICE_TYPE_GAMEPAD found at 0x%08X", (uintptr_t)g_DeviceType_Gamepad); } - // The MU device type is not present in the xpp table, because that only holds the types that XInputOpen supports, and MUs are not - // one of those. Insted, this type is referenced by MU_Init, the main MU initialization function, so we can derive it from that. - // Unfortunately, the offset of the MU type varies slightly between xdk revisions, so we cannot just read from a fixed offset. What's - // constant is that the type is always hardcoded in a push instruction immediately followed by a call, and there are no other push - call - // instructions between the start of MU_Init and the offset of interest. - - if (uint8_t *start = reinterpret_cast(g_SymbolAddresses["MU_Init"])) { - _CodeInfo ci; - ci.code = start; - ci.codeLen = 100; - ci.codeOffset = 0; - ci.dt = Decode32Bits; - ci.features = DF_NONE; - std::array<_DInst, 50> info; - unsigned i; - - distorm_decompose(&ci, info.data(), 50, &i); - - i = 0; - const auto &it = std::find_if(info.begin(), info.end(), [&info, &i](_DInst &op) { - if (!(op.opcode == I_PUSH)) { - ++i; - return false; - } - - if (((i + 1) <= 49) && (info[i + 1].opcode == I_CALL)) { - return true; - } - - ++i; - return false; - }); - - if (it == info.end()) { - EmuLog(LOG_LEVEL::WARNING, "XDEVICE_TYPE_MEMORY_UNIT was not found inside MU_Init"); - } - else { - g_DeviceType_MU = reinterpret_cast(*reinterpret_cast((it->addr + start + 1))); - EmuLog(LOG_LEVEL::INFO, "XDEVICE_TYPE_MEMORY_UNIT found at 0x%08X", reinterpret_cast(g_DeviceType_MU)); - } + if (xbox::addr_xt mu_xpp_type = g_SymbolAddresses["g_DeviceType_MU"]) { + g_DeviceType_MU = reinterpret_cast(mu_xpp_type); + EmuLog(LOG_LEVEL::INFO, "XDEVICE_TYPE_MEMORY_UNIT found at 0x%08X", reinterpret_cast(g_DeviceType_MU)); } else { - EmuLog(LOG_LEVEL::INFO, "XDEVICE_TYPE_MEMORY_UNIT was not found because MU_Init could not be found"); + EmuLog(LOG_LEVEL::INFO, "XDEVICE_TYPE_MEMORY_UNIT was not found by XbSymbolDatabase"); } - // Temporary code until XapiMountedMUs is derived by XbSymbolDatabase - Xbe::LibraryVersion *pLibraryVersion = reinterpret_cast(CxbxKrnl_Xbe->m_Header.dwLibraryVersionsAddr); - if (pLibraryVersion != nullptr) { - if (uint8_t *start = reinterpret_cast(g_SymbolAddresses["XUnmountMU"])) { - uint32_t offset = 0; - for (unsigned v = 0; v < CxbxKrnl_Xbe->m_Header.dwLibraryVersions; ++v) { - if (std::strcmp(pLibraryVersion[v].szName, "XAPILIB") == 0) { - if (pLibraryVersion[v].wBuildVersion < 4242) { - offset = 0x1D; - } - else { - offset = 0x2A; - } - break; - } - } - // skip 2 because the address is hard-coded inside a test instruction - g_XapiMountedMUs = reinterpret_cast(*reinterpret_cast((g_SymbolAddresses["XUnmountMU"] + offset + 2))); - EmuLog(LOG_LEVEL::INFO, "XapiMountedMUs found at 0x%08X", reinterpret_cast(g_XapiMountedMUs)); - } - else { - EmuLog(LOG_LEVEL::WARNING, "XapiMountedMUs was not found because XUnmountMU could not be found"); - } + if (xbox::addr_xt xapi_mounted_mu = g_SymbolAddresses["g_XapiMountedMUs"]) { + g_XapiMountedMUs = reinterpret_cast(xapi_mounted_mu); + EmuLog(LOG_LEVEL::INFO, "XapiMountedMUs found at 0x%08X", reinterpret_cast(g_XapiMountedMUs)); + + g_XapiAltLett_MU = reinterpret_cast(g_XapiMountedMUs - 1); + EmuLog(LOG_LEVEL::INFO, "XapiAltLett_MU found at 0x%08X", reinterpret_cast(g_XapiAltLett_MU)); } else { - EmuLog(LOG_LEVEL::WARNING, "XapiMountedMUs was not found because this xbe does not have a library version address"); + EmuLog(LOG_LEVEL::INFO, "XapiMountedMUs was not found by XbSymbolDatabase"); } } @@ -545,10 +503,10 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(XGetDevices) LOG_FUNC_ONE_ARG(DeviceType); g_bXppGuard = true; - static dword_xt last_connected = 0; + if (g_bIsDevicesInitializing || g_bIsDevicesEmulating) { g_bXppGuard = false; - RETURN(last_connected); + RETURN(DeviceType->CurrentConnected); } for (unsigned i = 0; i < 12; ++i) { @@ -558,15 +516,14 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(XGetDevices) SDL_Event DeviceRemoveEvent; SDL_memset(&DeviceRemoveEvent, 0, sizeof(SDL_Event)); DeviceRemoveEvent.type = Sdl::DeviceRemoveAck_t; - DeviceRemoveEvent.user.data1 = new char[g_devs[i].port.size()]; - std::strcpy(static_cast(DeviceRemoveEvent.user.data1), g_devs[i].port.c_str()); + DeviceRemoveEvent.user.data1 = new std::string(g_devs[i].port); SDL_PushEvent(&DeviceRemoveEvent); } } UCHAR oldIrql = xbox::KeRaiseIrqlToDpcLevel(); - last_connected = DeviceType->CurrentConnected; + dword_xt ret = DeviceType->CurrentConnected; DeviceType->ChangeConnected = 0; DeviceType->PreviousConnected = DeviceType->CurrentConnected; @@ -575,7 +532,7 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(XGetDevices) g_bXppGuard = false; - RETURN(last_connected); + RETURN(ret); } // ****************************************************************** @@ -613,8 +570,7 @@ xbox::bool_xt WINAPI xbox::EMUPATCH(XGetDeviceChanges) SDL_Event DeviceRemoveEvent; SDL_memset(&DeviceRemoveEvent, 0, sizeof(SDL_Event)); DeviceRemoveEvent.type = Sdl::DeviceRemoveAck_t; - DeviceRemoveEvent.user.data1 = new char[g_devs[i].port.size()]; - std::strcpy(static_cast(DeviceRemoveEvent.user.data1), g_devs[i].port.c_str()); + DeviceRemoveEvent.user.data1 = new std::string(g_devs[i].port); SDL_PushEvent(&DeviceRemoveEvent); } } @@ -1384,6 +1340,22 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(XMountMUA) RETURN(ERROR_ALREADY_ASSIGNED); } + char title_id_buff[9]; + std::sprintf(title_id_buff, "%08lx", CxbxKrnl_Xbe->m_Certificate.dwTitleId); + std::string mu_path_str(DrivePrefix + lett + ":"); + std::string mu_dev_str(DeviceMU + std::to_string(MuPort2Idx(dwPort, dwSlot))); + ANSI_STRING mu_dev, mu_path; + RtlInitAnsiString(&mu_path, mu_path_str.data()); + RtlInitAnsiString(&mu_dev, mu_dev_str.data()); + mu_dev_str += '\\'; + + ntstatus_xt status = XB_TRMP(XapiMapLetterToDirectory)(&mu_path, &mu_dev, title_id_buff, 1, + reinterpret_cast(CxbxKrnl_Xbe->m_Certificate.wsTitleName), 0); + + if (!nt_success(status)) { + RETURN(RtlNtStatusToDosError(status)); + } + MuSetMounted(lett); if (pchDrive != zeroptr) { *pchDrive = lett; @@ -1465,8 +1437,7 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(XMountMURootA) if (pchDrive != zeroptr) { *pchDrive = 0; } - RtlNtStatusToDosError(status); - RETURN(status); + RETURN(RtlNtStatusToDosError(status)); } MuSetMounted(lett); @@ -1498,21 +1469,115 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(XUnmountMU) RETURN(ERROR_INVALID_DRIVE); } + if (*g_XapiAltLett_MU == lett) { + XB_TRMP(XUnmountAlternateTitleA)('X'); + } + std::string mu_path_str(DrivePrefix + lett + ":"); ANSI_STRING mu_path; RtlInitAnsiString(&mu_path, mu_path_str.data()); ntstatus_xt status = IoDeleteSymbolicLink(&mu_path); if (!nt_success(status)) { - RtlNtStatusToDosError(status); - RETURN(status); + RETURN(RtlNtStatusToDosError(status)); } MuClearMounted(lett); + g_io_mu_metadata->flush(static_cast(lett)); RETURN(ERROR_SUCCESS); } +// ****************************************************************** +// * patch: XReadMUMetaData +// ****************************************************************** +xbox::dword_xt WINAPI xbox::EMUPATCH(XReadMUMetaData) +( + IN dword_xt dwPort, + IN dword_xt dwSlot, + IN LPVOID lpBuffer, + IN dword_xt dwByteOffset, + IN dword_xt dwNumberOfBytesToRead +) +{ + LOG_FUNC_BEGIN + LOG_FUNC_ARG(dwPort) + LOG_FUNC_ARG(dwSlot) + LOG_FUNC_ARG(lpBuffer) + LOG_FUNC_ARG(dwByteOffset) + LOG_FUNC_ARG(dwNumberOfBytesToRead) + LOG_FUNC_END; + + // NOTE: in reality, this function should actually use IoSynchronousFsdRequest to read the metadata of the MU. Unfortunately, + // that requires kernel support for device objects, which when this was implemented, was non-existent. So, we instead cheat + // and use NtFsControlFile to perform the same action. + + std::lock_guard lock(g_MuLock); + + bool unmount = false; + char_xt lett = MuPort2Lett(dwPort, dwSlot); + if (!MuIsMounted(lett)) { + unmount = true; + dword_xt ret = EMUPATCH(XMountMURootA(dwPort, dwSlot, &lett)); + if (ret != ERROR_SUCCESS) { + RETURN(ret); + } + } + + OBJECT_ATTRIBUTES obj; + std::string mu_path_str(DrivePrefix + lett + ":"); + ANSI_STRING mu_path; + RtlInitAnsiString(&mu_path, mu_path_str.data()); + XB_InitializeObjectAttributes(&obj, &mu_path, obj_case_insensitive, ObDosDevicesDirectory()); + + HANDLE handle; + IO_STATUS_BLOCK io_status_block; + ntstatus_xt status = NtOpenFile(&handle, + SYNCHRONIZE | GENERIC_READ, + &obj, + &io_status_block, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_SYNCHRONOUS_IO_ALERT); + + if (nt_success(status)) { + fatx_volume_metadata volume; + volume.offset = dwByteOffset; + volume.length = dwNumberOfBytesToRead; + volume.buffer = new char[dwNumberOfBytesToRead]; + + status = NtFsControlFile(handle, + zeroptr, + zeroptr, + zeroptr, + &io_status_block, + fsctl_read_fatx_metadata, + &volume, + sizeof(volume), + zeroptr, + 0); + + if (nt_success(status)) { + std::memcpy(lpBuffer, volume.buffer, dwNumberOfBytesToRead); + status = status_success; + } + else { + status = status_unrecognized_volume; + } + + delete[] volume.buffer; + NtClose(handle); + } + else { + status = status_unrecognized_volume; + } + + if (unmount) { + EMUPATCH(XUnmountMU(dwPort, dwSlot)); + } + + RETURN(RtlNtStatusToDosError(status)); +} + // ****************************************************************** // * patch: OutputDebugStringA // ****************************************************************** diff --git a/src/core/hle/XAPI/Xapi.h b/src/core/hle/XAPI/Xapi.h index 3902fd71e..b70125f64 100644 --- a/src/core/hle/XAPI/Xapi.h +++ b/src/core/hle/XAPI/Xapi.h @@ -693,6 +693,18 @@ xbox::dword_xt WINAPI EMUPATCH(XUnmountMU) dword_xt dwSlot ); +// ****************************************************************** +// * patch: XReadMUMetaData +// ****************************************************************** +xbox::dword_xt WINAPI EMUPATCH(XReadMUMetaData) +( + IN dword_xt dwPort, + IN dword_xt dwSlot, + IN LPVOID lpBuffer, + IN dword_xt dwByteOffset, + IN dword_xt dwNumberOfBytesToRead +); + // ****************************************************************** // * patch: XMountAlternateTitleA // ****************************************************************** diff --git a/src/core/kernel/common/types.h b/src/core/kernel/common/types.h index d579da3a5..b7afa1bbd 100644 --- a/src/core/kernel/common/types.h +++ b/src/core/kernel/common/types.h @@ -100,6 +100,7 @@ inline constexpr dword_xt status_unable_to_free_vm = 0xC000001AL; inline constexpr dword_xt status_free_vm_not_at_base = 0xC000009FL; inline constexpr dword_xt status_memory_not_allocated = 0xC00000A0L; inline constexpr dword_xt status_not_committed = 0xC000002DL; +inline constexpr dword_xt status_unrecognized_volume = 0xC000014FL; // ****************************************************************** // * Registry value types diff --git a/src/core/kernel/exports/EmuKrnlNt.cpp b/src/core/kernel/exports/EmuKrnlNt.cpp index 633b826a1..7f672a7f1 100644 --- a/src/core/kernel/exports/EmuKrnlNt.cpp +++ b/src/core/kernel/exports/EmuKrnlNt.cpp @@ -619,8 +619,7 @@ XBSYSAPI EXPORTNUM(196) xbox::ntstatus_xt NTAPI xbox::NtDeviceIoControlFile switch (IoControlCode) { - case 0x4D014: // IOCTL_SCSI_PASS_THROUGH_DIRECT - { + case 0x4D014: { // IOCTL_SCSI_PASS_THROUGH_DIRECT PSCSI_PASS_THROUGH_DIRECT PassThrough = (PSCSI_PASS_THROUGH_DIRECT)InputBuffer; PDVDX2_AUTHENTICATION Authentication = (PDVDX2_AUTHENTICATION)PassThrough->DataBuffer; @@ -628,34 +627,63 @@ XBSYSAPI EXPORTNUM(196) xbox::ntstatus_xt NTAPI xbox::NtDeviceIoControlFile Authentication->AuthenticationPage.CDFValid = 1; Authentication->AuthenticationPage.PartitionArea = 1; Authentication->AuthenticationPage.Authentication = 1; - break; } - case 0x70000: // IOCTL_DISK_GET_DRIVE_GEOMETRY - { + break; + + case 0x70000: { // IOCTL_DISK_GET_DRIVE_GEOMETRY PDISK_GEOMETRY DiskGeometry = (PDISK_GEOMETRY)OutputBuffer; - DiskGeometry->MediaType = FixedMedia; - DiskGeometry->TracksPerCylinder = 1; - DiskGeometry->SectorsPerTrack = 1; - DiskGeometry->BytesPerSector = 512; - DiskGeometry->Cylinders.QuadPart = 0x1400000; // Around 10GB, size of stock xbox HDD - break; + DeviceType type = CxbxrGetDeviceTypeFromHandle(FileHandle); + if (type == DeviceType::Harddisk0) { + DiskGeometry->MediaType = FixedMedia; + DiskGeometry->TracksPerCylinder = 1; + DiskGeometry->SectorsPerTrack = 1; + DiskGeometry->BytesPerSector = 512; + DiskGeometry->Cylinders.QuadPart = 0x1400000; // 10GB, size of stock xbox HDD + } + else if (type == DeviceType::MU) { + DiskGeometry->MediaType = FixedMedia; + DiskGeometry->TracksPerCylinder = 1; + DiskGeometry->SectorsPerTrack = 1; + DiskGeometry->BytesPerSector = 512; + DiskGeometry->Cylinders.QuadPart = 0x4000; // 8MB, Microsoft original MUs + } + else { + EmuLog(LOG_LEVEL::WARNING, "%s: Unrecongnized handle 0x%X with IoControlCode IOCTL_DISK_GET_DRIVE_GEOMETRY.", __func__, FileHandle); + ret = status_invalid_handle; + } } - case 0x74004: // IOCTL_DISK_GET_PARTITION_INFO - { + break; + + case 0x74004: { // IOCTL_DISK_GET_PARTITION_INFO PPARTITION_INFORMATION partitioninfo = (PPARTITION_INFORMATION)OutputBuffer; - XboxPartitionTable partitionTable = CxbxGetPartitionTable(); - int partitionNumber = CxbxGetPartitionNumberFromHandle(FileHandle); - - // Now we read from the partition table, to fill in the partitionInfo struct - partitioninfo->PartitionNumber = partitionNumber; - partitioninfo->StartingOffset.QuadPart = partitionTable.TableEntries[partitionNumber - 1].LBAStart * 512; - partitioninfo->PartitionLength.QuadPart = partitionTable.TableEntries[partitionNumber - 1].LBASize * 512; - partitioninfo->HiddenSectors = partitionTable.TableEntries[partitionNumber - 1].Reserved; - partitioninfo->RecognizedPartition = true; - break; + DeviceType type = CxbxrGetDeviceTypeFromHandle(FileHandle); + if (type == DeviceType::Harddisk0) { + XboxPartitionTable partitionTable = CxbxGetPartitionTable(); + int partitionNumber = CxbxGetPartitionNumberFromHandle(FileHandle); + + // Now we read from the partition table, to fill in the partitionInfo struct + partitioninfo->PartitionNumber = partitionNumber; + partitioninfo->StartingOffset.QuadPart = partitionTable.TableEntries[partitionNumber - 1].LBAStart * 512; + partitioninfo->PartitionLength.QuadPart = partitionTable.TableEntries[partitionNumber - 1].LBASize * 512; + partitioninfo->HiddenSectors = partitionTable.TableEntries[partitionNumber - 1].Reserved; + partitioninfo->RecognizedPartition = true; + } + else if (type == DeviceType::MU) { + partitioninfo->PartitionNumber = 0; + partitioninfo->StartingOffset.QuadPart = 0; // FIXME: where does the MU partition start? + partitioninfo->PartitionLength.QuadPart = 16384; // 8MB + partitioninfo->HiddenSectors = 0; + partitioninfo->RecognizedPartition = true; + } + else { + EmuLog(LOG_LEVEL::WARNING, "%s: Unrecongnized handle 0x%X with IoControlCode IOCTL_DISK_GET_PARTITION_INFO.", __func__, FileHandle); + ret = status_invalid_handle; + } } + break; + default: LOG_UNIMPLEMENTED(); } @@ -802,19 +830,55 @@ XBSYSAPI EXPORTNUM(200) xbox::ntstatus_xt NTAPI xbox::NtFsControlFile LOG_FUNC_ARG(OutputBufferLength) LOG_FUNC_END; - NTSTATUS ret = STATUS_INVALID_PARAMETER; + ntstatus_xt ret = STATUS_INVALID_PARAMETER; + + switch (FsControlCode) + { + case fsctl_dismount_volume: { + int partitionNumber = CxbxGetPartitionNumberFromHandle(FileHandle); + if (partitionNumber > 0) { + CxbxFormatPartitionByHandle(FileHandle); + ret = xbox::status_success; + } + } + break; + + case fsctl_read_fatx_metadata: { + const std::wstring path = CxbxGetFinalPathNameByHandle(FileHandle); + size_t pos = path.rfind(L"\\EmuMu"); + if (pos != std::string::npos && path[pos + 6] == '\\') { + // Ensure that InputBuffer is indeed what we think it is + pfatx_volume_metadata volume = static_cast(InputBuffer); + assert(InputBufferLength == sizeof(fatx_volume_metadata)); + g_io_mu_metadata->read(path[pos + 7], volume->offset, static_cast(volume->buffer), volume->length); + ret = xbox::status_success; + } + else { + ret = status_invalid_handle; + } + } + break; + + case fsctl_write_fatx_metadata: { + const std::wstring path = CxbxGetFinalPathNameByHandle(FileHandle); + size_t pos = path.rfind(L"\\EmuMu"); + if (pos != std::string::npos && path[pos + 6] == '\\') { + // Ensure that InputBuffer is indeed what we think it is + pfatx_volume_metadata volume = static_cast(InputBuffer); + assert(InputBufferLength == sizeof(fatx_volume_metadata)); + g_io_mu_metadata->write(path[pos + 7], volume->offset, static_cast(volume->buffer), volume->length); + ret = xbox::status_success; + } + else { + ret = status_invalid_handle; + } + } + break; - switch (FsControlCode) { - case 0x00090020: // FSCTL_DISMOUNT_VOLUME - int partitionNumber = CxbxGetPartitionNumberFromHandle(FileHandle); - if (partitionNumber > 0) { - CxbxFormatPartitionByHandle(FileHandle); - ret = xbox::status_success; - } - break; } - LOG_UNIMPLEMENTED(); + LOG_INCOMPLETE(); + RETURN(ret); } @@ -1499,16 +1563,15 @@ XBSYSAPI EXPORTNUM(218) xbox::ntstatus_xt NTAPI xbox::NtQueryVolumeInformationFi // FileFsSizeInformation is a special case that should read from our emulated partition table if ((DWORD)FileInformationClass == FileFsSizeInformation) { + ntstatus_xt status; PFILE_FS_SIZE_INFORMATION XboxSizeInfo = (PFILE_FS_SIZE_INFORMATION)FileInformation; - // This might access the HDD or a MU, so we need to figure out the correct one first - const std::wstring path = CxbxGetFinalPathNameByHandle(FileHandle); - size_t pos = path.rfind(L"\\EmuDisk\\Partition"); - if (pos != std::string::npos) { - // We are accessing a disk partition + // This might access the HDD, a MU or the DVD drive, so we need to figure out the correct one first + DeviceType type = CxbxrGetDeviceTypeFromHandle(FileHandle); + if (type == DeviceType::Harddisk0) { XboxPartitionTable partitionTable = CxbxGetPartitionTable(); - int partitionNumber = CxbxGetPartitionNumberFromPath(path); + int partitionNumber = CxbxGetPartitionNumberFromHandle(FileHandle); FATX_SUPERBLOCK superBlock = CxbxGetFatXSuperBlock(partitionNumber); XboxSizeInfo->BytesPerSector = 512; @@ -1525,24 +1588,31 @@ XBSYSAPI EXPORTNUM(218) xbox::ntstatus_xt NTAPI xbox::NtQueryVolumeInformationFi XboxSizeInfo->TotalAllocationUnits.QuadPart = partitionTable.TableEntries[partitionNumber - 1].LBASize / XboxSizeInfo->SectorsPerAllocationUnit; XboxSizeInfo->AvailableAllocationUnits.QuadPart = partitionTable.TableEntries[partitionNumber - 1].LBASize / XboxSizeInfo->SectorsPerAllocationUnit; - RETURN(xbox::status_success); + status = status_success; } - - pos = path.rfind(L"\\EmuMu"); - if (pos != std::string::npos) { - // We are accessing a MU + else if (type == DeviceType::MU) { XboxSizeInfo->BytesPerSector = 512; XboxSizeInfo->SectorsPerAllocationUnit = 32; XboxSizeInfo->TotalAllocationUnits.QuadPart = 512; // 8MB -> ((1024)^2 * 8) / (BytesPerSector * SectorsPerAllocationUnit) XboxSizeInfo->AvailableAllocationUnits.QuadPart = 512; // constant, so there's always free space available to write stuff - RETURN(xbox::status_success); + status = status_success; + } + else if (type == DeviceType::Cdrom0) { + + XboxSizeInfo->BytesPerSector = 2048; + XboxSizeInfo->SectorsPerAllocationUnit = 1; + XboxSizeInfo->TotalAllocationUnits.QuadPart = 3820880; // assuming DVD-9 (dual layer), redump reports a total size in bytes of 7825162240 + + status = status_success; + } + else { + EmuLog(LOG_LEVEL::WARNING, "%s: Unrecongnized handle 0x%X with class FileFsSizeInformation.", __func__, FileHandle); + status = status_invalid_handle; } - EmuLog(LOG_LEVEL::WARNING, "%s: Unrecongnized handle 0x%X with class FileFsSizeInformation", __func__, FileHandle); - - RETURN(xbox::status_invalid_handle); + RETURN(status); } // Get the required size for the host buffer diff --git a/src/core/kernel/init/CxbxKrnl.cpp b/src/core/kernel/init/CxbxKrnl.cpp index 99dfb5dcf..edd786d6a 100644 --- a/src/core/kernel/init/CxbxKrnl.cpp +++ b/src/core/kernel/init/CxbxKrnl.cpp @@ -1509,15 +1509,21 @@ __declspec(noreturn) void CxbxKrnlInit CxbxRegisterDeviceHostPath(DeviceHarddisk0Partition7, CxbxBasePath + "Partition7"); CxbxRegisterDeviceHostPath(DevicePrefix + "\\Chihiro", CxbxBasePath + "Chihiro"); - // Create the MU directories - CxbxRegisterDeviceHostPath(DeviceMU0, MuBasePath + "F"); - CxbxRegisterDeviceHostPath(DeviceMU1, MuBasePath + "G"); - CxbxRegisterDeviceHostPath(DeviceMU2, MuBasePath + "H"); - CxbxRegisterDeviceHostPath(DeviceMU3, MuBasePath + "I"); - CxbxRegisterDeviceHostPath(DeviceMU4, MuBasePath + "J"); - CxbxRegisterDeviceHostPath(DeviceMU5, MuBasePath + "K"); - CxbxRegisterDeviceHostPath(DeviceMU6, MuBasePath + "L"); - CxbxRegisterDeviceHostPath(DeviceMU7, MuBasePath + "M"); + // Create the MU directories and the bin files + CxbxRegisterDeviceHostPath(DeviceMU0, MuBasePath + "F", false, sizeof(FATX_SUPERBLOCK)); + CxbxRegisterDeviceHostPath(DeviceMU1, MuBasePath + "G", false, sizeof(FATX_SUPERBLOCK)); + CxbxRegisterDeviceHostPath(DeviceMU2, MuBasePath + "H", false, sizeof(FATX_SUPERBLOCK)); + CxbxRegisterDeviceHostPath(DeviceMU3, MuBasePath + "I", false, sizeof(FATX_SUPERBLOCK)); + CxbxRegisterDeviceHostPath(DeviceMU4, MuBasePath + "J", false, sizeof(FATX_SUPERBLOCK)); + CxbxRegisterDeviceHostPath(DeviceMU5, MuBasePath + "K", false, sizeof(FATX_SUPERBLOCK)); + CxbxRegisterDeviceHostPath(DeviceMU6, MuBasePath + "L", false, sizeof(FATX_SUPERBLOCK)); + CxbxRegisterDeviceHostPath(DeviceMU7, MuBasePath + "M", false, sizeof(FATX_SUPERBLOCK)); + + std::mbstate_t ps = std::mbstate_t(); + const char *src = MuBasePath.c_str(); + std::wstring wMuBasePath(MuBasePath.size(), L'0'); + std::mbsrtowcs(wMuBasePath.data(), &src, wMuBasePath.size(), &ps); + g_io_mu_metadata = new io_mu_metadata(wMuBasePath); // Create default symbolic links : EmuLogInit(LOG_LEVEL::DEBUG, "Creating default symbolic links."); @@ -1942,6 +1948,11 @@ void CxbxKrnlShutDown(bool is_reboot) // Shutdown the memory manager g_VMManager.Shutdown(); + if (g_io_mu_metadata) { + delete g_io_mu_metadata; + g_io_mu_metadata = nullptr; + } + // Shutdown the render manager if (g_renderbase != nullptr) { g_renderbase->Shutdown(); diff --git a/src/core/kernel/support/EmuFile.cpp b/src/core/kernel/support/EmuFile.cpp index 846b6c651..c96f2dae1 100644 --- a/src/core/kernel/support/EmuFile.cpp +++ b/src/core/kernel/support/EmuFile.cpp @@ -31,13 +31,13 @@ #include #include #include +#include #include #include #include #pragma warning(disable:4005) // Ignore redefined status values #include #pragma warning(default:4005) -#include "core\kernel\init\CxbxKrnl.h" #include "Logging.h" #include "common/util/strConverter.hpp" // utf16_to_ascii #include "common/util/cliConfig.hpp" @@ -84,7 +84,102 @@ XboxPartitionTable BackupPartTbl = } }; -void CxbxCreatePartitionHeaderFile(std::string filename, bool partition0 = false) +io_mu_metadata *g_io_mu_metadata = nullptr; + +io_mu_metadata::io_mu_metadata(const std::wstring_view root_path) : m_root_path(root_path) +{ + for (unsigned i = 0; i < 8; ++i) { + m_buff[i] = new char[sizeof(FATX_SUPERBLOCK)]; + assert(m_buff[i] != nullptr); + std::wstring path = m_root_path + static_cast(L'F' + i) + L".bin"; + std::fstream fs(path, std::ios_base::in | std::ios_base::out | std::ios_base::binary); + if (!fs.is_open()) { + CxbxKrnlCleanup("%s: could not open MU bin file at \"%ls\"!", __func__, path.c_str()); + } + fs.seekg(0); + fs.read(m_buff[i], sizeof(FATX_SUPERBLOCK)); + // if the signature is not "fatx" or we read less bytes than expected, then we assume the bin file is either corrupted or + // unformatted, so we reformat it now + FATX_SUPERBLOCK *volume = reinterpret_cast(m_buff[i]); + if ((fs.gcount() != sizeof(FATX_SUPERBLOCK)) || (volume->Signature != fatx_signature)) { + volume->Signature = fatx_signature; + volume->VolumeID = 0x11223344 + i; + volume->ClusterSize = 32; + volume->FatCopies = 1; + std::memset(volume->Name, 0, mu_max_name_lenght); + std::memset(volume->OnlineData, 0, fatx_online_data_length); + std::memset(volume->Unused, 0xFF, fatx_reserved_length); + fs.write(m_buff[i], sizeof(FATX_SUPERBLOCK)); + } + } +} + +io_mu_metadata::~io_mu_metadata() +{ + std::unique_lock lck(m_rw_lock); + for (unsigned i = 0; i < 8; ++i) { + std::wstring path = m_root_path + static_cast(L'F' + i) + L".bin"; + std::ofstream ofs(path, std::ios_base::out | std::ios_base::binary); + if (!ofs.is_open()) { + EmuLog(LOG_LEVEL::ERROR2, "%s: could not open MU bin file at \"%ls\"!", __func__, path.c_str()); + delete[] m_buff[i]; + continue; + } + ofs.seekp(0); + ofs.write(m_buff[i], sizeof(FATX_SUPERBLOCK)); + delete[] m_buff[i]; + } +} + +void io_mu_metadata::read(const wchar_t lett, std::size_t offset, char *buff, std::size_t size) +{ + std::shared_lock lck(m_rw_lock); // allows for concurrent reads + std::memcpy(buff, m_buff[lett - L'F'] + offset, size); +} + +void io_mu_metadata::write(const wchar_t lett, std::size_t offset, const char *buff, std::size_t size) +{ + std::unique_lock lck(m_rw_lock); // blocks when there is rw in progress + std::memcpy(m_buff[lett - L'F'] + offset, buff, size); +} + +void io_mu_metadata::flush(const wchar_t lett) +{ + std::unique_lock lck(m_rw_lock); + std::wstring path = m_root_path + lett + L".bin"; + std::ofstream ofs(path, std::ios_base::out | std::ios_base::binary); + if (!ofs.is_open()) { + EmuLog(LOG_LEVEL::ERROR2, "%s: could not open MU bin file at \"%ls\"!", __func__, path.c_str()); + return; + } + ofs.seekp(0); + ofs.write(m_buff[lett - L'F'], sizeof(FATX_SUPERBLOCK)); + ofs.flush(); +} + +DeviceType CxbxrGetDeviceTypeFromHandle(HANDLE hFile) +{ + const std::wstring path = CxbxGetFinalPathNameByHandle(hFile); + + size_t pos = path.rfind(L"\\EmuDisk\\Partition"); + if (pos != std::string::npos) { + return DeviceType::Harddisk0; + } + + pos = path.rfind(L"\\EmuMu"); + if (pos != std::string::npos) { + return DeviceType::MU; + } + + EmuNtSymbolicLinkObject *ret = FindNtSymbolicLinkObjectByDevice(DeviceCdrom0); + if (ret != nullptr && path.rfind(ret->wHostSymbolicLinkPath) != std::string::npos) { + return DeviceType::Cdrom0; + } + + return DeviceType::Invalid; +} + +void CxbxCreatePartitionHeaderFile(std::string filename, bool partition0 = false, std::size_t size = 512 * ONE_KB) { HANDLE hf = CreateFile(filename.c_str(), GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0); if (!hf) { @@ -98,7 +193,7 @@ void CxbxCreatePartitionHeaderFile(std::string filename, bool partition0 = false WriteFile(hf, &BackupPartTbl, sizeof(XboxPartitionTable), &NumberOfBytesWritten, 0); } - SetFilePointer(hf, 512 * ONE_KB, 0, FILE_BEGIN); + SetFilePointer(hf, size, 0, FILE_BEGIN); SetEndOfFile(hf); CloseHandle(hf); } @@ -701,7 +796,7 @@ std::string CxbxConvertXboxToHostPath(const std::string_view XboxDevicePath) return XbePath; } -int CxbxRegisterDeviceHostPath(const std::string_view XboxDevicePath, std::string HostDevicePath, bool IsFile) +int CxbxRegisterDeviceHostPath(const std::string_view XboxDevicePath, std::string HostDevicePath, bool IsFile, std::size_t size) { XboxDevice newDevice; newDevice.XboxDevicePath = XboxDevicePath; @@ -709,11 +804,12 @@ int CxbxRegisterDeviceHostPath(const std::string_view XboxDevicePath, std::strin bool succeeded{ false }; - // All HDD partitions have a .bin file to allow direct file io on the partition info - if (_strnicmp(XboxDevicePath.data(), DeviceHarddisk0PartitionPrefix.c_str(), DeviceHarddisk0PartitionPrefix.length()) == 0) { + // All HDD and MU partitions have a .bin file to allow direct file io on the partition info + if (_strnicmp(XboxDevicePath.data(), DeviceHarddisk0PartitionPrefix.c_str(), DeviceHarddisk0PartitionPrefix.length()) == 0 || + _strnicmp(XboxDevicePath.data(), DeviceMU.c_str(), DeviceMU.length()) == 0) { std::string partitionHeaderPath = HostDevicePath + ".bin"; if (!std::filesystem::exists(partitionHeaderPath)) { - CxbxCreatePartitionHeaderFile(partitionHeaderPath, XboxDevicePath == DeviceHarddisk0Partition0); + CxbxCreatePartitionHeaderFile(partitionHeaderPath, XboxDevicePath == DeviceHarddisk0Partition0, size); } succeeded = true; @@ -833,6 +929,10 @@ NTSTATUS EmuNtSymbolicLinkObject::Init(std::string aSymbolicLinkName, std::strin } else { + std::mbstate_t ps = std::mbstate_t(); + const char *src = HostSymbolicLinkPath.c_str(); + wHostSymbolicLinkPath.resize(HostSymbolicLinkPath.size()); + std::mbsrtowcs(wHostSymbolicLinkPath.data(), &src, wHostSymbolicLinkPath.size(), &ps); NtSymbolicLinkObjects[DriveLetter - 'A'] = this; EmuLog(LOG_LEVEL::DEBUG, "Linked \"%s\" to \"%s\" (residing at \"%s\")", aSymbolicLinkName.c_str(), aFullPath.c_str(), HostSymbolicLinkPath.c_str()); } @@ -918,6 +1018,19 @@ EmuNtSymbolicLinkObject* FindNtSymbolicLinkObjectByRootHandle(const HANDLE Handl } +EmuNtSymbolicLinkObject *FindNtSymbolicLinkObjectByDevice(const std::string_view Device) +{ + for (char DriveLetter = 'A'; DriveLetter <= 'Z'; DriveLetter++) + { + EmuNtSymbolicLinkObject *result = NtSymbolicLinkObjects[DriveLetter - 'A']; + if ((result != nullptr) && (result->XboxSymbolicLinkPath == Device)) + return result; + } + + return nullptr; +} + + void _CxbxPVOIDDeleter(PVOID *ptr) { if (*ptr) { diff --git a/src/core/kernel/support/EmuFile.h b/src/core/kernel/support/EmuFile.h index 487d33949..fe0dabc52 100644 --- a/src/core/kernel/support/EmuFile.h +++ b/src/core/kernel/support/EmuFile.h @@ -26,6 +26,7 @@ #include +#include "core\kernel\init\CxbxKrnl.h" #include #include #include @@ -106,6 +107,18 @@ extern const std::string DeviceMU6; extern const std::string DeviceMU7; constexpr char CxbxAutoMountDriveLetter = 'D'; +enum class DeviceType : int { + Invalid = -1, + Cdrom0, + Harddisk0, + MU, +}; + +inline constexpr xbox::ulong_xt fsctl_dismount_volume = 0x00090020; +inline constexpr xbox::ulong_xt fsctl_read_fatx_metadata = 0x0009411C; +inline constexpr xbox::ulong_xt fsctl_write_fatx_metadata = 0x00098120; + +inline constexpr std::size_t mu_max_name_lenght = 32 * sizeof(xbox::wchar_xt); // MU names are in wide chars extern std::string CxbxBasePath; extern HANDLE CxbxBasePathHandle; @@ -218,6 +231,7 @@ public: bool IsHostBasedPath; std::string XboxSymbolicLinkPath; std::string HostSymbolicLinkPath; + std::wstring wHostSymbolicLinkPath; HANDLE RootDirectoryHandle; NTSTATUS Init(std::string aSymbolicLinkName, std::string aFullPath); ~EmuNtSymbolicLinkObject(); @@ -235,9 +249,31 @@ struct EmuDirPath { HANDLE HostDirHandle; }; +typedef struct _fatx_volume_metadata { + xbox::dword_xt offset; + xbox::dword_xt length; + xbox::PVOID buffer; +} fatx_volume_metadata, *pfatx_volume_metadata; + CHAR* NtStatusToString(IN NTSTATUS Status); -int CxbxRegisterDeviceHostPath(std::string_view XboxFullPath, std::string HostDevicePath, bool IsFile = false); +class io_mu_metadata +{ +public: + io_mu_metadata(const std::wstring_view root_path); + ~io_mu_metadata(); + void read(const wchar_t lett, std::size_t offset, char *buff, std::size_t size); + void write(const wchar_t lett, std::size_t offset, const char *buff, std::size_t size); + void flush(const wchar_t lett); + +private: + char *m_buff[8]; + const std::wstring m_root_path; + std::shared_mutex m_rw_lock; +}; +extern io_mu_metadata *g_io_mu_metadata; + +int CxbxRegisterDeviceHostPath(std::string_view XboxFullPath, std::string HostDevicePath, bool IsFile = false, std::size_t size = 512 * ONE_KB); int CxbxDeviceIndexByDevicePath(const char *XboxDevicePath); XboxDevice* CxbxDeviceByDevicePath(const std::string_view XboxDevicePath); XboxDevice* CxbxDeviceByHostPath(const std::string_view HostPath); @@ -248,6 +284,8 @@ EmuNtSymbolicLinkObject* FindNtSymbolicLinkObjectByDriveLetter(const char DriveL EmuNtSymbolicLinkObject* FindNtSymbolicLinkObjectByName(std::string SymbolicLinkName); void FindEmuDirPathByDevice(std::string DeviceName, EmuDirPath& hybrid_path); EmuNtSymbolicLinkObject* FindNtSymbolicLinkObjectByRootHandle(HANDLE Handle); +EmuNtSymbolicLinkObject *FindNtSymbolicLinkObjectByDevice(const std::string_view Device); +DeviceType CxbxrGetDeviceTypeFromHandle(HANDLE hFile); void CleanupSymbolicLinks(); HANDLE CxbxGetDeviceNativeRootHandle(std::string XboxFullPath); @@ -314,16 +352,25 @@ typedef struct XboxPartitionTableEntry TableEntries[14]; } XboxPartitionTable; +inline constexpr xbox::ulong_xt fatx_name_length = 32; +inline constexpr xbox::ulong_xt fatx_online_data_length = 2048; +inline constexpr xbox::ulong_xt fatx_reserved_length = 1968; + +inline constexpr xbox::ulong_xt fatx_signature = 'XTAF'; + typedef struct _FATX_SUPERBLOCK { - char Tag[4]; - unsigned int VolumeID; - unsigned int ClusterSize; - USHORT FatCopies; - int Resvd; - char Unused[4078]; + xbox::ulong_xt Signature; + xbox::ulong_xt VolumeID; + xbox::ulong_xt ClusterSize; + xbox::ulong_xt FatCopies; + xbox::wchar_xt Name[fatx_name_length]; + xbox::uchar_xt OnlineData[fatx_online_data_length]; + xbox::uchar_xt Unused[fatx_reserved_length]; } FATX_SUPERBLOCK; +static_assert(sizeof(FATX_SUPERBLOCK) == PAGE_SIZE); + XboxPartitionTable CxbxGetPartitionTable(); FATX_SUPERBLOCK CxbxGetFatXSuperBlock(int partitionNumber); int CxbxGetPartitionNumberFromHandle(HANDLE hFile); diff --git a/src/gui/controllers/DlgDukeControllerConfig.cpp b/src/gui/controllers/DlgDukeControllerConfig.cpp index ccbfe3ed5..fefaba7a6 100644 --- a/src/gui/controllers/DlgDukeControllerConfig.cpp +++ b/src/gui/controllers/DlgDukeControllerConfig.cpp @@ -88,6 +88,14 @@ void DukeInputWindow::Initialize(HWND hwnd, int port_num, int dev_type) if (m_dev_type == to_underlying(XBOX_INPUT_DEVICE::ARCADE_STICK)) { // The arcade joystick does not have slot ports so we always disable the corresponding options + LRESULT index_top = SendMessage(m_hwnd_slot_list[SLOT_TOP], CB_ADDSTRING, 0, + reinterpret_cast(GetInputDeviceName(to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)).c_str())); + LRESULT index_bottom = SendMessage(m_hwnd_slot_list[SLOT_BOTTOM], CB_ADDSTRING, 0, + reinterpret_cast(GetInputDeviceName(to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)).c_str())); + SendMessage(m_hwnd_slot_list[SLOT_TOP], CB_SETITEMDATA, index_top, to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)); + SendMessage(m_hwnd_slot_list[SLOT_BOTTOM], CB_SETITEMDATA, index_bottom, to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)); + SendMessage(m_hwnd_slot_list[SLOT_TOP], CB_SETCURSEL, index_top, 0); + SendMessage(m_hwnd_slot_list[SLOT_BOTTOM], CB_SETCURSEL, index_bottom, 0); EnableWindow(m_hwnd_slot_list[SLOT_TOP], FALSE); EnableWindow(m_hwnd_slot_list[SLOT_BOTTOM], FALSE); } @@ -248,24 +256,6 @@ void DukeInputWindow::DetectOutput(int ms) } } -int DukeInputWindow::IsProfileSaved() -{ - if (int ret = InputWindow::IsProfileSaved()) { - if (ret == EXIT_IGNORE) { - return EXIT_IGNORE; - } - else { - if (m_dev_type != to_underlying(XBOX_INPUT_DEVICE::ARCADE_STICK)) { - SaveSlotConfig(); - } - - return EXIT_SAVE; - } - } - - return EXIT_ABORT; -} - void DukeInputWindow::SaveSlotConfig() { int DeviceType = SendMessage(m_hwnd_slot_list[SLOT_TOP], CB_GETITEMDATA, SendMessage(m_hwnd_slot_list[SLOT_TOP], CB_GETCURSEL, 0, 0), 0); From efd9108279707d5f19f3928e440018b352e3dd90 Mon Sep 17 00:00:00 2001 From: ergo720 <45463469+ergo720@users.noreply.github.com> Date: Wed, 23 Jun 2021 00:03:11 +0200 Subject: [PATCH 8/9] Properly log device creation/destruction + untangle profile saving from slot connectivity --- src/common/Settings.cpp | 41 +++++++------- src/common/Settings.hpp | 3 +- src/common/input/InputManager.cpp | 4 -- src/common/input/InputWindow.cpp | 3 - src/common/input/InputWindow.h | 5 +- src/core/hle/XAPI/Xapi.cpp | 4 ++ src/gui/DlgInputConfig.cpp | 8 +-- .../controllers/DlgDukeControllerConfig.cpp | 56 +++++++------------ src/gui/controllers/DlgSBControllerConfig.cpp | 8 +++ 9 files changed, 59 insertions(+), 73 deletions(-) diff --git a/src/common/Settings.cpp b/src/common/Settings.cpp index cd3082f88..2fc41acef 100644 --- a/src/common/Settings.cpp +++ b/src/common/Settings.cpp @@ -467,25 +467,24 @@ bool Settings::LoadConfig() // ==== Input Port Begin ==== for (int port_num = 0; port_num < 4; port_num++) { - m_input_port[port_num].Type = to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID); - m_input_port[port_num].TopSlotType = to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID); - m_input_port[port_num].BottomSlotType = to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID); + for (int slot = 0; slot < XBOX_CTRL_NUM_SLOTS; ++slot) { + m_input_port[port_num].Type = to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID); + m_input_port[port_num].SlotType[slot] = to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID); - std::string current_section = std::string(section_input_port) + std::to_string(port_num); - int ret = m_si.GetLongValue(current_section.c_str(), sect_input_port.type, -2); - if (ret == -2) { - continue; + std::string current_section = std::string(section_input_port) + std::to_string(port_num); + int ret = m_si.GetLongValue(current_section.c_str(), sect_input_port.type, -2); + if (ret == -2) { + continue; + } + m_input_port[port_num].Type = ret; + m_input_port[port_num].DeviceName = m_si.GetValue(current_section.c_str(), sect_input_port.device); + m_input_port[port_num].ProfileName = TrimQuoteFromString(m_si.GetValue(current_section.c_str(), sect_input_port.config)); + ret = m_si.GetLongValue(current_section.c_str(), slot == 0 ? sect_input_port.top_slot : sect_input_port.bottom_slot, -2); + if (ret == -2) { + continue; + } + m_input_port[port_num].SlotType[slot] = ret; } - m_input_port[port_num].Type = ret; - m_input_port[port_num].DeviceName = m_si.GetValue(current_section.c_str(), sect_input_port.device); - m_input_port[port_num].ProfileName = TrimQuoteFromString(m_si.GetValue(current_section.c_str(), sect_input_port.config)); - ret = m_si.GetLongValue(current_section.c_str(), sect_input_port.top_slot, -2); - if (ret == -2) { - continue; - } - m_input_port[port_num].TopSlotType = ret; - m_input_port[port_num].BottomSlotType = m_si.GetLongValue(current_section.c_str(), sect_input_port.bottom_slot, -2); - assert(m_input_port[port_num].BottomSlotType != -2); } // ==== Input Port End ============== @@ -656,8 +655,8 @@ bool Settings::Save(std::string file_path) m_si.SetLongValue(current_section.c_str(), sect_input_port.type, m_input_port[port_num].Type, nullptr, false, true); m_si.SetValue(current_section.c_str(), sect_input_port.device, m_input_port[port_num].DeviceName.c_str(), nullptr, true); m_si.SetValue(current_section.c_str(), sect_input_port.config, quoted_prf_str.c_str(), nullptr, true); - m_si.SetLongValue(current_section.c_str(), sect_input_port.top_slot, m_input_port[port_num].TopSlotType, nullptr, false, true); - m_si.SetLongValue(current_section.c_str(), sect_input_port.bottom_slot, m_input_port[port_num].BottomSlotType, nullptr, false, true); + m_si.SetLongValue(current_section.c_str(), sect_input_port.top_slot, m_input_port[port_num].SlotType[SLOT_TOP], nullptr, false, true); + m_si.SetLongValue(current_section.c_str(), sect_input_port.bottom_slot, m_input_port[port_num].SlotType[SLOT_BOTTOM], nullptr, false, true); } // ==== Input Port End ============== @@ -783,8 +782,8 @@ void Settings::SyncToEmulator() // register xbox device input settings for (int i = 0; i < 4; i++) { g_EmuShared->SetInputDevTypeSettings(&m_input_port[i].Type, i); - g_EmuShared->SetInputSlotTypeSettings(&m_input_port[i].TopSlotType, i, SLOT_TOP); - g_EmuShared->SetInputSlotTypeSettings(&m_input_port[i].BottomSlotType, i, SLOT_BOTTOM); + g_EmuShared->SetInputSlotTypeSettings(&m_input_port[i].SlotType[SLOT_TOP], i, SLOT_TOP); + g_EmuShared->SetInputSlotTypeSettings(&m_input_port[i].SlotType[SLOT_BOTTOM], i, SLOT_BOTTOM); if (m_input_port[i].Type != to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)) { g_EmuShared->SetInputDevNameSettings(m_input_port[i].DeviceName.c_str(), i); auto it = std::find_if(m_input_profiles[m_input_port[i].Type].begin(), diff --git a/src/common/Settings.hpp b/src/common/Settings.hpp index 0d3da1b73..e11f4c829 100644 --- a/src/common/Settings.hpp +++ b/src/common/Settings.hpp @@ -147,10 +147,9 @@ public: struct s_input_port { int Type; + int SlotType[2]; std::string DeviceName; std::string ProfileName; - int TopSlotType; - int BottomSlotType; }; std::array m_input_port; diff --git a/src/common/input/InputManager.cpp b/src/common/input/InputManager.cpp index 6bde93123..9c42093bb 100644 --- a/src/common/input/InputManager.cpp +++ b/src/common/input/InputManager.cpp @@ -297,16 +297,12 @@ void InputDeviceManager::ConnectDevice(DeviceState *dev, DeviceState *upstream, { ConstructHleInputDevice(dev, upstream, type, port); BindHostDevice(type, port); - EmuLog(LOG_LEVEL::INFO, "Attached device %s to port %d", GetInputDeviceName(type).c_str(), - PortUserFormat(port).c_str()); } void InputDeviceManager::DisconnectDevice(DeviceState *dev, std::string_view port, bool ack) { if (ack) { - int type = to_underlying(dev->type); DestructHleInputDevice(dev); - EmuLog(LOG_LEVEL::INFO, "Detached device %s from port %d", GetInputDeviceName(type).c_str(), PortUserFormat(port).c_str()); } else { dev->bPendingRemoval = true; diff --git a/src/common/input/InputWindow.cpp b/src/common/input/InputWindow.cpp index 12d617037..2caec9292 100644 --- a/src/common/input/InputWindow.cpp +++ b/src/common/input/InputWindow.cpp @@ -260,9 +260,6 @@ bool InputWindow::SaveProfile(const std::string& name) g_Settings->m_input_port[m_port_num].DeviceName = profile.DeviceName; g_Settings->m_input_port[m_port_num].ProfileName = profile.ProfileName; g_Settings->m_input_profiles[m_dev_type].push_back(std::move(profile)); - if (auto duke_wnd = dynamic_cast(this)) { - duke_wnd->SaveSlotConfig(); - } m_bHasChanges = false; return true; diff --git a/src/common/input/InputWindow.h b/src/common/input/InputWindow.h index b0fcbdbff..0534dd349 100644 --- a/src/common/input/InputWindow.h +++ b/src/common/input/InputWindow.h @@ -40,7 +40,6 @@ #define RUMBLE_CLEAR 7 #define BUTTON_CLEAR 8 #define BUTTON_SWAP 9 -#define SLOTS_CHANGED 10 #define XINPUT_DEFAULT 0 #define DINPUT_DEFAULT 1 @@ -75,6 +74,7 @@ protected: void OverwriteProfile(const std::string& name); void LoadDefaultProfile(); virtual int EnableDefaultButton() = 0; + virtual void SaveSlotConfig() = 0; // xbox device under configuration EmuDevice* m_DeviceConfig; @@ -107,7 +107,7 @@ public: void BindDefault(); void ClearBindings() override; void UpdateProfile(const std::string &name, int command) override; - void SaveSlotConfig(); + void SaveSlotConfig() override; private: @@ -131,6 +131,7 @@ class SbcInputWindow : public InputWindow public: void Initialize(HWND hwnd, int port_num, int dev_type) override; void ClearBindings() override; + void SaveSlotConfig() override; private: diff --git a/src/core/hle/XAPI/Xapi.cpp b/src/core/hle/XAPI/Xapi.cpp index 7949b86b1..952cddb39 100644 --- a/src/core/hle/XAPI/Xapi.cpp +++ b/src/core/hle/XAPI/Xapi.cpp @@ -277,6 +277,8 @@ void ConstructHleInputDevice(DeviceState *dev, DeviceState *upstream, int type, UpdateXppState(dev, static_cast(type), port); g_bIsDevicesEmulating = false; + + EmuLogEx(CXBXR_MODULE::INPSYS, LOG_LEVEL::INFO, "Attached device %s to port %s", GetInputDeviceName(type).c_str(), PortUserFormat(port).c_str()); } void DestructHleInputDevice(DeviceState *dev) @@ -343,6 +345,8 @@ void DestructHleInputDevice(DeviceState *dev) dev->upstream = nullptr; g_bIsDevicesEmulating = false; + + EmuLogEx(CXBXR_MODULE::INPSYS, LOG_LEVEL::INFO, "Detached device %s from port %s", GetInputDeviceName(to_underlying(type)).c_str(), PortUserFormat(port).c_str()); } void SetupXboxDeviceTypes() diff --git a/src/gui/DlgInputConfig.cpp b/src/gui/DlgInputConfig.cpp index 3530a9c96..69b0fa319 100644 --- a/src/gui/DlgInputConfig.cpp +++ b/src/gui/DlgInputConfig.cpp @@ -51,8 +51,8 @@ void SyncInputSettings(int port_num, int dev_type, bool is_opt) if (!is_opt) { // Sync updated input to kernel process to use run-time settings. g_EmuShared->SetInputDevTypeSettings(&g_Settings->m_input_port[port_num].Type, port_num); - g_EmuShared->SetInputSlotTypeSettings(&g_Settings->m_input_port[port_num].TopSlotType, port_num, SLOT_TOP); - g_EmuShared->SetInputSlotTypeSettings(&g_Settings->m_input_port[port_num].BottomSlotType, port_num, SLOT_BOTTOM); + g_EmuShared->SetInputSlotTypeSettings(&g_Settings->m_input_port[port_num].SlotType[SLOT_TOP], port_num, SLOT_TOP); + g_EmuShared->SetInputSlotTypeSettings(&g_Settings->m_input_port[port_num].SlotType[SLOT_BOTTOM], port_num, SLOT_BOTTOM); if (dev_type != to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)) { std::string dev_name = g_Settings->m_input_port[port_num].DeviceName; @@ -165,8 +165,8 @@ INT_PTR CALLBACK DlgInputConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPAR DeviceType != to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_S)) { // Forcefully set the child devices to none. This will happen if the user sets MUs in the controller dialog but // then they set the parent device to a device that cannot support them in the input dialog - g_Settings->m_input_port[port].TopSlotType = to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID); - g_Settings->m_input_port[port].BottomSlotType = to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID); + g_Settings->m_input_port[port].SlotType[SLOT_TOP] = to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID); + g_Settings->m_input_port[port].SlotType[SLOT_BOTTOM] = to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID); } SyncInputSettings(port, DeviceType, false); } diff --git a/src/gui/controllers/DlgDukeControllerConfig.cpp b/src/gui/controllers/DlgDukeControllerConfig.cpp index fefaba7a6..5f66839e2 100644 --- a/src/gui/controllers/DlgDukeControllerConfig.cpp +++ b/src/gui/controllers/DlgDukeControllerConfig.cpp @@ -88,31 +88,24 @@ void DukeInputWindow::Initialize(HWND hwnd, int port_num, int dev_type) if (m_dev_type == to_underlying(XBOX_INPUT_DEVICE::ARCADE_STICK)) { // The arcade joystick does not have slot ports so we always disable the corresponding options - LRESULT index_top = SendMessage(m_hwnd_slot_list[SLOT_TOP], CB_ADDSTRING, 0, - reinterpret_cast(GetInputDeviceName(to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)).c_str())); - LRESULT index_bottom = SendMessage(m_hwnd_slot_list[SLOT_BOTTOM], CB_ADDSTRING, 0, - reinterpret_cast(GetInputDeviceName(to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)).c_str())); - SendMessage(m_hwnd_slot_list[SLOT_TOP], CB_SETITEMDATA, index_top, to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)); - SendMessage(m_hwnd_slot_list[SLOT_BOTTOM], CB_SETITEMDATA, index_bottom, to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)); - SendMessage(m_hwnd_slot_list[SLOT_TOP], CB_SETCURSEL, index_top, 0); - SendMessage(m_hwnd_slot_list[SLOT_BOTTOM], CB_SETCURSEL, index_bottom, 0); - EnableWindow(m_hwnd_slot_list[SLOT_TOP], FALSE); - EnableWindow(m_hwnd_slot_list[SLOT_BOTTOM], FALSE); + for (unsigned slot = 0; slot < XBOX_CTRL_NUM_SLOTS; ++slot) { + LRESULT index = SendMessage(m_hwnd_slot_list[slot], CB_ADDSTRING, 0, + reinterpret_cast(GetInputDeviceName(to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)).c_str())); + SendMessage(m_hwnd_slot_list[slot], CB_SETITEMDATA, index, to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)); + SendMessage(m_hwnd_slot_list[slot], CB_SETCURSEL, index, 0); + EnableWindow(m_hwnd_slot_list[slot], FALSE); + } } else { // Set up the device types we support in the slot ports for (auto slot_type : slot_support_list) { - LRESULT index_top = SendMessage(m_hwnd_slot_list[SLOT_TOP], CB_ADDSTRING, 0, - reinterpret_cast(GetInputDeviceName(to_underlying(slot_type)).c_str())); - LRESULT index_bottom = SendMessage(m_hwnd_slot_list[SLOT_BOTTOM], CB_ADDSTRING, 0, - reinterpret_cast(GetInputDeviceName(to_underlying(slot_type)).c_str())); - SendMessage(m_hwnd_slot_list[SLOT_TOP], CB_SETITEMDATA, index_top, to_underlying(slot_type)); - SendMessage(m_hwnd_slot_list[SLOT_BOTTOM], CB_SETITEMDATA, index_bottom, to_underlying(slot_type)); - if (g_Settings->m_input_port[m_port_num].TopSlotType == to_underlying(slot_type)) { - SendMessage(m_hwnd_slot_list[SLOT_TOP], CB_SETCURSEL, index_top, 0); - } - if (g_Settings->m_input_port[m_port_num].BottomSlotType == to_underlying(slot_type)) { - SendMessage(m_hwnd_slot_list[SLOT_BOTTOM], CB_SETCURSEL, index_bottom, 0); + for (unsigned slot = 0; slot < XBOX_CTRL_NUM_SLOTS; ++slot) { + LRESULT index = SendMessage(m_hwnd_slot_list[slot], CB_ADDSTRING, 0, + reinterpret_cast(GetInputDeviceName(to_underlying(slot_type)).c_str())); + SendMessage(m_hwnd_slot_list[slot], CB_SETITEMDATA, index, to_underlying(slot_type)); + if (g_Settings->m_input_port[m_port_num].SlotType[slot] == to_underlying(slot_type)) { + SendMessage(m_hwnd_slot_list[slot], CB_SETCURSEL, index, 0); + } } } } @@ -218,10 +211,6 @@ void DukeInputWindow::UpdateProfile(const std::string &name, int command) m_rumble = std::string(); break; - case SLOTS_CHANGED: - m_bHasChanges = true; - break; - default: InputWindow::UpdateProfile(name, command); } @@ -258,10 +247,10 @@ void DukeInputWindow::DetectOutput(int ms) void DukeInputWindow::SaveSlotConfig() { - int DeviceType = SendMessage(m_hwnd_slot_list[SLOT_TOP], CB_GETITEMDATA, SendMessage(m_hwnd_slot_list[SLOT_TOP], CB_GETCURSEL, 0, 0), 0); - g_Settings->m_input_port[m_port_num].TopSlotType = DeviceType; - DeviceType = SendMessage(m_hwnd_slot_list[SLOT_BOTTOM], CB_GETITEMDATA, SendMessage(m_hwnd_slot_list[SLOT_BOTTOM], CB_GETCURSEL, 0, 0), 0); - g_Settings->m_input_port[m_port_num].BottomSlotType = DeviceType; + for (unsigned slot = 0; slot < XBOX_CTRL_NUM_SLOTS; ++slot) { + g_Settings->m_input_port[m_port_num].SlotType[slot] = SendMessage(m_hwnd_slot_list[slot], CB_GETITEMDATA, + SendMessage(m_hwnd_slot_list[slot], CB_GETCURSEL, 0, 0), 0); + } } static INT_PTR CALLBACK DlgRumbleConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); @@ -291,6 +280,7 @@ INT_PTR CALLBACK DlgXidControllerConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wPar case WM_CLOSE: { if (g_InputWindow->IsProfileSaved()) { + g_InputWindow->SaveSlotConfig(); delete g_InputWindow; g_InputWindow = nullptr; EndDialog(hWndDlg, wParam); @@ -309,14 +299,6 @@ INT_PTR CALLBACK DlgXidControllerConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wPar } break; - case IDC_DEVICE_LIST_TOP_SLOT: - case IDC_DEVICE_LIST_BOTTOM_SLOT: { - if (HIWORD(wParam) == CBN_SELCHANGE) { - g_InputWindow->UpdateProfile(std::string(), SLOTS_CHANGED); - } - } - break; - case IDC_PROFILE_NAME: { if (HIWORD(wParam) == CBN_SELCHANGE) { char name[50]; diff --git a/src/gui/controllers/DlgSBControllerConfig.cpp b/src/gui/controllers/DlgSBControllerConfig.cpp index 4627c879e..7a83dea9a 100644 --- a/src/gui/controllers/DlgSBControllerConfig.cpp +++ b/src/gui/controllers/DlgSBControllerConfig.cpp @@ -87,6 +87,13 @@ int SbcInputWindow::EnableDefaultButton() return -1; } +void SbcInputWindow::SaveSlotConfig() +{ + for (unsigned slot = 0; slot < XBOX_CTRL_NUM_SLOTS; ++slot) { + g_Settings->m_input_port[m_port_num].SlotType[slot] = to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID); + } +} + INT_PTR CALLBACK DlgSBControllerConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) @@ -110,6 +117,7 @@ INT_PTR CALLBACK DlgSBControllerConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wPara case WM_CLOSE: { if (g_InputWindow->IsProfileSaved()) { + g_InputWindow->SaveSlotConfig(); delete g_InputWindow; g_InputWindow = nullptr; EndDialog(hWndDlg, wParam); From e6650da541d5a6bd13aede86560a5d4a2cf78445 Mon Sep 17 00:00:00 2001 From: ergo720 <45463469+ergo720@users.noreply.github.com> Date: Wed, 23 Jun 2021 17:21:15 +0200 Subject: [PATCH 9/9] Review remarks + some code cleanup --- src/common/Settings.cpp | 1 - src/common/Settings.hpp | 4 +- src/common/input/Button.h | 2 - src/common/input/InputDevice.cpp | 19 ++--- src/common/input/InputDevice.h | 10 +-- src/common/input/InputManager.cpp | 98 ++++++++++++------------- src/common/input/InputManager.h | 25 +++++-- src/common/input/InputWindow.h | 2 +- src/common/input/RawDevice.cpp | 10 +-- src/common/input/RawDevice.h | 12 +-- src/common/input/SdlJoystick.cpp | 22 +++--- src/common/input/SdlJoystick.h | 14 ++-- src/common/input/XInputPad.cpp | 10 +-- src/common/input/XInputPad.h | 12 +-- src/common/win32/EmuShared.h | 8 +- src/core/hle/D3D8/Direct3D9/Direct3D9.h | 3 +- src/core/hle/XAPI/Xapi.cpp | 32 ++++---- src/core/hle/XAPI/Xapi.h | 2 + src/core/kernel/exports/EmuKrnlNt.cpp | 1 + src/core/kernel/init/CxbxKrnl.cpp | 6 +- src/core/kernel/support/EmuFile.cpp | 22 +----- src/core/kernel/support/EmuFile.h | 2 - 22 files changed, 146 insertions(+), 171 deletions(-) diff --git a/src/common/Settings.cpp b/src/common/Settings.cpp index 2fc41acef..6b082b6d6 100644 --- a/src/common/Settings.cpp +++ b/src/common/Settings.cpp @@ -33,7 +33,6 @@ #include "core\kernel\support\Emu.h" #include "EmuShared.h" #include -#include "common\input\InputManager.h" #include "common\input\layout_xbox_device.h" #include #include "common/util/cliConfig.hpp" diff --git a/src/common/Settings.hpp b/src/common/Settings.hpp index e11f4c829..d24a6f755 100644 --- a/src/common/Settings.hpp +++ b/src/common/Settings.hpp @@ -29,7 +29,7 @@ #include "Cxbx.h" #include "SimpleIni.h" -#include "input\InputDevice.h" +#include "common\input\InputManager.h" #include "common\util\CxbxUtil.h" #include #include @@ -147,7 +147,7 @@ public: struct s_input_port { int Type; - int SlotType[2]; + int SlotType[XBOX_CTRL_NUM_SLOTS]; std::string DeviceName; std::string ProfileName; }; diff --git a/src/common/input/Button.h b/src/common/input/Button.h index efd71b959..a74afded5 100644 --- a/src/common/input/Button.h +++ b/src/common/input/Button.h @@ -35,8 +35,6 @@ #define SBC_NUM_BUTTONS 56 #define HIGHEST_NUM_BUTTONS SBC_NUM_BUTTONS -#define XBOX_CTRL_NUM_SLOTS 2 - #define XBOX_BUTTON_NAME_LENGTH 30 #define HOST_BUTTON_NAME_LENGTH 30 diff --git a/src/common/input/InputDevice.cpp b/src/common/input/InputDevice.cpp index 2d2596483..aa63b6dc7 100644 --- a/src/common/input/InputDevice.cpp +++ b/src/common/input/InputDevice.cpp @@ -33,6 +33,7 @@ // https://github.com/dolphin-emu/dolphin #include "InputDevice.h" +#include "InputManager.h" #include "common\util\CxbxUtil.h" #include #include @@ -93,22 +94,22 @@ std::string GetInputDeviceName(int dev_type) std::string PortUserFormat(std::string_view port) { - int port1, slot; - PortStr2Int(port, &port1, &slot); - ++port1; + int port_num, slot; + PortStr2Int(port, &port_num, &slot); + ++port_num; if (slot != PORT_INVALID) { ++slot; - return std::to_string(port1) + "." + std::to_string(slot); + return std::to_string(port_num) + "." + std::to_string(slot); } else { - return std::to_string(port1); + return std::to_string(port_num); } } -void PortStr2Int(std::string_view port, int *port1, int *slot) +void PortStr2Int(std::string_view port, int *port_num, int *slot) { *slot = PORT_INVALID; - auto &ret = std::from_chars(port.data(), port.data() + port.size(), *port1); + auto &ret = std::from_chars(port.data(), port.data() + port.size(), *port_num); assert(ret.ec != std::errc::invalid_argument); if (ret.ptr != port.data() + port.size()) { ++ret.ptr; @@ -161,8 +162,8 @@ const std::vector InputDevice::GetIoControls() const auto InputDevice::FindPort(std::string_view Port) const { - return std::find_if(m_XboxPort.begin(), m_XboxPort.end(), [Port](std::string_view Port1) { - if (Port1 == Port) { + return std::find_if(m_XboxPort.begin(), m_XboxPort.end(), [Port](std::string_view CurrPort) { + if (CurrPort == Port) { return true; } return false; diff --git a/src/common/input/InputDevice.h b/src/common/input/InputDevice.h index a56ab1f9b..18323d8b8 100644 --- a/src/common/input/InputDevice.h +++ b/src/common/input/InputDevice.h @@ -36,12 +36,6 @@ #include #include "SDL.h" -#define PORT_INVALID -1 -#define PORT_1 0 -#define PORT_2 1 -#define PORT_3 2 -#define PORT_4 3 - #define DIRECTION_IN 0 #define DIRECTION_OUT 1 @@ -69,15 +63,13 @@ XBOX_INPUT_DEVICE; inline bool g_bIsTrackingMoLeave = false; inline bool g_bIsTrackingMoMove = false; -// Lookup array used to translate a gui port to an xbox usb port and vice versa -extern int Gui2XboxPortArray[4]; // Retrieves the printable name of a xid type std::string GetInputDeviceName(int dev_type); // Converts the port number in the user format std::string PortUserFormat(std::string_view); // Extracts port and slot number from a port formatted as a string -void PortStr2Int(std::string_view port, int *port1, int *slot); +void PortStr2Int(std::string_view port, int *port_num, int *slot); /* Abstract class which represents a host device usable for input/output */ class InputDevice diff --git a/src/common/input/InputManager.cpp b/src/common/input/InputManager.cpp index 9c42093bb..894d32356 100644 --- a/src/common/input/InputManager.cpp +++ b/src/common/input/InputManager.cpp @@ -52,12 +52,6 @@ // hle input specific #include "core\hle\XAPI\Xapi.h" -int Gui2XboxPortArray[4] = { - 3, - 4, - 1, - 2 -}; int dev_num_buttons[to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX)] = { XBOX_CTRL_NUM_BUTTONS, // MS_CONTROLLER_DUKE @@ -95,13 +89,13 @@ void InputDeviceManager::Initialize(bool is_gui, HWND hwnd) }); m_Cv.wait(lck, []() { - return (Sdl::SdlInitStatus != Sdl::SDL_NOT_INIT) && - (XInput::XInputInitStatus != XInput::XINPUT_NOT_INIT) && - (RawInput::RawInputInitStatus != RawInput::RAWINPUT_NOT_INIT); + return (Sdl::InitStatus != Sdl::NOT_INIT) && + (XInput::InitStatus != XInput::NOT_INIT) && + (RawInput::InitStatus != RawInput::NOT_INIT); }); lck.unlock(); - if (Sdl::SdlInitStatus < 0 || XInput::XInputInitStatus < 0 || RawInput::RawInputInitStatus < 0) { + if (Sdl::InitStatus < 0 || XInput::InitStatus < 0 || RawInput::InitStatus < 0) { CxbxKrnlCleanup("Failed to initialize input subsystem! Consult debug log for more information"); } @@ -109,12 +103,12 @@ void InputDeviceManager::Initialize(bool is_gui, HWND hwnd) RefreshDevices(); if (!is_gui) { - for (unsigned i = 0; i < 12; ++i) { + for (unsigned i = 0; i < MAX_DEVS; ++i) { g_devs[i].type = XBOX_INPUT_DEVICE::DEVICE_INVALID; g_devs[i].port = std::to_string(PORT_INVALID); } - for (unsigned i = 0; i < 4; ++i) { + for (unsigned i = 0; i < XBOX_NUM_PORTS; ++i) { int type; g_EmuShared->GetInputDevTypeSettings(&type, i); if (type != to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)) { @@ -225,31 +219,31 @@ void InputDeviceManager::RemoveDevice(std::function Ca void InputDeviceManager::UpdateDevices(std::string_view port, bool ack) { DeviceState *dev, *upstream; - int port1, slot, type; - PortStr2Int(port, &port1, &slot); - dev = &g_devs[port1]; + int port_num, slot, type; + PortStr2Int(port, &port_num, &slot); + dev = &g_devs[port_num]; if (slot == PORT_INVALID) { // Port references a device attached to an xbox port upstream = nullptr; - g_EmuShared->GetInputDevTypeSettings(&type, port1); + g_EmuShared->GetInputDevTypeSettings(&type, port_num); } else { // Port references a device attached to a slot port upstream = dev; dev = dev->slots[slot]; - g_EmuShared->GetInputSlotTypeSettings(&type, port1, slot); + g_EmuShared->GetInputSlotTypeSettings(&type, port_num, slot); } // updating a slot if (dev == nullptr) { // connect slot if (type != to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID) && - g_devs[MU_OFFSET + (XBOX_CTRL_NUM_SLOTS * port1) + slot].type == XBOX_INPUT_DEVICE::DEVICE_INVALID) { - ConnectDevice(&g_devs[MU_OFFSET + (XBOX_CTRL_NUM_SLOTS * port1) + slot], upstream, type, port); + g_devs[MU_OFFSET + (XBOX_CTRL_NUM_SLOTS * port_num) + slot].type == XBOX_INPUT_DEVICE::DEVICE_INVALID) { + ConnectDevice(&g_devs[MU_OFFSET + (XBOX_CTRL_NUM_SLOTS * port_num) + slot], upstream, type, port); } // disconnect slot else if (type == to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID) && - g_devs[MU_OFFSET + (XBOX_CTRL_NUM_SLOTS * port1) + slot].type != XBOX_INPUT_DEVICE::DEVICE_INVALID) { - DisconnectDevice(&g_devs[MU_OFFSET + (XBOX_CTRL_NUM_SLOTS * port1) + slot], port, ack); + g_devs[MU_OFFSET + (XBOX_CTRL_NUM_SLOTS * port_num) + slot].type != XBOX_INPUT_DEVICE::DEVICE_INVALID) { + DisconnectDevice(&g_devs[MU_OFFSET + (XBOX_CTRL_NUM_SLOTS * port_num) + slot], port, ack); } // update bindings slot else { @@ -270,9 +264,9 @@ void InputDeviceManager::UpdateDevices(std::string_view port, bool ack) } // update bindings else { - auto dev1 = g_InputDeviceManager.FindDevice(port); - if (dev1 != nullptr) { - dev1->SetPort(port, false); + auto host_dev = g_InputDeviceManager.FindDevice(port); + if (host_dev != nullptr) { + host_dev->SetPort(port, false); } if (type != to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)) { if (type != to_underlying(dev->type)) { @@ -307,9 +301,9 @@ void InputDeviceManager::DisconnectDevice(DeviceState *dev, std::string_view por else { dev->bPendingRemoval = true; } - auto dev1 = g_InputDeviceManager.FindDevice(port); - if (dev1 != nullptr) { - dev1->SetPort(port, false); + auto host_dev = g_InputDeviceManager.FindDevice(port); + if (host_dev != nullptr) { + host_dev->SetPort(port, false); } } @@ -322,15 +316,15 @@ void InputDeviceManager::BindHostDevice(int type, std::string_view port) char dev_name[50]; char dev_control_names[HIGHEST_NUM_BUTTONS][HOST_BUTTON_NAME_LENGTH]; - int port1, slot; - PortStr2Int(port, &port1, &slot); - g_EmuShared->GetInputDevNameSettings(dev_name, port1); - g_EmuShared->GetInputBindingsSettings(dev_control_names, dev_num_buttons[type], port1); + int port_num, slot; + PortStr2Int(port, &port_num, &slot); + g_EmuShared->GetInputDevNameSettings(dev_name, port_num); + g_EmuShared->GetInputBindingsSettings(dev_control_names, dev_num_buttons[type], port_num); auto dev = FindDevice(std::string(dev_name)); if (dev != nullptr) { - std::string port1(port); - dev->ClearBindings(port1); + std::string port_str(port); + dev->ClearBindings(port_str); std::vector controls = dev->GetIoControls(); for (int index = 0; index < dev_num_buttons[type]; index++) { std::string dev_button(dev_control_names[index]); @@ -340,7 +334,7 @@ void InputDeviceManager::BindHostDevice(int type, std::string_view port) } return false; }); - dev->SetBindings(index, (it != controls.end()) ? *it : nullptr, port1); + dev->SetBindings(index, (it != controls.end()) ? *it : nullptr, port_str); } dev->SetPort(port, true); } @@ -357,19 +351,19 @@ bool InputDeviceManager::UpdateXboxPortInput(int port, void* buffer, int directi // If somebody else is currently holding the lock, we won't wait and instead report no input changes if (!g_renderbase->IsImGuiFocus() && m_Mtx.try_lock()) { for (auto &dev : m_Devices) { - std::string port1 = std::to_string(port); - if (dev->GetPort(port1)) { + std::string port_str = std::to_string(port); + if (dev->GetPort(port_str)) { switch (type) { case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE): case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_S): case to_underlying(XBOX_INPUT_DEVICE::ARCADE_STICK): - has_changed = UpdateInputXpad(dev, buffer, direction, port1); + has_changed = UpdateInputXpad(dev, buffer, direction, port_str); m_Mtx.unlock(); return has_changed; case to_underlying(XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER): - has_changed = UpdateInputSBC(dev, buffer, direction, port, port1); + has_changed = UpdateInputSBC(dev, buffer, direction, port, port_str); m_Mtx.unlock(); return has_changed; @@ -381,7 +375,7 @@ bool InputDeviceManager::UpdateXboxPortInput(int port, void* buffer, int directi case to_underlying(XBOX_INPUT_DEVICE::STEERING_WHEEL): case to_underlying(XBOX_INPUT_DEVICE::IR_DONGLE): EmuLog(LOG_LEVEL::ERROR2, "An unsupported device is attached at port %d! The device was %s", - Gui2XboxPortArray[port], GetInputDeviceName(type).c_str()); + PortUserFormat(port_str).c_str(), GetInputDeviceName(type).c_str()); break; } @@ -393,9 +387,9 @@ bool InputDeviceManager::UpdateXboxPortInput(int port, void* buffer, int directi return has_changed; } -bool InputDeviceManager::UpdateInputXpad(std::shared_ptr& Device, void* Buffer, int Direction, const std::string &Port1) +bool InputDeviceManager::UpdateInputXpad(std::shared_ptr& Device, void* Buffer, int Direction, const std::string &Port) { - std::map bindings = Device->GetBindings(Port1); + std::map bindings = Device->GetBindings(Port); assert(bindings.size() == static_cast(dev_num_buttons[to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE)])); if (Direction == DIRECTION_IN) { @@ -457,9 +451,9 @@ bool InputDeviceManager::UpdateInputXpad(std::shared_ptr& Device, v return true; } -bool InputDeviceManager::UpdateInputSBC(std::shared_ptr& Device, void* Buffer, int Direction, int Port, const std::string &Port1) +bool InputDeviceManager::UpdateInputSBC(std::shared_ptr& Device, void* Buffer, int Direction, int Port_num, const std::string &Port) { - std::map bindings = Device->GetBindings(Port1); + std::map bindings = Device->GetBindings(Port); assert(bindings.size() == static_cast(dev_num_buttons[to_underlying(XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER)])); // NOTE: the output state is not supported @@ -480,7 +474,7 @@ bool InputDeviceManager::UpdateInputSBC(std::shared_ptr& Device, vo // 8 -> TunerDial Down // 9 -> GearLever Up // 10 -> GearLever Down - static uint16_t last_in_state[4] = { 0, 0, 0, 0 }; + static uint16_t last_in_state[XBOX_NUM_PORTS] = { 0, 0, 0, 0 }; SBCInput *in_buf = static_cast(Buffer); for (int i = 0; i < 4; i++) { ControlState state = (bindings[i] != nullptr) ? dynamic_cast(bindings[i])->GetState() : 0.0; @@ -496,10 +490,10 @@ bool InputDeviceManager::UpdateInputSBC(std::shared_ptr& Device, vo for (int i = 4, j = 0; i < 6; i++, j++) { ControlState state = (bindings[i] != nullptr) ? dynamic_cast(bindings[i])->GetState() : 0.0; uint16_t curr_in_state = static_cast(!!state); - if ((~curr_in_state) & ((last_in_state[Port] >> j) & 1)) { + if ((~curr_in_state) & ((last_in_state[Port_num] >> j) & 1)) { in_buf->wButtons[0] ^= (1 << i); } - (last_in_state[Port] &= ~(1 << j)) |= (curr_in_state << j); + (last_in_state[Port_num] &= ~(1 << j)) |= (curr_in_state << j); } for (int i = 6; i < 34; i++) { @@ -516,10 +510,10 @@ bool InputDeviceManager::UpdateInputSBC(std::shared_ptr& Device, vo for (int i = 34, j = 2; i < 39; i++, j++) { ControlState state = (bindings[i] != nullptr) ? dynamic_cast(bindings[i])->GetState() : 0.0; uint16_t curr_in_state = static_cast(!!state); - if ((~curr_in_state) & ((last_in_state[Port] >> j) & 1)) { + if ((~curr_in_state) & ((last_in_state[Port_num] >> j) & 1)) { in_buf->wButtons[2] ^= (1 << (i % 16)); } - (last_in_state[Port] &= ~(1 << j)) |= (curr_in_state << j); + (last_in_state[Port_num] &= ~(1 << j)) |= (curr_in_state << j); } for (int i = 39; i < 49; i += 2) { @@ -578,7 +572,7 @@ bool InputDeviceManager::UpdateInputSBC(std::shared_ptr& Device, vo for (int i = 52, j = 7; i < 56; i++, j++) { ControlState state = (bindings[i] != nullptr) ? dynamic_cast(bindings[i])->GetState() : 0.0; uint16_t curr_in_state = static_cast(!!state); - if ((~curr_in_state) & ((last_in_state[Port] >> j) & 1)) { + if ((~curr_in_state) & ((last_in_state[Port_num] >> j) & 1)) { switch (i) { case 52: @@ -606,7 +600,7 @@ bool InputDeviceManager::UpdateInputSBC(std::shared_ptr& Device, vo break; } } - (last_in_state[Port] &= ~(1 << j)) |= (curr_in_state << j); + (last_in_state[Port_num] &= ~(1 << j)) |= (curr_in_state << j); } } @@ -616,7 +610,7 @@ bool InputDeviceManager::UpdateInputSBC(std::shared_ptr& Device, vo void InputDeviceManager::RefreshDevices() { std::unique_lock lck(m_Mtx); - Sdl::SdlPopulateOK = false; + Sdl::PopulateOK = false; m_Devices.clear(); lck.unlock(); XInput::PopulateDevices(); @@ -624,7 +618,7 @@ void InputDeviceManager::RefreshDevices() Sdl::PopulateDevices(); lck.lock(); m_Cv.wait(lck, []() { - return Sdl::SdlPopulateOK; + return Sdl::PopulateOK; }); for (auto &dev : m_Devices) { if (StrStartsWith(dev->GetDeviceName(), "KeyboardMouse")) { diff --git a/src/common/input/InputManager.h b/src/common/input/InputManager.h index 56605a806..e47f2cfdf 100644 --- a/src/common/input/InputManager.h +++ b/src/common/input/InputManager.h @@ -37,11 +37,20 @@ #undef SetPort #endif -#define SLOT_TOP 0 -#define SLOT_BOTTOM 1 +#define PORT_INVALID -1 +#define PORT_1 0 +#define PORT_2 1 +#define PORT_3 2 +#define PORT_4 3 +#define XBOX_NUM_PORTS 4 + +#define SLOT_TOP 0 +#define SLOT_BOTTOM 1 +#define XBOX_CTRL_NUM_SLOTS 2 #define CTRL_OFFSET 0 #define MU_OFFSET 4 +#define MAX_DEVS (XBOX_NUM_PORTS + XBOX_CTRL_NUM_SLOTS * XBOX_NUM_PORTS) extern int dev_num_buttons[to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX)]; @@ -56,6 +65,8 @@ inline XBOX_INPUT_DEVICE input_support_list[] = { inline XBOX_INPUT_DEVICE slot_support_list[] = { XBOX_INPUT_DEVICE::DEVICE_INVALID, XBOX_INPUT_DEVICE::MEMORY_UNIT, + // Microphone + // Phantasy star online keyboard }; #pragma pack(1) @@ -109,7 +120,7 @@ union InputBuff { }; struct DeviceInfo { - xbox::HANDLE hhandle; // device handle returned by xapi + xbox::HANDLE hHandle; // device handle returned by xapi bool bAutoPoll; // autopoll on/off, as instructed by the title in XInputOpen bool bAutoPollDefault; // default autopoll value, depending on device type uint8_t ucType; // xapi type @@ -121,7 +132,6 @@ struct DeviceInfo { }; struct DeviceState { - DeviceState *upstream; std::string port; int port_idx; XBOX_INPUT_DEVICE type; @@ -129,9 +139,10 @@ struct DeviceState { bool bSignaled; DeviceInfo info; DeviceState *slots[XBOX_CTRL_NUM_SLOTS]; + DeviceState *upstream; }; -extern DeviceState g_devs[4 + 8]; +extern DeviceState g_devs[MAX_DEVS]; class InputDeviceManager @@ -165,9 +176,9 @@ public: private: // update input for an xbox controller - bool UpdateInputXpad(std::shared_ptr& Device, void* Buffer, int Direction, const std::string &Port1); + bool UpdateInputXpad(std::shared_ptr& Device, void* Buffer, int Direction, const std::string &Port); // update input for a Steel Battalion controller - bool UpdateInputSBC(std::shared_ptr& Device, void* Buffer, int Direction, int Port, const std::string &Port1); + bool UpdateInputSBC(std::shared_ptr& Device, void* Buffer, int Direction, int Port_num, const std::string &Port); // bind a host device to an emulated device void BindHostDevice(int type, std::string_view port); // connect a device to the emulated machine diff --git a/src/common/input/InputWindow.h b/src/common/input/InputWindow.h index 0534dd349..4df21cae4 100644 --- a/src/common/input/InputWindow.h +++ b/src/common/input/InputWindow.h @@ -121,7 +121,7 @@ private: // handle of the rumble combobox HWND m_hwnd_rumble_list; // handles of the slot combobox - HWND m_hwnd_slot_list[2]; + HWND m_hwnd_slot_list[XBOX_CTRL_NUM_SLOTS]; // currently selected rumble control std::string m_rumble; }; diff --git a/src/common/input/RawDevice.cpp b/src/common/input/RawDevice.cpp index a4c6c4343..fdceecc7b 100644 --- a/src/common/input/RawDevice.cpp +++ b/src/common/input/RawDevice.cpp @@ -35,7 +35,7 @@ namespace RawInput { - int RawInputInitStatus = RAWINPUT_NOT_INIT; + int InitStatus = NOT_INIT; bool IgnoreHotplug = true; void Init(std::mutex &Mtx, bool is_gui, HWND hwnd) @@ -44,7 +44,7 @@ namespace RawInput if (is_gui) { // We don't need to monitor xinput device changes from the gui, because there we have the refresh button to detect changes - RawInputInitStatus = RAWINPUT_INIT_SUCCESS; + InitStatus = INIT_SUCCESS; return; } @@ -69,16 +69,16 @@ namespace RawInput static_cast(sizeof(decltype(devices)::value_type)))) { EmuLog(LOG_LEVEL::ERROR2, "RegisterRawInputDevices failed: %i", GetLastError()); - RawInputInitStatus = RAWINPUT_INIT_ERROR; + InitStatus = INIT_ERROR; return; } - RawInputInitStatus = RAWINPUT_INIT_SUCCESS; + InitStatus = INIT_SUCCESS; } void DeInit() { - RawInputInitStatus = RAWINPUT_NOT_INIT; + InitStatus = NOT_INIT; IgnoreHotplug = true; } } diff --git a/src/common/input/RawDevice.h b/src/common/input/RawDevice.h index 7be2bc3f5..6d81a44a9 100644 --- a/src/common/input/RawDevice.h +++ b/src/common/input/RawDevice.h @@ -33,15 +33,15 @@ namespace RawInput { - typedef enum _RAWINPUT_INIT_STATUS : int + typedef enum _INIT_STATUS : int { - RAWINPUT_NOT_INIT = -2, - RAWINPUT_INIT_ERROR, - RAWINPUT_INIT_SUCCESS, + NOT_INIT = -2, + INIT_ERROR, + INIT_SUCCESS, } - RAWINPUT_INIT_STATUS; + INIT_STATUS; - extern int RawInputInitStatus; + extern int InitStatus; extern bool IgnoreHotplug; // initialize RawInput diff --git a/src/common/input/SdlJoystick.cpp b/src/common/input/SdlJoystick.cpp index e571ee3a7..6a50d662b 100644 --- a/src/common/input/SdlJoystick.cpp +++ b/src/common/input/SdlJoystick.cpp @@ -54,8 +54,8 @@ namespace Sdl uint32_t PopulateEvent_t; uint32_t UpdateInputEvent_t; uint32_t DeviceRemoveAck_t; - int SdlInitStatus = SDL_NOT_INIT; - bool SdlPopulateOK = false; + int InitStatus = NOT_INIT; + bool PopulateOK = false; void Init(std::mutex& Mtx, std::condition_variable& Cv, bool is_gui) { @@ -65,7 +65,7 @@ namespace Sdl if (SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC) < 0) { EmuLog(LOG_LEVEL::ERROR2, "Failed to initialize SDL subsystem! The error was: %s", SDL_GetError()); - SdlInitStatus = SDL_INIT_ERROR; + InitStatus = INIT_ERROR; lck.unlock(); Cv.notify_one(); return; @@ -74,7 +74,7 @@ namespace Sdl if (CustomEvent_t == (uint32_t)-1) { SDL_Quit(); EmuLog(LOG_LEVEL::ERROR2, "Failed to create SDL custom events!"); - SdlInitStatus = SDL_INIT_ERROR; + InitStatus = INIT_ERROR; lck.unlock(); Cv.notify_one(); return; @@ -96,7 +96,7 @@ namespace Sdl break; } } - SdlInitStatus = SDL_INIT_SUCCESS; + InitStatus = INIT_SUCCESS; lck.unlock(); Cv.notify_one(); @@ -133,10 +133,6 @@ namespace Sdl case SDL_JOYBUTTONUP: id = Event.jbutton.which; break; - - default: { - // unreachable - } } auto dev = g_InputDeviceManager.FindDevice(id); if (dev != nullptr) { @@ -147,7 +143,7 @@ namespace Sdl for (int i = 0; i < SDL_NumJoysticks(); i++) { OpenSdlDevice(i); } - SdlPopulateOK = true; + PopulateOK = true; Cv.notify_one(); } else if (Event.type == ExitEvent_t) { @@ -161,8 +157,8 @@ namespace Sdl XInput::GetDeviceChanges(); DInput::GetDeviceChanges(); std::string port = std::to_string(*static_cast(Event.user.data1)); - int port1, slot; - PortStr2Int(port, &port1, &slot); + int port_num, slot; + PortStr2Int(port, &port_num, &slot); g_InputDeviceManager.UpdateDevices(port, false); // Force an update of the entire slot connectivity of this port @@ -185,7 +181,7 @@ namespace Sdl void DeInit(std::thread& Thr) { - SdlInitStatus = SDL_NOT_INIT; + InitStatus = NOT_INIT; if (!Thr.joinable()) { return; } diff --git a/src/common/input/SdlJoystick.h b/src/common/input/SdlJoystick.h index b6d18008e..688d84a07 100644 --- a/src/common/input/SdlJoystick.h +++ b/src/common/input/SdlJoystick.h @@ -35,20 +35,20 @@ namespace Sdl { - typedef enum _SDL_INIT_STATUS : int + typedef enum _INIT_STATUS : int { - SDL_NOT_INIT = -2, - SDL_INIT_ERROR, - SDL_INIT_SUCCESS, + NOT_INIT = -2, + INIT_ERROR, + INIT_SUCCESS, } - SDL_INIT_STATUS; + INIT_STATUS; extern uint32_t ExitEvent_t; extern uint32_t PopulateEvent_t; extern uint32_t UpdateInputEvent_t; extern uint32_t DeviceRemoveAck_t; - extern int SdlInitStatus; - extern bool SdlPopulateOK; + extern int InitStatus; + extern bool PopulateOK; // initialize SDL void Init(std::mutex& Mtx, std::condition_variable& Cv, bool is_gui); diff --git a/src/common/input/XInputPad.cpp b/src/common/input/XInputPad.cpp index 1ac1a9597..53016d672 100644 --- a/src/common/input/XInputPad.cpp +++ b/src/common/input/XInputPad.cpp @@ -70,7 +70,7 @@ namespace XInput static XInputGetState_t PXInputGetState = nullptr; static bool haveGuideButton = false; - int XInputInitStatus = XINPUT_NOT_INIT; + int InitStatus = NOT_INIT; uint8_t DevicesConnected = 0; static const struct @@ -118,7 +118,7 @@ namespace XInput hXInput = ::LoadLibrary(TEXT(xinput_dll_name.c_str())); if (!hXInput) { EmuLog(LOG_LEVEL::ERROR2, "Failed to initialize XInput subsystem!"); - XInputInitStatus = XINPUT_INIT_ERROR; + InitStatus = INIT_ERROR; return; } } @@ -147,15 +147,15 @@ namespace XInput ::FreeLibrary(hXInput); hXInput = nullptr; EmuLog(LOG_LEVEL::ERROR2, "Failed to find XInput functions!"); - XInputInitStatus = XINPUT_INIT_ERROR; + InitStatus = INIT_ERROR; return; } - XInputInitStatus = XINPUT_INIT_SUCCESS; + InitStatus = INIT_SUCCESS; } void DeInit() { - XInputInitStatus = XINPUT_NOT_INIT; + InitStatus = NOT_INIT; if (hXInput) { ::FreeLibrary(hXInput); diff --git a/src/common/input/XInputPad.h b/src/common/input/XInputPad.h index f6faae243..c64822805 100644 --- a/src/common/input/XInputPad.h +++ b/src/common/input/XInputPad.h @@ -34,15 +34,15 @@ namespace XInput { - typedef enum _XINPUT_INIT_STATUS : int + typedef enum _INIT_STATUS : int { - XINPUT_NOT_INIT = -2, - XINPUT_INIT_ERROR, - XINPUT_INIT_SUCCESS, + NOT_INIT = -2, + INIT_ERROR, + INIT_SUCCESS, } - XINPUT_INIT_STATUS; + INIT_STATUS; - extern int XInputInitStatus; + extern int InitStatus; extern uint8_t DevicesConnected; // initialize XInput diff --git a/src/common/win32/EmuShared.h b/src/common/win32/EmuShared.h index aff5a810e..1f685437c 100644 --- a/src/common/win32/EmuShared.h +++ b/src/common/win32/EmuShared.h @@ -367,10 +367,10 @@ class EmuShared : public Mutex bool m_bFirstLaunch; bool m_bClipCursor; unsigned int m_dwKrnlProcID; // Only used for kernel mode level. - int m_DeviceType[4]; - int m_SlotDeviceType[4][XBOX_CTRL_NUM_SLOTS]; - char m_DeviceControlNames[4][HIGHEST_NUM_BUTTONS][HOST_BUTTON_NAME_LENGTH]; - char m_DeviceName[4][50]; + int m_DeviceType[XBOX_NUM_PORTS]; + int m_SlotDeviceType[XBOX_NUM_PORTS][XBOX_CTRL_NUM_SLOTS]; + char m_DeviceControlNames[XBOX_NUM_PORTS][HIGHEST_NUM_BUTTONS][HOST_BUTTON_NAME_LENGTH]; + char m_DeviceName[XBOX_NUM_PORTS][50]; char m_TitleMountPath[xbox::max_path]; // Settings class in memory should not be tampered by third-party. diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.h b/src/core/hle/D3D8/Direct3D9/Direct3D9.h index 9d5a68fe5..f3ae9c596 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.h +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.h @@ -37,8 +37,7 @@ #define DIRECTDRAW_VERSION 0x0700 #include -extern void LookupTrampolinesD3D(); -extern void LookupTrampolinesXAPI(); +void LookupTrampolinesD3D(); // initialize render window extern void CxbxInitWindow(bool bFullInit); diff --git a/src/core/hle/XAPI/Xapi.cpp b/src/core/hle/XAPI/Xapi.cpp index 952cddb39..0cdef1d9a 100644 --- a/src/core/hle/XAPI/Xapi.cpp +++ b/src/core/hle/XAPI/Xapi.cpp @@ -59,7 +59,7 @@ std::atomic g_bXppGuard = false; // Allocate enough memory for the max number of devices we can support simultaneously // 4 duke / S / sbc / arcade joystick (mutually exclusive) + 8 memory units -DeviceState g_devs[4 + 8]; +DeviceState g_devs[MAX_DEVS]; xbox::ulong_xt g_Mounted_MUs = 0; xbox::char_xt g_AltLett_MU = 0; @@ -173,9 +173,9 @@ void UpdateXppState(DeviceState *dev, XBOX_INPUT_DEVICE type, std::string_view p return; } - int port1, slot; - PortStr2Int(port, &port1, &slot); - xbox::ulong_xt port_mask = 1 << port1; + int port_num, slot; + PortStr2Int(port, &port_num, &slot); + xbox::ulong_xt port_mask = 1 << port_num; xbox::ulong_xt slot_mask = 0; // Guard against the unfortunate case where XGetDevices or XGetDeviceChanges have already checked for g_bIsDevicesInitializing @@ -209,11 +209,11 @@ void ConstructHleInputDevice(DeviceState *dev, DeviceState *upstream, int type, return; } // Set up common device state - int port1, slot; - PortStr2Int(port, &port1, &slot); + int port_num, slot; + PortStr2Int(port, &port_num, &slot); dev->upstream = nullptr; dev->port = port; - dev->port_idx = port1; + dev->port_idx = port_num; dev->bPendingRemoval = false; dev->bSignaled = false; dev->info.dwPacketNumber = 0; @@ -330,8 +330,8 @@ void DestructHleInputDevice(DeviceState *dev) case XBOX_INPUT_DEVICE::MEMORY_UNIT: { assert(dev->upstream != nullptr); - int port1, slot; - PortStr2Int(port, &port1, &slot); + int port_num, slot; + PortStr2Int(port, &port_num, &slot); assert(slot != PORT_INVALID); dev->upstream->slots[slot] = nullptr; } @@ -446,7 +446,7 @@ xbox::dword_xt CxbxImpl_XInputHandler(xbox::HANDLE hDevice, xbox::PXINPUT_STATE DeviceState *dev = static_cast(hDevice); int port = dev->port_idx; - if ((g_devs[port].info.hhandle == hDevice) && !g_devs[port].bPendingRemoval) { + if ((g_devs[port].info.hHandle == hDevice) && !g_devs[port].bPendingRemoval) { if (g_devs[port].info.bAutoPoll != IsXInputPoll) { if (g_InputDeviceManager.UpdateXboxPortInput(port, &g_devs[port].info.buff, DIRECTION_IN, to_underlying(g_devs[port].type))) { g_devs[port].info.dwPacketNumber++; @@ -639,8 +639,8 @@ xbox::HANDLE WINAPI xbox::EMUPATCH(XInputOpen) if (DeviceType == g_devs[dwPort].type) { g_devs[dwPort].info.bAutoPoll = pPollingParameters != xbox::zeroptr ? pPollingParameters->fAutoPoll : g_devs[dwPort].info.bAutoPollDefault; - g_devs[dwPort].info.hhandle = &g_devs[dwPort]; - RETURN(g_devs[dwPort].info.hhandle); + g_devs[dwPort].info.hHandle = &g_devs[dwPort]; + RETURN(g_devs[dwPort].info.hHandle); } } @@ -658,8 +658,8 @@ xbox::void_xt WINAPI xbox::EMUPATCH(XInputClose) LOG_FUNC_ONE_ARG(hDevice); DeviceState *dev = static_cast(hDevice); - if (g_devs[dev->port_idx].info.hhandle == hDevice) { - dev->info.hhandle = NULL; + if (g_devs[dev->port_idx].info.hHandle == hDevice) { + dev->info.hHandle = NULL; } } @@ -696,7 +696,7 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(XInputGetCapabilities) dword_xt ret = ERROR_DEVICE_NOT_CONNECTED; DeviceState *dev = static_cast(hDevice); int port = dev->port_idx; - if (g_devs[port].info.hhandle == hDevice && !g_devs[port].bPendingRemoval) { + if (g_devs[port].info.hHandle == hDevice && !g_devs[port].bPendingRemoval) { pCapabilities->SubType = g_devs[port].info.ucSubType; UCHAR* pCap = (UCHAR*)(&pCapabilities->In); std::memset(pCap, 0xFF, g_devs[port].info.ucInputStateSize + g_devs[port].info.ucFeedbackSize); @@ -745,7 +745,7 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(XInputSetState) DeviceState *dev = static_cast(hDevice); int port = dev->port_idx; - if (g_devs[port].info.hhandle == hDevice && !g_devs[port].bPendingRemoval) { + if (g_devs[port].info.hHandle == hDevice && !g_devs[port].bPendingRemoval) { pFeedback->Header.dwStatus = ERROR_IO_PENDING; g_InputDeviceManager.UpdateXboxPortInput(port, (void*)&pFeedback->Rumble, DIRECTION_OUT, to_underlying(g_devs[port].type)); pFeedback->Header.dwStatus = ERROR_SUCCESS; diff --git a/src/core/hle/XAPI/Xapi.h b/src/core/hle/XAPI/Xapi.h index b70125f64..1b5d2949f 100644 --- a/src/core/hle/XAPI/Xapi.h +++ b/src/core/hle/XAPI/Xapi.h @@ -25,6 +25,8 @@ #ifndef XAPI_H #define XAPI_H +void LookupTrampolinesXAPI(); + #include "xbox_types.h" namespace xbox { diff --git a/src/core/kernel/exports/EmuKrnlNt.cpp b/src/core/kernel/exports/EmuKrnlNt.cpp index 7f672a7f1..a5c1a2db9 100644 --- a/src/core/kernel/exports/EmuKrnlNt.cpp +++ b/src/core/kernel/exports/EmuKrnlNt.cpp @@ -835,6 +835,7 @@ XBSYSAPI EXPORTNUM(200) xbox::ntstatus_xt NTAPI xbox::NtFsControlFile switch (FsControlCode) { case fsctl_dismount_volume: { + // HACK: this should just free the resources assocoated with the volume, it should not reformat it int partitionNumber = CxbxGetPartitionNumberFromHandle(FileHandle); if (partitionNumber > 0) { CxbxFormatPartitionByHandle(FileHandle); diff --git a/src/core/kernel/init/CxbxKrnl.cpp b/src/core/kernel/init/CxbxKrnl.cpp index edd786d6a..ef960cf52 100644 --- a/src/core/kernel/init/CxbxKrnl.cpp +++ b/src/core/kernel/init/CxbxKrnl.cpp @@ -1945,14 +1945,14 @@ void CxbxKrnlShutDown(bool is_reboot) // Shutdown the input device manager g_InputDeviceManager.Shutdown(); - // Shutdown the memory manager - g_VMManager.Shutdown(); - if (g_io_mu_metadata) { delete g_io_mu_metadata; g_io_mu_metadata = nullptr; } + // Shutdown the memory manager + g_VMManager.Shutdown(); + // Shutdown the render manager if (g_renderbase != nullptr) { g_renderbase->Shutdown(); diff --git a/src/core/kernel/support/EmuFile.cpp b/src/core/kernel/support/EmuFile.cpp index c96f2dae1..b7afe8429 100644 --- a/src/core/kernel/support/EmuFile.cpp +++ b/src/core/kernel/support/EmuFile.cpp @@ -171,8 +171,9 @@ DeviceType CxbxrGetDeviceTypeFromHandle(HANDLE hFile) return DeviceType::MU; } - EmuNtSymbolicLinkObject *ret = FindNtSymbolicLinkObjectByDevice(DeviceCdrom0); - if (ret != nullptr && path.rfind(ret->wHostSymbolicLinkPath) != std::string::npos) { + EmuDirPath hybrid_path; + FindEmuDirPathByDevice(DeviceCdrom0, hybrid_path); + if (hybrid_path.HostDirPath != "") { return DeviceType::Cdrom0; } @@ -929,10 +930,6 @@ NTSTATUS EmuNtSymbolicLinkObject::Init(std::string aSymbolicLinkName, std::strin } else { - std::mbstate_t ps = std::mbstate_t(); - const char *src = HostSymbolicLinkPath.c_str(); - wHostSymbolicLinkPath.resize(HostSymbolicLinkPath.size()); - std::mbsrtowcs(wHostSymbolicLinkPath.data(), &src, wHostSymbolicLinkPath.size(), &ps); NtSymbolicLinkObjects[DriveLetter - 'A'] = this; EmuLog(LOG_LEVEL::DEBUG, "Linked \"%s\" to \"%s\" (residing at \"%s\")", aSymbolicLinkName.c_str(), aFullPath.c_str(), HostSymbolicLinkPath.c_str()); } @@ -1018,19 +1015,6 @@ EmuNtSymbolicLinkObject* FindNtSymbolicLinkObjectByRootHandle(const HANDLE Handl } -EmuNtSymbolicLinkObject *FindNtSymbolicLinkObjectByDevice(const std::string_view Device) -{ - for (char DriveLetter = 'A'; DriveLetter <= 'Z'; DriveLetter++) - { - EmuNtSymbolicLinkObject *result = NtSymbolicLinkObjects[DriveLetter - 'A']; - if ((result != nullptr) && (result->XboxSymbolicLinkPath == Device)) - return result; - } - - return nullptr; -} - - void _CxbxPVOIDDeleter(PVOID *ptr) { if (*ptr) { diff --git a/src/core/kernel/support/EmuFile.h b/src/core/kernel/support/EmuFile.h index fe0dabc52..eedc2e2b2 100644 --- a/src/core/kernel/support/EmuFile.h +++ b/src/core/kernel/support/EmuFile.h @@ -231,7 +231,6 @@ public: bool IsHostBasedPath; std::string XboxSymbolicLinkPath; std::string HostSymbolicLinkPath; - std::wstring wHostSymbolicLinkPath; HANDLE RootDirectoryHandle; NTSTATUS Init(std::string aSymbolicLinkName, std::string aFullPath); ~EmuNtSymbolicLinkObject(); @@ -284,7 +283,6 @@ EmuNtSymbolicLinkObject* FindNtSymbolicLinkObjectByDriveLetter(const char DriveL EmuNtSymbolicLinkObject* FindNtSymbolicLinkObjectByName(std::string SymbolicLinkName); void FindEmuDirPathByDevice(std::string DeviceName, EmuDirPath& hybrid_path); EmuNtSymbolicLinkObject* FindNtSymbolicLinkObjectByRootHandle(HANDLE Handle); -EmuNtSymbolicLinkObject *FindNtSymbolicLinkObjectByDevice(const std::string_view Device); DeviceType CxbxrGetDeviceTypeFromHandle(HANDLE hFile); void CleanupSymbolicLinks();