diff --git a/Source/Core/Core/Movie.cpp b/Source/Core/Core/Movie.cpp index 368ad04eb9..35bbae2762 100644 --- a/Source/Core/Core/Movie.cpp +++ b/Source/Core/Core/Movie.cpp @@ -85,11 +85,14 @@ static u8 s_language = 10; //Set to unknown until language is known static bool s_bRecordingFromSaveState = false; static bool s_bPolled = false; +// s_InputDisplay is used by both CPU and GPU (is mutable). +static std::mutex s_input_display_lock; static std::string s_InputDisplay[8]; static GCManipFunction gcmfunc = nullptr; static WiiManipFunction wiimfunc = nullptr; +// NOTE: Host / CPU Thread static void EnsureTmpInputSize(size_t bound) { if (tmpInputAllocated >= bound) @@ -119,6 +122,7 @@ static bool IsMovieHeader(u8 magic[4]) magic[3] == 0x1A; } +// NOTE: GPU Thread std::string GetInputDisplay() { if (!IsMovieActive()) @@ -133,14 +137,19 @@ std::string GetInputDisplay() } } - std::string inputDisplay = ""; - for (int i = 0; i < 8; ++i) - if ((s_numPads & (1 << i)) != 0) - inputDisplay.append(s_InputDisplay[i]); - - return inputDisplay; + std::string input_display; + { + std::lock_guard guard(s_input_display_lock); + for (int i = 0; i < 8; ++i) + { + if ((s_numPads & (1 << i)) != 0) + input_display += s_InputDisplay[i]; + } + } + return input_display; } +// NOTE: GPU Thread void FrameUpdate() { // TODO[comex]: This runs on the GPU thread, yet it messes with the CPU @@ -168,6 +177,7 @@ void FrameUpdate() // called when game is booting up, even if no movie is active, // but potentially after BeginRecordingInput or PlayInput has been called. +// NOTE: EmuThread void Init() { s_bPolled = false; @@ -213,6 +223,7 @@ void Init() } } +// NOTE: CPU Thread void InputUpdate() { g_currentInputCount++; @@ -224,6 +235,7 @@ void InputUpdate() } } +// NOTE: Host Thread void SetFrameSkipping(unsigned int framesToSkip) { std::lock_guard lk(cs_frameSkip); @@ -237,11 +249,13 @@ void SetFrameSkipping(unsigned int framesToSkip) Fifo::SetRendering(true); } +// NOTE: CPU Thread void SetPolledDevice() { s_bPolled = true; } +// NOTE: Host Thread void DoFrameStep() { if (Core::GetState() == Core::CORE_PAUSE) @@ -258,6 +272,7 @@ void DoFrameStep() } } +// NOTE: Host Thread void SetReadOnly(bool bEnabled) { if (s_bReadOnly != bEnabled) @@ -266,6 +281,7 @@ void SetReadOnly(bool bEnabled) s_bReadOnly = bEnabled; } +// NOTE: GPU Thread void FrameSkipping() { // Frameskipping will desync movie playback @@ -399,6 +415,7 @@ bool IsNetPlayRecording() return s_bNetPlay; } +// NOTE: Host / CPU Thread void ChangePads(bool instantly) { if (!Core::IsRunning()) @@ -431,6 +448,7 @@ void ChangePads(bool instantly) } } +// NOTE: Host / Emu Threads void ChangeWiiPads(bool instantly) { int controllers = 0; @@ -450,6 +468,7 @@ void ChangeWiiPads(bool instantly) } } +// NOTE: Host Thread bool BeginRecordingInput(int controllers) { if (s_playMode != MODE_NONE || controllers == 0) @@ -575,46 +594,51 @@ static std::string Analog1DToString(u8 v, const std::string& prefix, u8 range = } } +// NOTE: CPU Thread static void SetInputDisplayString(ControllerState padState, int controllerID) { - s_InputDisplay[controllerID] = StringFromFormat("P%d:", controllerID + 1); + std::string display_str = StringFromFormat("P%d:", controllerID + 1); if (padState.A) - s_InputDisplay[controllerID].append(" A"); + display_str += " A"; if (padState.B) - s_InputDisplay[controllerID].append(" B"); + display_str += " B"; if (padState.X) - s_InputDisplay[controllerID].append(" X"); + display_str += " X"; if (padState.Y) - s_InputDisplay[controllerID].append(" Y"); + display_str += " Y"; if (padState.Z) - s_InputDisplay[controllerID].append(" Z"); + display_str += " Z"; if (padState.Start) - s_InputDisplay[controllerID].append(" START"); + display_str += " START"; if (padState.DPadUp) - s_InputDisplay[controllerID].append(" UP"); + display_str += " UP"; if (padState.DPadDown) - s_InputDisplay[controllerID].append(" DOWN"); + display_str += " DOWN"; if (padState.DPadLeft) - s_InputDisplay[controllerID].append(" LEFT"); + display_str += " LEFT"; if (padState.DPadRight) - s_InputDisplay[controllerID].append(" RIGHT"); + display_str += " RIGHT"; if (padState.reset) - s_InputDisplay[controllerID].append(" RESET"); + display_str += " RESET"; - s_InputDisplay[controllerID].append(Analog1DToString(padState.TriggerL, " L")); - s_InputDisplay[controllerID].append(Analog1DToString(padState.TriggerR, " R")); - s_InputDisplay[controllerID].append(Analog2DToString(padState.AnalogStickX, padState.AnalogStickY, " ANA")); - s_InputDisplay[controllerID].append(Analog2DToString(padState.CStickX, padState.CStickY, " C")); - s_InputDisplay[controllerID].append("\n"); + display_str += Analog1DToString(padState.TriggerL, " L"); + display_str += Analog1DToString(padState.TriggerR, " R"); + display_str += Analog2DToString(padState.AnalogStickX, padState.AnalogStickY, " ANA"); + display_str += Analog2DToString(padState.CStickX, padState.CStickY, " C"); + display_str += '\n'; + + std::lock_guard guard(s_input_display_lock); + s_InputDisplay[controllerID] = std::move(display_str); } +// NOTE: CPU Thread static void SetWiiInputDisplayString(int remoteID, u8* const data, const WiimoteEmu::ReportFeatures& rptf, int ext, const wiimote_key key) { int controllerID = remoteID + 4; - s_InputDisplay[controllerID] = StringFromFormat("R%d:", remoteID + 1); + std::string display_str = StringFromFormat("R%d:", remoteID + 1); u8* const coreData = rptf.core ? (data + rptf.core) : nullptr; u8* const accelData = rptf.accel ? (data + rptf.accel) : nullptr; @@ -625,43 +649,43 @@ static void SetWiiInputDisplayString(int remoteID, u8* const data, const Wiimote { wm_buttons buttons = *(wm_buttons*)coreData; if(buttons.left) - s_InputDisplay[controllerID].append(" LEFT"); + display_str += " LEFT"; if(buttons.right) - s_InputDisplay[controllerID].append(" RIGHT"); + display_str += " RIGHT"; if(buttons.down) - s_InputDisplay[controllerID].append(" DOWN"); + display_str += " DOWN"; if(buttons.up) - s_InputDisplay[controllerID].append(" UP"); + display_str += " UP"; if(buttons.a) - s_InputDisplay[controllerID].append(" A"); + display_str += " A"; if(buttons.b) - s_InputDisplay[controllerID].append(" B"); + display_str += " B"; if(buttons.plus) - s_InputDisplay[controllerID].append(" +"); + display_str += " +"; if(buttons.minus) - s_InputDisplay[controllerID].append(" -"); + display_str += " -"; if(buttons.one) - s_InputDisplay[controllerID].append(" 1"); + display_str += " 1"; if(buttons.two) - s_InputDisplay[controllerID].append(" 2"); + display_str += " 2"; if(buttons.home) - s_InputDisplay[controllerID].append(" HOME"); + display_str += " HOME"; } if (accelData) { wm_accel* dt = (wm_accel*)accelData; - std::string accel = StringFromFormat(" ACC:%d,%d,%d", - dt->x << 2 | ((wm_buttons*)coreData)->acc_x_lsb, dt->y << 2 | ((wm_buttons*)coreData)->acc_y_lsb << 1, dt->z << 2 | ((wm_buttons*)coreData)->acc_z_lsb << 1); - s_InputDisplay[controllerID].append(accel); + display_str += StringFromFormat(" ACC:%d,%d,%d", + dt->x << 2 | ((wm_buttons*)coreData)->acc_x_lsb, + dt->y << 2 | ((wm_buttons*)coreData)->acc_y_lsb << 1, + dt->z << 2 | ((wm_buttons*)coreData)->acc_z_lsb << 1); } if (irData) { u16 x = irData[0] | ((irData[2] >> 4 & 0x3) << 8); u16 y = irData[1] | ((irData[2] >> 6 & 0x3) << 8); - std::string ir = StringFromFormat(" IR:%d,%d", x,y); - s_InputDisplay[controllerID].append(ir); + display_str += StringFromFormat(" IR:%d,%d", x, y); } // Nunchuk @@ -676,11 +700,11 @@ static void SetWiiInputDisplayString(int remoteID, u8* const data, const Wiimote (nunchuk.ax << 2) | nunchuk.bt.acc_x_lsb, (nunchuk.ay << 2) | nunchuk.bt.acc_y_lsb, (nunchuk.az << 2) | nunchuk.bt.acc_z_lsb); if (nunchuk.bt.c) - s_InputDisplay[controllerID].append(" C"); + display_str += " C"; if (nunchuk.bt.z) - s_InputDisplay[controllerID].append(" Z"); - s_InputDisplay[controllerID].append(accel); - s_InputDisplay[controllerID].append(Analog2DToString(nunchuk.jx, nunchuk.jy, " ANA")); + display_str += " Z"; + display_str += accel; + display_str += Analog2DToString(nunchuk.jx, nunchuk.jy, " ANA"); } // Classic controller @@ -692,41 +716,45 @@ static void SetWiiInputDisplayString(int remoteID, u8* const data, const Wiimote cc.bt.hex = cc.bt.hex ^ 0xFFFF; if (cc.bt.regular_data.dpad_left) - s_InputDisplay[controllerID].append(" LEFT"); + display_str += " LEFT"; if (cc.bt.dpad_right) - s_InputDisplay[controllerID].append(" RIGHT"); + display_str += " RIGHT"; if (cc.bt.dpad_down) - s_InputDisplay[controllerID].append(" DOWN"); + display_str += " DOWN"; if (cc.bt.regular_data.dpad_up) - s_InputDisplay[controllerID].append(" UP"); + display_str += " UP"; if (cc.bt.a) - s_InputDisplay[controllerID].append(" A"); + display_str += " A"; if (cc.bt.b) - s_InputDisplay[controllerID].append(" B"); + display_str += " B"; if (cc.bt.x) - s_InputDisplay[controllerID].append(" X"); + display_str += " X"; if (cc.bt.y) - s_InputDisplay[controllerID].append(" Y"); + display_str += " Y"; if (cc.bt.zl) - s_InputDisplay[controllerID].append(" ZL"); + display_str += " ZL"; if (cc.bt.zr) - s_InputDisplay[controllerID].append(" ZR"); + display_str += " ZR"; if (cc.bt.plus) - s_InputDisplay[controllerID].append(" +"); + display_str += " +"; if (cc.bt.minus) - s_InputDisplay[controllerID].append(" -"); + display_str += " -"; if (cc.bt.home) - s_InputDisplay[controllerID].append(" HOME"); + display_str += " HOME"; - s_InputDisplay[controllerID].append(Analog1DToString(cc.lt1 | (cc.lt2 << 3), " L", 31)); - s_InputDisplay[controllerID].append(Analog1DToString(cc.rt, " R", 31)); - s_InputDisplay[controllerID].append(Analog2DToString(cc.regular_data.lx, cc.regular_data.ly, " ANA", 63)); - s_InputDisplay[controllerID].append(Analog2DToString(cc.rx1 | (cc.rx2 << 1) | (cc.rx3 << 3), cc.ry, " R-ANA", 31)); + display_str += Analog1DToString(cc.lt1 | (cc.lt2 << 3), " L", 31); + display_str += Analog1DToString(cc.rt, " R", 31); + display_str += Analog2DToString(cc.regular_data.lx, cc.regular_data.ly, " ANA", 63); + display_str += Analog2DToString(cc.rx1 | (cc.rx2 << 1) | (cc.rx3 << 3), cc.ry, " R-ANA", 31); } - s_InputDisplay[controllerID].append("\n"); + display_str += '\n'; + + std::lock_guard guard(s_input_display_lock); + s_InputDisplay[controllerID] = std::move(display_str); } +// NOTE: CPU Thread void CheckPadStatus(GCPadStatus* PadStatus, int controllerID) { s_padState.A = ((PadStatus->button & PAD_BUTTON_A) != 0); @@ -760,6 +788,7 @@ void CheckPadStatus(GCPadStatus* PadStatus, int controllerID) SetInputDisplayString(s_padState, controllerID); } +// NOTE: CPU Thread void RecordInput(GCPadStatus* PadStatus, int controllerID) { if (!IsRecordingInput() || !IsUsingPad(controllerID)) @@ -773,6 +802,7 @@ void RecordInput(GCPadStatus* PadStatus, int controllerID) s_totalBytes = s_currentByte; } +// NOTE: CPU Thread void CheckWiimoteStatus(int wiimote, u8 *data, const WiimoteEmu::ReportFeatures& rptf, int ext, const wiimote_key key) { SetWiiInputDisplayString(wiimote, data, rptf, ext, key); @@ -794,6 +824,7 @@ void RecordWiimote(int wiimote, u8 *data, u8 size) s_totalBytes = s_currentByte; } +// NOTE: CPU / EmuThread / Host Thread void ReadHeader() { s_numPads = tmpHeader.numControllers; @@ -832,6 +863,7 @@ void ReadHeader() s_DSPcoefHash = tmpHeader.DSPcoefHash; } +// NOTE: Host Thread bool PlayInput(const std::string& filename) { if (s_playMode != MODE_NONE) @@ -902,6 +934,7 @@ void DoState(PointerWrap &p) // other variables (such as s_totalBytes and g_totalFrames) are set in LoadInput } +// NOTE: Host / CPU Thread void LoadInput(const std::string& filename) { File::IOFile t_record; @@ -1039,6 +1072,7 @@ void LoadInput(const std::string& filename) } } +// NOTE: CPU Thread static void CheckInputEnd() { if (g_currentFrame > g_totalFrames || s_currentByte >= s_totalBytes || (CoreTiming::GetTicks() > s_totalTickCount && !IsRecordingInputFromSaveState())) @@ -1047,6 +1081,7 @@ static void CheckInputEnd() } } +// NOTE: CPU Thread void PlayController(GCPadStatus* PadStatus, int controllerID) { // Correct playback is entirely dependent on the emulator polling the controllers @@ -1147,6 +1182,7 @@ void PlayController(GCPadStatus* PadStatus, int controllerID) CheckInputEnd(); } +// NOTE: CPU Thread bool PlayWiimote(int wiimote, u8 *data, const WiimoteEmu::ReportFeatures& rptf, int ext, const wiimote_key key) { if (!IsPlayingInput() || !IsUsingWiimote(wiimote) || tmpInput == nullptr) @@ -1189,6 +1225,7 @@ bool PlayWiimote(int wiimote, u8 *data, const WiimoteEmu::ReportFeatures& rptf, return true; } +// NOTE: Host / EmuThread / CPU Thread void EndPlayInput(bool cont) { if (cont) @@ -1214,6 +1251,7 @@ void EndPlayInput(bool cont) } } +// NOTE: Save State + Host Thread void SaveRecording(const std::string& filename) { File::IOFile save_record(filename, "wb"); @@ -1292,17 +1330,20 @@ void SetWiiInputManip(WiiManipFunction func) wiimfunc = func; } +// NOTE: CPU Thread void CallGCInputManip(GCPadStatus* PadStatus, int controllerID) { if (gcmfunc) (*gcmfunc)(PadStatus, controllerID); } +// NOTE: CPU Thread void CallWiiInputManip(u8* data, WiimoteEmu::ReportFeatures rptf, int controllerID, int ext, const wiimote_key key) { if (wiimfunc) (*wiimfunc)(data, rptf, controllerID, ext, key); } +// NOTE: GPU Thread void SetGraphicsConfig() { g_Config.bEFBAccessEnable = tmpHeader.bEFBAccessEnable; @@ -1312,6 +1353,7 @@ void SetGraphicsConfig() g_Config.bUseRealXFB = tmpHeader.bUseRealXFB; } +// NOTE: CPU / EmuThread / Host Thread void GetSettings() { s_bSaveConfig = true; @@ -1372,6 +1414,7 @@ void GetSettings() static const mbedtls_md_info_t* s_md5_info = mbedtls_md_info_from_type(MBEDTLS_MD_MD5); +// NOTE: Entrypoint for own thread void CheckMD5() { for (int i = 0, n = 0; i < 16; ++i) @@ -1393,6 +1436,7 @@ void CheckMD5() Core::DisplayMessage("Checksum of current game does not match the recorded game!", 3000); } +// NOTE: Entrypoint for own thread void GetMD5() { Core::DisplayMessage("Calculating checksum of game file...", 2000); @@ -1401,6 +1445,7 @@ void GetMD5() Core::DisplayMessage("Finished calculating checksum.", 2000); } +// NOTE: EmuThread void Shutdown() { g_currentInputCount = g_totalInputCount = g_totalFrames = s_totalBytes = s_tickCountAtLastInput = 0; diff --git a/Source/Core/DolphinWX/TASInputDlg.cpp b/Source/Core/DolphinWX/TASInputDlg.cpp index 814be18d29..9c3d8c1f33 100644 --- a/Source/Core/DolphinWX/TASInputDlg.cpp +++ b/Source/Core/DolphinWX/TASInputDlg.cpp @@ -29,6 +29,7 @@ wxDEFINE_EVENT(INVALIDATE_BUTTON_EVENT, wxCommandEvent); wxDEFINE_EVENT(INVALIDATE_CONTROL_EVENT, wxCommandEvent); +wxDEFINE_EVENT(INVALIDATE_EXTENSION_EVENT, wxThreadEvent); struct TASWiimoteReport { @@ -63,11 +64,17 @@ void TASInputDlg::CreateBaseLayout() m_controls[1] = &m_main_stick.y_cont; m_a = CreateButton("A"); + m_a.checkbox->SetClientData(&m_a); m_b = CreateButton("B"); + m_b.checkbox->SetClientData(&m_b); m_dpad_up = CreateButton("Up"); + m_dpad_up.checkbox->SetClientData(&m_dpad_up); m_dpad_right = CreateButton("Right"); + m_dpad_right.checkbox->SetClientData(&m_dpad_right); m_dpad_down = CreateButton("Down"); + m_dpad_down.checkbox->SetClientData(&m_dpad_down); m_dpad_left = CreateButton("Left"); + m_dpad_left.checkbox->SetClientData(&m_dpad_left); m_buttons_dpad = new wxGridSizer(3); m_buttons_dpad->AddSpacer(20); @@ -134,10 +141,15 @@ void TASInputDlg::CreateWiiLayout(int num) wxGridSizer* const m_buttons_grid = new wxGridSizer(4); m_plus = CreateButton("+"); + m_plus.checkbox->SetClientData(&m_plus); m_minus = CreateButton("-"); + m_minus.checkbox->SetClientData(&m_minus); m_one = CreateButton("1"); + m_one.checkbox->SetClientData(&m_one); m_two = CreateButton("2"); + m_two.checkbox->SetClientData(&m_two); m_home = CreateButton("Home"); + m_home.checkbox->SetClientData(&m_home); m_main_szr = new wxBoxSizer(wxVERTICAL); m_wiimote_szr = new wxBoxSizer(wxHORIZONTAL); @@ -178,7 +190,9 @@ void TASInputDlg::CreateWiiLayout(int num) wxStaticBoxSizer* const nunchukaxisBox = CreateAccelLayout(&m_nx_cont, &m_ny_cont, &m_nz_cont, _("Nunchuk orientation")); m_c = CreateButton("C"); + m_c.checkbox->SetClientData(&m_c); m_z = CreateButton("Z"); + m_z.checkbox->SetClientData(&m_z); m_ext_szr->Add(m_c_stick_szr, 0, wxLEFT | wxBOTTOM | wxRIGHT, 5); m_ext_szr->Add(nunchukaxisBox); @@ -212,6 +226,7 @@ void TASInputDlg::FinishLayout() Bind(wxEVT_CLOSE_WINDOW, &TASInputDlg::OnCloseWindow, this); Bind(INVALIDATE_BUTTON_EVENT, &TASInputDlg::UpdateFromInvalidatedButton, this); Bind(INVALIDATE_CONTROL_EVENT, &TASInputDlg::UpdateFromInvalidatedControl, this); + Bind(INVALIDATE_EXTENSION_EVENT, &TASInputDlg::UpdateFromInvalidatedExtension, this); m_has_layout = true; } @@ -220,7 +235,10 @@ wxBoxSizer* TASInputDlg::CreateCCLayout() wxBoxSizer* const szr = new wxBoxSizer(wxHORIZONTAL); for (size_t i = 0; i < ArraySize(m_cc_buttons); ++i) + { m_cc_buttons[i] = CreateButton(m_cc_button_names[i]); + m_cc_buttons[i].checkbox->SetClientData(&m_cc_buttons[i]); + } m_cc_l_stick = CreateStick(ID_CC_L_STICK, 63, 63, WiimoteEmu::Classic::LEFT_STICK_CENTER_X, WiimoteEmu::Classic::LEFT_STICK_CENTER_Y, false, true); m_cc_r_stick = CreateStick(ID_CC_R_STICK, 31, 31, WiimoteEmu::Classic::RIGHT_STICK_CENTER_X, WiimoteEmu::Classic::RIGHT_STICK_CENTER_Y, false, true); @@ -348,11 +366,17 @@ void TASInputDlg::CreateGCLayout() wxGridSizer* const m_buttons_grid = new wxGridSizer(4); m_x = CreateButton("X"); + m_x.checkbox->SetClientData(&m_x); m_y = CreateButton("Y"); + m_y.checkbox->SetClientData(&m_y); m_l = CreateButton("L"); + m_l.checkbox->SetClientData(&m_l); m_r = CreateButton("R"); + m_r.checkbox->SetClientData(&m_r); m_z = CreateButton("Z"); + m_z.checkbox->SetClientData(&m_z); m_start = CreateButton("Start"); + m_start.checkbox->SetClientData(&m_start); for (unsigned int i = 4; i < ArraySize(m_buttons); ++i) if (m_buttons[i] != nullptr) @@ -449,11 +473,18 @@ TASInputDlg::Button TASInputDlg::CreateButton(const std::string& name) wxCheckBox* checkbox = new wxCheckBox(this, m_eleID++, name); checkbox->Bind(wxEVT_RIGHT_DOWN, &TASInputDlg::SetTurbo, this); checkbox->Bind(wxEVT_LEFT_DOWN, &TASInputDlg::SetTurbo, this); + checkbox->Bind(wxEVT_CHECKBOX, &TASInputDlg::OnCheckboxToggle, this); temp.checkbox = checkbox; temp.id = m_eleID - 1; return temp; } +void TASInputDlg::OnCheckboxToggle(wxCommandEvent& event) +{ + auto cbox = static_cast(event.GetEventObject()); + static_cast(cbox->GetClientData())->is_checked = event.IsChecked(); +} + void TASInputDlg::ResetValues() { for (Button* const button : m_buttons) @@ -491,6 +522,7 @@ void TASInputDlg::ResetValues() } } +// NOTE: Host / CPU Thread void TASInputDlg::SetStickValue(Control* control, int CurrentValue, int center) { if (CurrentValue != center) @@ -511,6 +543,7 @@ void TASInputDlg::SetStickValue(Control* control, int CurrentValue, int center) InvalidateControl(control); } +// NOTE: Host / CPU Thread void TASInputDlg::SetSliderValue(Control* control, int CurrentValue) { if (CurrentValue != (int)control->default_value) @@ -531,6 +564,7 @@ void TASInputDlg::SetSliderValue(Control* control, int CurrentValue) InvalidateControl(control); } +// NOTE: Host / CPU Thread void TASInputDlg::SetButtonValue(Button* button, bool CurrentState) { if (CurrentState) @@ -550,16 +584,18 @@ void TASInputDlg::SetButtonValue(Button* button, bool CurrentState) InvalidateButton(button); } +// NOTE: Host / CPU Thread void TASInputDlg::SetWiiButtons(u16* butt) { for (unsigned int i = 0; i < 11; ++i) { if (m_buttons[i] != nullptr) - *butt |= (m_buttons[i]->checkbox->IsChecked()) ? m_wii_buttons_bitmask[i] : 0; + *butt |= (m_buttons[i]->is_checked) ? m_wii_buttons_bitmask[i] : 0; } ButtonTurbo(); } +// NOTE: Host / CPU Thread void TASInputDlg::GetKeyBoardInput(GCPadStatus* PadStatus) { SetStickValue(&m_main_stick.x_cont, PadStatus->stickX); @@ -579,6 +615,7 @@ void TASInputDlg::GetKeyBoardInput(GCPadStatus* PadStatus) SetButtonValue(&m_r, ((PadStatus->triggerRight) == 255) || ((PadStatus->button & PAD_TRIGGER_R) != 0)); } +// NOTE: Host / CPU Thread void TASInputDlg::GetKeyBoardInput(u8* data, WiimoteEmu::ReportFeatures rptf, int ext, const wiimote_key key) { u8* const coreData = rptf.core ? (data + rptf.core) : nullptr; @@ -651,6 +688,9 @@ void TASInputDlg::GetKeyBoardInput(u8* data, WiimoteEmu::ReportFeatures rptf, in } } +// NOTE: Host / CPU Thread +// Do not touch the GUI. Requires wxMutexGuiEnter which will deadlock against +// the GUI when pausing/stopping. void TASInputDlg::GetValues(u8* data, WiimoteEmu::ReportFeatures rptf, int ext, const wiimote_key key) { if (!IsShown() || !m_has_layout) @@ -743,7 +783,7 @@ void TASInputDlg::GetValues(u8* data, WiimoteEmu::ReportFeatures rptf, int ext, if (ext != m_ext) { m_ext = ext; - HandleExtensionChange(); + InvalidateExtension(); } else if (extData && ext == 1) { @@ -759,8 +799,8 @@ void TASInputDlg::GetValues(u8* data, WiimoteEmu::ReportFeatures rptf, int ext, nunchuk.az = m_nz_cont.value >> 2; nunchuk.bt.acc_z_lsb = m_nz_cont.value & 0x3; - nunchuk.bt.hex |= (m_buttons[11]->checkbox->IsChecked()) ? WiimoteEmu::Nunchuk::BUTTON_C : 0; - nunchuk.bt.hex |= (m_buttons[12]->checkbox->IsChecked()) ? WiimoteEmu::Nunchuk::BUTTON_Z : 0; + nunchuk.bt.hex |= (m_buttons[11]->is_checked) ? WiimoteEmu::Nunchuk::BUTTON_C : 0; + nunchuk.bt.hex |= (m_buttons[12]->is_checked) ? WiimoteEmu::Nunchuk::BUTTON_Z : 0; nunchuk.bt.hex = nunchuk.bt.hex ^ 0x3; WiimoteEncrypt(&key, (u8*)&nunchuk, 0, sizeof(wm_nc)); } @@ -772,7 +812,7 @@ void TASInputDlg::GetValues(u8* data, WiimoteEmu::ReportFeatures rptf, int ext, for (unsigned int i = 0; i < ArraySize(m_cc_buttons); ++i) { - cc.bt.hex |= (m_cc_buttons[i].checkbox->IsChecked()) ? m_cc_buttons_bitmask[i] : 0; + cc.bt.hex |= (m_cc_buttons[i].is_checked) ? m_cc_buttons_bitmask[i] : 0; } cc.bt.hex ^= 0xFFFF; @@ -793,6 +833,7 @@ void TASInputDlg::GetValues(u8* data, WiimoteEmu::ReportFeatures rptf, int ext, } } +// NOTE: Host / CPU Thread void TASInputDlg::GetValues(GCPadStatus* PadStatus) { if (!IsShown() || !m_has_layout) @@ -805,26 +846,26 @@ void TASInputDlg::GetValues(GCPadStatus* PadStatus) PadStatus->stickY = m_main_stick.y_cont.value; PadStatus->substickX = m_c_stick.x_cont.value; PadStatus->substickY = m_c_stick.y_cont.value; - PadStatus->triggerLeft = m_l.checkbox->GetValue() ? 255 : m_l_cont.value; - PadStatus->triggerRight = m_r.checkbox->GetValue() ? 255 : m_r_cont.value; + PadStatus->triggerLeft = m_l.is_checked ? 255 : m_l_cont.value; + PadStatus->triggerRight = m_r.is_checked ? 255 : m_r_cont.value; for (unsigned int i = 0; i < ArraySize(m_buttons); ++i) { if (m_buttons[i] != nullptr) { - if (m_buttons[i]->checkbox->IsChecked()) + if (m_buttons[i]->is_checked) PadStatus->button |= m_gc_pad_buttons_bitmask[i]; else PadStatus->button &= ~m_gc_pad_buttons_bitmask[i]; } } - if (m_a.checkbox->IsChecked()) + if (m_a.is_checked) PadStatus->analogA = 0xFF; else PadStatus->analogA = 0x00; - if (m_b.checkbox->IsChecked()) + if (m_b.is_checked) PadStatus->analogB = 0xFF; else PadStatus->analogB = 0x00; @@ -1035,6 +1076,7 @@ void TASInputDlg::SetTurbo(wxMouseEvent& event) event.Skip(); } +// NOTE: Host / CPU Thread void TASInputDlg::ButtonTurbo() { static u64 frame = Movie::g_currentFrame; @@ -1046,7 +1088,7 @@ void TASInputDlg::ButtonTurbo() { if (button != nullptr && button->turbo_on) { - button->value = !button->checkbox->GetValue(); + button->value = !button->is_checked; InvalidateButton(button); } } @@ -1056,7 +1098,7 @@ void TASInputDlg::ButtonTurbo() { if (button.turbo_on) { - button.value = !button.checkbox->GetValue(); + button.value = !button.is_checked; InvalidateButton(&button); } } @@ -1075,6 +1117,7 @@ void TASInputDlg::InvalidateButton(Button* button) } button->checkbox->SetValue(button->value); + button->is_checked = button->value; } void TASInputDlg::InvalidateControl(Control* control) @@ -1090,11 +1133,23 @@ void TASInputDlg::InvalidateControl(Control* control) control->text->SetValue(std::to_string(control->value)); } +void TASInputDlg::InvalidateExtension() +{ + if (!wxIsMainThread()) + { + GetEventHandler()->QueueEvent(new wxThreadEvent(INVALIDATE_EXTENSION_EVENT)); + return; + } + + HandleExtensionChange(); +} + void TASInputDlg::UpdateFromInvalidatedButton(wxCommandEvent& event) { Button* button = static_cast(event.GetClientData()); _assert_msg_(PAD, button->id == button->checkbox->GetId(), "Button ids do not match: %i != %i", button->id, button->checkbox->GetId()); button->checkbox->SetValue(button->value); + button->is_checked = button->value; } void TASInputDlg::UpdateFromInvalidatedControl(wxCommandEvent& event) @@ -1104,6 +1159,11 @@ void TASInputDlg::UpdateFromInvalidatedControl(wxCommandEvent& event) control->text->SetValue(std::to_string(control->value)); } +void TASInputDlg::UpdateFromInvalidatedExtension(wxThreadEvent&) +{ + HandleExtensionChange(); +} + wxBitmap TASInputDlg::CreateStickBitmap(int x, int y) { x = x / 2; diff --git a/Source/Core/DolphinWX/TASInputDlg.h b/Source/Core/DolphinWX/TASInputDlg.h index ba003fddf7..f7e4996374 100644 --- a/Source/Core/DolphinWX/TASInputDlg.h +++ b/Source/Core/DolphinWX/TASInputDlg.h @@ -70,6 +70,7 @@ class TASInputDlg : public wxDialog struct Button { wxCheckBox* checkbox; + bool is_checked = false; bool value = false; bool set_by_keyboard = false; bool turbo_on = false; @@ -92,8 +93,11 @@ class TASInputDlg : public wxDialog void UpdateStickBitmap(Stick stick); void InvalidateButton(Button* button); void InvalidateControl(Control* button); + void InvalidateExtension(); void UpdateFromInvalidatedButton(wxCommandEvent& event); void UpdateFromInvalidatedControl(wxCommandEvent& event); + void UpdateFromInvalidatedExtension(wxThreadEvent& event); + void OnCheckboxToggle(wxCommandEvent& event); Stick* FindStickByID(int id); Stick CreateStick(int id_stick, int xRange, int yRange, u32 defaultX, u32 defaultY, bool reverseX, bool reverseY); wxStaticBoxSizer* CreateStickLayout(Stick* tempStick, const wxString& title);