From 0a121c97c79d329caa027e21714737a70cef80dd Mon Sep 17 00:00:00 2001 From: capitalistspz Date: Thu, 26 Jun 2025 16:25:34 +0100 Subject: [PATCH 01/31] Input: Detect Classic Controller Pro as Classic Controller (#1614) --- src/input/api/Wiimote/WiimoteControllerProvider.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/input/api/Wiimote/WiimoteControllerProvider.cpp b/src/input/api/Wiimote/WiimoteControllerProvider.cpp index 221d75a7..c2454319 100644 --- a/src/input/api/Wiimote/WiimoteControllerProvider.cpp +++ b/src/input/api/Wiimote/WiimoteControllerProvider.cpp @@ -323,6 +323,7 @@ void WiimoteControllerProvider::reader_thread() break; case kExtensionClassicPro: cemuLog_logDebug(LogType::Force,"Extension Type Received: Classic Pro"); + new_state.m_extension = ClassicData{}; break; case kExtensionGuitar: cemuLog_logDebug(LogType::Force,"Extension Type Received: Guitar"); From 7db2b77983ce4059c6bf706b1e8789b1f4038acc Mon Sep 17 00:00:00 2001 From: Exzap <13877693+Exzap@users.noreply.github.com> Date: Sat, 28 Jun 2025 14:53:15 +0200 Subject: [PATCH 02/31] CPU: Implement more instructions in interpreter + various fixes All of the changes are verified against real hardware, except for the byte string instructions --- .../Interpreter/PPCInterpreterALU.hpp | 165 +++++++++++++----- .../Interpreter/PPCInterpreterImpl.cpp | 81 ++++++--- .../Interpreter/PPCInterpreterLoadStore.hpp | 115 ++++++++++-- .../Interpreter/PPCInterpreterMain.cpp | 3 +- .../Interpreter/PPCInterpreterOPC.cpp | 1 - .../Interpreter/PPCInterpreterOPC.hpp | 2 + .../OS/libs/coreinit/coreinit_OSScreen.cpp | 1 - 7 files changed, 281 insertions(+), 87 deletions(-) diff --git a/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterALU.hpp b/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterALU.hpp index 769344f8..2fe07509 100644 --- a/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterALU.hpp +++ b/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterALU.hpp @@ -41,7 +41,7 @@ static void PPCInterpreter_ADD(PPCInterpreter_t* hCPU, uint32 opcode) static void PPCInterpreter_ADDO(PPCInterpreter_t* hCPU, uint32 opcode) { - // untested (Don't Starve Giant Edition uses this instruction + BSO) + // Don't Starve Giant Edition uses this instruction + BSO PPC_OPC_TEMPL3_XO(); uint32 result = hCPU->gpr[rA] + hCPU->gpr[rB]; PPCInterpreter_setXerOV(hCPU, checkAdditionOverflow(hCPU->gpr[rA], hCPU->gpr[rB], result)); @@ -113,7 +113,6 @@ static void PPCInterpreter_ADDEO(PPCInterpreter_t* hCPU, uint32 opcode) else hCPU->xer_ca = 0; PPCInterpreter_setXerOV(hCPU, checkAdditionOverflow(a, b, hCPU->gpr[rD])); - // update CR if (opHasRC()) ppc_update_cr0(hCPU, hCPU->gpr[rD]); PPCInterpreter_nextInstruction(hCPU); @@ -130,7 +129,7 @@ static void PPCInterpreter_ADDI(PPCInterpreter_t* hCPU, uint32 opcode) static void PPCInterpreter_ADDIC(PPCInterpreter_t* hCPU, uint32 opcode) { - int rD, rA; + sint32 rD, rA; uint32 imm; PPC_OPC_TEMPL_D_SImm(opcode, rD, rA, imm); uint32 a = hCPU->gpr[rA]; @@ -145,7 +144,7 @@ static void PPCInterpreter_ADDIC(PPCInterpreter_t* hCPU, uint32 opcode) static void PPCInterpreter_ADDIC_(PPCInterpreter_t* hCPU, uint32 opcode) { - int rD, rA; + sint32 rD, rA; uint32 imm; PPC_OPC_TEMPL_D_SImm(opcode, rD, rA, imm); uint32 a = hCPU->gpr[rA]; @@ -155,14 +154,13 @@ static void PPCInterpreter_ADDIC_(PPCInterpreter_t* hCPU, uint32 opcode) hCPU->xer_ca = 1; else hCPU->xer_ca = 0; - // update cr0 flags ppc_update_cr0(hCPU, hCPU->gpr[rD]); PPCInterpreter_nextInstruction(hCPU); } static void PPCInterpreter_ADDIS(PPCInterpreter_t* hCPU, uint32 opcode) { - int rD, rA; + sint32 rD, rA; uint32 imm; PPC_OPC_TEMPL_D_Shift16(opcode, rD, rA, imm); hCPU->gpr[rD] = (rA ? hCPU->gpr[rA] : 0) + imm; @@ -185,6 +183,23 @@ static void PPCInterpreter_ADDZE(PPCInterpreter_t* hCPU, uint32 opcode) PPCInterpreter_nextInstruction(hCPU); } +static void PPCInterpreter_ADDZEO(PPCInterpreter_t* hCPU, uint32 opcode) +{ + PPC_OPC_TEMPL3_XO(); + PPC_ASSERT(rB == 0); + uint32 a = hCPU->gpr[rA]; + uint32 ca = hCPU->xer_ca; + hCPU->gpr[rD] = a + ca; + PPCInterpreter_setXerOV(hCPU, checkAdditionOverflow(a, 0, hCPU->gpr[rD])); + if ((a == 0xffffffff) && ca) + hCPU->xer_ca = 1; + else + hCPU->xer_ca = 0; + if (opHasRC()) + ppc_update_cr0(hCPU, hCPU->gpr[rD]); + PPCInterpreter_nextInstruction(hCPU); +} + static void PPCInterpreter_ADDME(PPCInterpreter_t* hCPU, uint32 opcode) { PPC_OPC_TEMPL3_XO(); @@ -201,6 +216,23 @@ static void PPCInterpreter_ADDME(PPCInterpreter_t* hCPU, uint32 opcode) PPCInterpreter_nextInstruction(hCPU); } +static void PPCInterpreter_ADDMEO(PPCInterpreter_t* hCPU, uint32 opcode) +{ + PPC_OPC_TEMPL3_XO(); + PPC_ASSERT(rB == 0); + uint32 a = hCPU->gpr[rA]; + uint32 ca = hCPU->xer_ca; + hCPU->gpr[rD] = a + ca + 0xffffffff; + PPCInterpreter_setXerOV(hCPU, checkAdditionOverflow(a, 0xffffffff, hCPU->gpr[rD])); + if (a || ca) + hCPU->xer_ca = 1; + else + hCPU->xer_ca = 0; + if (opHasRC()) + ppc_update_cr0(hCPU, hCPU->gpr[rD]); + PPCInterpreter_nextInstruction(hCPU); +} + static void PPCInterpreter_SUBF(PPCInterpreter_t* hCPU, uint32 opcode) { PPC_OPC_TEMPL3_XO(); @@ -260,7 +292,7 @@ static void PPCInterpreter_SUBFCO(PPCInterpreter_t* hCPU, uint32 opcode) static void PPCInterpreter_SUBFIC(PPCInterpreter_t* hCPU, uint32 opcode) { - int rD, rA; + sint32 rD, rA; uint32 imm; PPC_OPC_TEMPL_D_SImm(opcode, rD, rA, imm); uint32 a = hCPU->gpr[rA]; @@ -284,7 +316,6 @@ static void PPCInterpreter_SUBFE(PPCInterpreter_t* hCPU, uint32 opcode) hCPU->xer_ca = 1; else hCPU->xer_ca = 0; - // update cr0 if (opHasRC()) ppc_update_cr0(hCPU, hCPU->gpr[rD]); PPCInterpreter_nextInstruction(hCPU); @@ -304,7 +335,6 @@ static void PPCInterpreter_SUBFEO(PPCInterpreter_t* hCPU, uint32 opcode) else hCPU->xer_ca = 0; PPCInterpreter_setXerOV(hCPU, checkAdditionOverflow(~a, b, result)); - // update cr0 if (opHasRC()) ppc_update_cr0(hCPU, hCPU->gpr[rD]); PPCInterpreter_nextInstruction(hCPU); @@ -326,9 +356,25 @@ static void PPCInterpreter_SUBFZE(PPCInterpreter_t* hCPU, uint32 opcode) PPCInterpreter_nextInstruction(hCPU); } +static void PPCInterpreter_SUBFZEO(PPCInterpreter_t* hCPU, uint32 opcode) +{ + PPC_OPC_TEMPL3_XO(); + PPC_ASSERT(rB == 0); + uint32 a = hCPU->gpr[rA]; + uint32 ca = hCPU->xer_ca; + hCPU->gpr[rD] = ~a + ca; + PPCInterpreter_setXerOV(hCPU, checkAdditionOverflow(~a, 0, hCPU->gpr[rD])); + if (a == 0 && ca) + hCPU->xer_ca = 1; + else + hCPU->xer_ca = 0; + if (opHasRC()) + ppc_update_cr0(hCPU, hCPU->gpr[rD]); + PPCInterpreter_nextInstruction(hCPU); +} + static void PPCInterpreter_SUBFME(PPCInterpreter_t* hCPU, uint32 opcode) { - // untested PPC_OPC_TEMPL3_XO(); PPC_ASSERT(rB == 0); uint32 a = hCPU->gpr[rA]; @@ -339,7 +385,24 @@ static void PPCInterpreter_SUBFME(PPCInterpreter_t* hCPU, uint32 opcode) hCPU->xer_ca = 1; else hCPU->xer_ca = 0; - // update cr0 + if (opcode & PPC_OPC_RC) + ppc_update_cr0(hCPU, hCPU->gpr[rD]); + PPCInterpreter_nextInstruction(hCPU); +} + +static void PPCInterpreter_SUBFMEO(PPCInterpreter_t* hCPU, uint32 opcode) +{ + PPC_OPC_TEMPL3_XO(); + PPC_ASSERT(rB == 0); + uint32 a = hCPU->gpr[rA]; + uint32 ca = hCPU->xer_ca; + hCPU->gpr[rD] = ~a + 0xFFFFFFFF + ca; + PPCInterpreter_setXerOV(hCPU, checkAdditionOverflow(~a, 0xFFFFFFFF, hCPU->gpr[rD])); + // update xer carry + if (ppc_carry_3(~a, 0xFFFFFFFF, ca)) + hCPU->xer_ca = 1; + else + hCPU->xer_ca = 0; if (opcode & PPC_OPC_RC) ppc_update_cr0(hCPU, hCPU->gpr[rD]); PPCInterpreter_nextInstruction(hCPU); @@ -352,13 +415,8 @@ static void PPCInterpreter_MULHW_(PPCInterpreter_t* hCPU, uint32 opcode) sint64 b = (sint32)hCPU->gpr[rB]; sint64 c = a * b; hCPU->gpr[rD] = ((uint64)c) >> 32; - if (opcode & PPC_OPC_RC) { - // update cr0 flags -#ifdef CEMU_DEBUG_ASSERT - assert_dbg(); -#endif + if (opHasRC()) ppc_update_cr0(hCPU, hCPU->gpr[rD]); - } PPCInterpreter_nextInstruction(hCPU); } @@ -409,14 +467,14 @@ static void PPCInterpreter_MULLI(PPCInterpreter_t* hCPU, uint32 opcode) static void PPCInterpreter_DIVW(PPCInterpreter_t* hCPU, uint32 opcode) { PPC_OPC_TEMPL3_XO(); - sint32 a = hCPU->gpr[rA]; - sint32 b = hCPU->gpr[rB]; + sint32 a = (sint32)hCPU->gpr[rA]; + sint32 b = (sint32)hCPU->gpr[rB]; if (b == 0) - { - cemuLog_logDebug(LogType::Force, "Error: Division by zero! [{:08x}]", (uint32)hCPU->instructionPointer); - b++; - } - hCPU->gpr[rD] = a / b; + hCPU->gpr[rD] = a < 0 ? 0xFFFFFFFF : 0; + else if (a == 0x80000000 && b == 0xFFFFFFFF) + hCPU->gpr[rD] = 0xFFFFFFFF; + else + hCPU->gpr[rD] = a / b; if (opHasRC()) ppc_update_cr0(hCPU, hCPU->gpr[rD]); PPCInterpreter_nextInstruction(hCPU); @@ -425,16 +483,23 @@ static void PPCInterpreter_DIVW(PPCInterpreter_t* hCPU, uint32 opcode) static void PPCInterpreter_DIVWO(PPCInterpreter_t* hCPU, uint32 opcode) { PPC_OPC_TEMPL3_XO(); - sint32 a = hCPU->gpr[rA]; - sint32 b = hCPU->gpr[rB]; + sint32 a = (sint32)hCPU->gpr[rA]; + sint32 b = (sint32)hCPU->gpr[rB]; if (b == 0) { PPCInterpreter_setXerOV(hCPU, true); - PPCInterpreter_nextInstruction(hCPU); - return; + hCPU->gpr[rD] = a < 0 ? 0xFFFFFFFF : 0; + } + else if(a == 0x80000000 && b == 0xFFFFFFFF) + { + PPCInterpreter_setXerOV(hCPU, true); + hCPU->gpr[rD] = 0xFFFFFFFF; + } + else + { + hCPU->gpr[rD] = a / b; + PPCInterpreter_setXerOV(hCPU, false); } - hCPU->gpr[rD] = a / b; - PPCInterpreter_setXerOV(hCPU, false); if (opHasRC()) ppc_update_cr0(hCPU, hCPU->gpr[rD]); PPCInterpreter_nextInstruction(hCPU); @@ -443,12 +508,14 @@ static void PPCInterpreter_DIVWO(PPCInterpreter_t* hCPU, uint32 opcode) static void PPCInterpreter_DIVWU(PPCInterpreter_t* hCPU, uint32 opcode) { PPC_OPC_TEMPL3_XO(); - if (hCPU->gpr[rB] == 0) - { - PPCInterpreter_nextInstruction(hCPU); - return; - } - hCPU->gpr[rD] = hCPU->gpr[rA] / hCPU->gpr[rB]; + uint32 a = hCPU->gpr[rA]; + uint32 b = hCPU->gpr[rB]; + if (b == 0) + hCPU->gpr[rD] = 0; + else if (a == 0x80000000 && b == 0xFFFFFFFF) + hCPU->gpr[rD] = 0; + else + hCPU->gpr[rD] = a / b; if (opHasRC()) ppc_update_cr0(hCPU, hCPU->gpr[rD]); PPCInterpreter_nextInstruction(hCPU); @@ -457,14 +524,23 @@ static void PPCInterpreter_DIVWU(PPCInterpreter_t* hCPU, uint32 opcode) static void PPCInterpreter_DIVWUO(PPCInterpreter_t* hCPU, uint32 opcode) { PPC_OPC_TEMPL3_XO(); - if (hCPU->gpr[rB] == 0) + uint32 a = hCPU->gpr[rA]; + uint32 b = hCPU->gpr[rB]; + if (b == 0) { PPCInterpreter_setXerOV(hCPU, true); - PPCInterpreter_nextInstruction(hCPU); - return; + hCPU->gpr[rD] = 0; + } + else if(a == 0x80000000 && b == 0xFFFFFFFF) + { + PPCInterpreter_setXerOV(hCPU, false); + hCPU->gpr[rD] = 0; + } + else + { + hCPU->gpr[rD] = a / b; + PPCInterpreter_setXerOV(hCPU, false); } - hCPU->gpr[rD] = hCPU->gpr[rA] / hCPU->gpr[rB]; - PPCInterpreter_setXerOV(hCPU, false); if (opHasRC()) ppc_update_cr0(hCPU, hCPU->gpr[rD]); PPCInterpreter_nextInstruction(hCPU); @@ -491,6 +567,13 @@ static void PPCInterpreter_CRANDC(PPCInterpreter_t* hCPU, uint32 opcode) PPCInterpreter_nextInstruction(hCPU); } +static void PPCInterpreter_CRNAND(PPCInterpreter_t* hCPU, uint32 opcode) +{ + PPC_OPC_TEMPL_X_CR(); + ppc_setCRBit(hCPU, crD, (ppc_getCRBit(hCPU, crA)&ppc_getCRBit(hCPU, crB)) ^ 1); + PPCInterpreter_nextInstruction(hCPU); +} + static void PPCInterpreter_CROR(PPCInterpreter_t* hCPU, uint32 opcode) { PPC_OPC_TEMPL_X_CR(); diff --git a/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterImpl.cpp b/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterImpl.cpp index cacfa4a9..547472ab 100644 --- a/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterImpl.cpp +++ b/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterImpl.cpp @@ -428,9 +428,6 @@ public: } }; -uint32 testIP[100]; -uint32 testIPC = 0; - template class PPCInterpreterContainer { @@ -466,6 +463,10 @@ public: case 1: // virtual HLE PPCInterpreter_virtualHLE(hCPU, opcode); break; + case 3: + cemuLog_logDebug(LogType::Force, "Unsupported TWI instruction executed at {:08x}", hCPU->instructionPointer); + PPCInterpreter_nextInstruction(hCPU); + break; case 4: switch (PPC_getBits(opcode, 30, 5)) { @@ -482,8 +483,9 @@ public: PPCInterpreter_PS_CMPU1(hCPU, opcode); break; default: - debug_printf("Unknown execute %04X as [4->0] at %08X\n", PPC_getBits(opcode, 25, 5), hCPU->instructionPointer); + cemuLog_logDebug(LogType::Force, "Unknown execute {:04x} as [4->0] at {:08x}", PPC_getBits(opcode, 25, 5), hCPU->instructionPointer); cemu_assert_unimplemented(); + hCPU->instructionPointer += 4; break; } break; @@ -509,8 +511,9 @@ public: PPCInterpreter_PS_ABS(hCPU, opcode); break; default: - debug_printf("Unknown execute %04X as [4->8] at %08X\n", PPC_getBits(opcode, 25, 5), hCPU->instructionPointer); + cemuLog_logDebug(LogType::Force, "Unknown execute {:04x} as [4->8] at {:08x}", PPC_getBits(opcode, 25, 5), hCPU->instructionPointer); cemu_assert_unimplemented(); + hCPU->instructionPointer += 4; break; } break; @@ -548,8 +551,9 @@ public: PPCInterpreter_PS_MERGE11(hCPU, opcode); break; default: - debug_printf("Unknown execute %04X as [4->16] at %08X\n", PPC_getBits(opcode, 25, 5), hCPU->instructionPointer); - debugBreakpoint(); + cemuLog_logDebug(LogType::Force, "Unknown execute {:04x} as [4->16] at {:08x}", PPC_getBits(opcode, 25, 5), hCPU->instructionPointer); + cemu_assert_unimplemented(); + hCPU->instructionPointer += 4; break; } break; @@ -590,8 +594,9 @@ public: PPCInterpreter_PS_NMADD(hCPU, opcode); break; default: - debug_printf("Unknown execute %04X as [4] at %08X\n", PPC_getBits(opcode, 30, 5), hCPU->instructionPointer); + cemuLog_logDebug(LogType::Force, "Unknown execute {:04x} as [4] at {:08x}", PPC_getBits(opcode, 30, 5), hCPU->instructionPointer); cemu_assert_unimplemented(); + hCPU->instructionPointer += 4; break; } break; @@ -623,12 +628,15 @@ public: PPCInterpreter_BCX(hCPU, opcode); break; case 17: - if (PPC_getBits(opcode, 30, 1) == 1) { + if (PPC_getBits(opcode, 30, 1) == 1) + { PPCInterpreter_SC(hCPU, opcode); } - else { - debug_printf("Unsupported Opcode [0x17 --> 0x0]\n"); + else + { + cemuLog_logDebug(LogType::Force, "Unsupported Opcode [0x17 --> 0x0]"); cemu_assert_unimplemented(); + hCPU->instructionPointer += 4; } break; case 18: @@ -658,6 +666,9 @@ public: case 193: PPCInterpreter_CRXOR(hCPU, opcode); break; + case 225: + PPCInterpreter_CRNAND(hCPU, opcode); + break; case 257: PPCInterpreter_CRAND(hCPU, opcode); break; @@ -674,8 +685,9 @@ public: PPCInterpreter_BCCTR(hCPU, opcode); break; default: - debug_printf("Unknown execute %04X as [19] at %08X\n", PPC_getBits(opcode, 30, 10), hCPU->instructionPointer); + cemuLog_logDebug(LogType::Force, "Unknown execute {:04x} as [19] at {:08x}\n", PPC_getBits(opcode, 30, 10), hCPU->instructionPointer); cemu_assert_unimplemented(); + hCPU->instructionPointer += 4; break; } break; @@ -713,9 +725,6 @@ public: PPCInterpreter_CMP(hCPU, opcode); break; case 4: - #ifdef CEMU_DEBUG_ASSERT - debug_printf("TW instruction executed at %08x\n", hCPU->instructionPointer); - #endif PPCInterpreter_TW(hCPU, opcode); break; case 8: @@ -895,6 +904,12 @@ public: case 522: PPCInterpreter_ADDCO(hCPU, opcode); break; + case 523: // 11 | OE + PPCInterpreter_MULHWU_(hCPU, opcode); // OE is ignored + break; + case 533: + PPCInterpreter_LSWX(hCPU, opcode); + break; case 534: PPCInterpreter_LWBRX(hCPU, opcode); break; @@ -913,6 +928,9 @@ public: case 567: PPCInterpreter_LFSUX(hCPU, opcode); break; + case 587: // 75 | OE + PPCInterpreter_MULHW_(hCPU, opcode); // OE is ignored for MULHW + break; case 595: PPCInterpreter_MFSR(hCPU, opcode); break; @@ -943,15 +961,30 @@ public: case 663: PPCInterpreter_STFSX(hCPU, opcode); break; + case 661: + PPCInterpreter_STSWX(hCPU, opcode); + break; case 695: PPCInterpreter_STFSUX(hCPU, opcode); break; + case 712: // 200 | OE + PPCInterpreter_SUBFZEO(hCPU, opcode); + break; + case 714: // 202 | OE + PPCInterpreter_ADDZEO(hCPU, opcode); + break; case 725: PPCInterpreter_STSWI(hCPU, opcode); break; case 727: PPCInterpreter_STFDX(hCPU, opcode); break; + case 744: // 232 | OE + PPCInterpreter_SUBFMEO(hCPU, opcode); + break; + case 746: // 234 | OE + PPCInterpreter_ADDMEO(hCPU, opcode); + break; case 747: PPCInterpreter_MULLWO(hCPU, opcode); break; @@ -998,10 +1031,8 @@ public: PPCInterpreter_DCBZ(hCPU, opcode); break; default: - debug_printf("Unknown execute %04X as [31] at %08X\n", PPC_getBits(opcode, 30, 10), hCPU->instructionPointer); - #ifdef CEMU_DEBUG_ASSERT - assert_dbg(); - #endif + cemuLog_logDebug(LogType::Force, "Unknown execute {:04x} as [31] at {:08x}\n", PPC_getBits(opcode, 30, 10), hCPU->instructionPointer); + cemu_assert_unimplemented(); hCPU->instructionPointer += 4; break; } @@ -1084,7 +1115,7 @@ public: case 57: PPCInterpreter_PSQ_LU(hCPU, opcode); break; - case 59: //Opcode category + case 59: // opcode category switch (PPC_getBits(opcode, 30, 5)) { case 18: @@ -1115,8 +1146,9 @@ public: PPCInterpreter_FNMADDS(hCPU, opcode); break; default: - debug_printf("Unknown execute %04X as [59] at %08X\n", PPC_getBits(opcode, 30, 10), hCPU->instructionPointer); + cemuLog_logDebug(LogType::Force, "Unknown execute {:04x} as [59] at {:08x}\n", PPC_getBits(opcode, 30, 10), hCPU->instructionPointer); cemu_assert_unimplemented(); + hCPU->instructionPointer += 4; break; } break; @@ -1195,18 +1227,19 @@ public: case 583: PPCInterpreter_MFFS(hCPU, opcode); break; - case 711: // IBM documentation has this wrong as 771? + case 711: PPCInterpreter_MTFSF(hCPU, opcode); break; default: - debug_printf("Unknown execute %04X as [63] at %08X\n", PPC_getBits(opcode, 30, 10), hCPU->instructionPointer); + cemuLog_logDebug(LogType::Force, "Unknown execute {:04x} as [63] at {:08x}\n", PPC_getBits(opcode, 30, 10), hCPU->instructionPointer); cemu_assert_unimplemented(); + PPCInterpreter_nextInstruction(hCPU); break; } } break; default: - debug_printf("Unknown execute %04X at %08X\n", PPC_getBits(opcode, 5, 6), (unsigned int)hCPU->instructionPointer); + cemuLog_logDebug(LogType::Force, "Unknown execute {:04x} at {:08x}\n", PPC_getBits(opcode, 5, 6), (unsigned int)hCPU->instructionPointer); cemu_assert_unimplemented(); } } diff --git a/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterLoadStore.hpp b/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterLoadStore.hpp index 26467458..ea7bb038 100644 --- a/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterLoadStore.hpp +++ b/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterLoadStore.hpp @@ -31,7 +31,7 @@ static void PPCInterpreter_STW(PPCInterpreter_t* hCPU, uint32 Opcode) static void PPCInterpreter_STWU(PPCInterpreter_t* hCPU, uint32 Opcode) { - int rA, rS; + sint32 rA, rS; uint32 imm; PPC_OPC_TEMPL_D_SImm(Opcode, rS, rA, imm); ppcItpCtrl::ppcMem_writeDataU32(hCPU, hCPU->gpr[rA] + imm, hCPU->gpr[rS]); @@ -42,7 +42,7 @@ static void PPCInterpreter_STWU(PPCInterpreter_t* hCPU, uint32 Opcode) static void PPCInterpreter_STWX(PPCInterpreter_t* hCPU, uint32 Opcode) { - int rA, rS, rB; + sint32 rA, rS, rB; PPC_OPC_TEMPL_X(Opcode, rS, rA, rB); ppcItpCtrl::ppcMem_writeDataU32(hCPU, (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB], hCPU->gpr[rS]); PPCInterpreter_nextInstruction(hCPU); @@ -103,7 +103,7 @@ static void PPCInterpreter_STWCX(PPCInterpreter_t* hCPU, uint32 Opcode) static void PPCInterpreter_STWUX(PPCInterpreter_t* hCPU, uint32 Opcode) { - int rA, rS, rB; + sint32 rA, rS, rB; PPC_OPC_TEMPL_X(Opcode, rS, rA, rB); ppcItpCtrl::ppcMem_writeDataU32(hCPU, (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB], hCPU->gpr[rS]); if (rA) @@ -113,7 +113,7 @@ static void PPCInterpreter_STWUX(PPCInterpreter_t* hCPU, uint32 Opcode) static void PPCInterpreter_STWBRX(PPCInterpreter_t* hCPU, uint32 Opcode) { - int rA, rS, rB; + sint32 rA, rS, rB; PPC_OPC_TEMPL_X(Opcode, rS, rA, rB); ppcItpCtrl::ppcMem_writeDataU32(hCPU, (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB], _swapEndianU32(hCPU->gpr[rS])); PPCInterpreter_nextInstruction(hCPU); @@ -121,7 +121,7 @@ static void PPCInterpreter_STWBRX(PPCInterpreter_t* hCPU, uint32 Opcode) static void PPCInterpreter_STMW(PPCInterpreter_t* hCPU, uint32 Opcode) { - int rS, rA; + sint32 rS, rA; uint32 imm; PPC_OPC_TEMPL_D_SImm(Opcode, rS, rA, imm); uint32 ea = (rA ? hCPU->gpr[rA] : 0) + imm; @@ -136,7 +136,7 @@ static void PPCInterpreter_STMW(PPCInterpreter_t* hCPU, uint32 Opcode) static void PPCInterpreter_STH(PPCInterpreter_t* hCPU, uint32 Opcode) { - int rA, rS; + sint32 rA, rS; uint32 imm; PPC_OPC_TEMPL_D_SImm(Opcode, rS, rA, imm); ppcItpCtrl::ppcMem_writeDataU16(hCPU, (rA ? hCPU->gpr[rA] : 0) + imm, (uint16)hCPU->gpr[rS]); @@ -145,7 +145,7 @@ static void PPCInterpreter_STH(PPCInterpreter_t* hCPU, uint32 Opcode) static void PPCInterpreter_STHU(PPCInterpreter_t* hCPU, uint32 Opcode) { - int rA, rS; + sint32 rA, rS; uint32 imm; PPC_OPC_TEMPL_D_SImm(Opcode, rS, rA, imm); ppcItpCtrl::ppcMem_writeDataU16(hCPU, (rA ? hCPU->gpr[rA] : 0) + imm, (uint16)hCPU->gpr[rS]); @@ -156,7 +156,7 @@ static void PPCInterpreter_STHU(PPCInterpreter_t* hCPU, uint32 Opcode) static void PPCInterpreter_STHX(PPCInterpreter_t* hCPU, uint32 Opcode) { - int rA, rS, rB; + sint32 rA, rS, rB; PPC_OPC_TEMPL_X(Opcode, rS, rA, rB); ppcItpCtrl::ppcMem_writeDataU16(hCPU, (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB], (uint16)hCPU->gpr[rS]); PPCInterpreter_nextInstruction(hCPU); @@ -164,7 +164,7 @@ static void PPCInterpreter_STHX(PPCInterpreter_t* hCPU, uint32 Opcode) static void PPCInterpreter_STHUX(PPCInterpreter_t* hCPU, uint32 Opcode) { - int rA, rS, rB; + sint32 rA, rS, rB; PPC_OPC_TEMPL_X(Opcode, rS, rA, rB); ppcItpCtrl::ppcMem_writeDataU16(hCPU, (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB], (uint16)hCPU->gpr[rS]); if (rA) @@ -174,7 +174,7 @@ static void PPCInterpreter_STHUX(PPCInterpreter_t* hCPU, uint32 Opcode) static void PPCInterpreter_STHBRX(PPCInterpreter_t* hCPU, uint32 Opcode) { - int rA, rS, rB; + sint32 rA, rS, rB; PPC_OPC_TEMPL_X(Opcode, rS, rA, rB); ppcItpCtrl::ppcMem_writeDataU16(hCPU, (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB], _swapEndianU16((uint16)hCPU->gpr[rS])); PPCInterpreter_nextInstruction(hCPU); @@ -182,7 +182,7 @@ static void PPCInterpreter_STHBRX(PPCInterpreter_t* hCPU, uint32 Opcode) static void PPCInterpreter_STB(PPCInterpreter_t* hCPU, uint32 Opcode) { - int rA, rS; + sint32 rA, rS; uint32 imm; PPC_OPC_TEMPL_D_SImm(Opcode, rS, rA, imm); ppcItpCtrl::ppcMem_writeDataU8(hCPU, (rA ? hCPU->gpr[rA] : 0) + imm, (uint8)hCPU->gpr[rS]); @@ -191,7 +191,7 @@ static void PPCInterpreter_STB(PPCInterpreter_t* hCPU, uint32 Opcode) static void PPCInterpreter_STBU(PPCInterpreter_t* hCPU, uint32 Opcode) { - int rA, rS; + sint32 rA, rS; uint32 imm; PPC_OPC_TEMPL_D_SImm(Opcode, rS, rA, imm); ppcItpCtrl::ppcMem_writeDataU8(hCPU, hCPU->gpr[rA] + imm, (uint8)hCPU->gpr[rS]); @@ -201,7 +201,7 @@ static void PPCInterpreter_STBU(PPCInterpreter_t* hCPU, uint32 Opcode) static void PPCInterpreter_STBX(PPCInterpreter_t* hCPU, uint32 Opcode) { - int rA, rS, rB; + sint32 rA, rS, rB; PPC_OPC_TEMPL_X(Opcode, rS, rA, rB); ppcItpCtrl::ppcMem_writeDataU8(hCPU, (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB], (uint8)hCPU->gpr[rS]); PPCInterpreter_nextInstruction(hCPU); @@ -209,7 +209,7 @@ static void PPCInterpreter_STBX(PPCInterpreter_t* hCPU, uint32 Opcode) static void PPCInterpreter_STBUX(PPCInterpreter_t* hCPU, uint32 Opcode) { - int rA, rS, rB; + sint32 rA, rS, rB; PPC_OPC_TEMPL_X(Opcode, rS, rA, rB); ppcItpCtrl::ppcMem_writeDataU8(hCPU, (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB], (uint8)hCPU->gpr[rS]); if (rA) @@ -219,7 +219,7 @@ static void PPCInterpreter_STBUX(PPCInterpreter_t* hCPU, uint32 Opcode) static void PPCInterpreter_STSWI(PPCInterpreter_t* hCPU, uint32 Opcode) { - int rA, rS, nb; + sint32 rA, rS, nb; PPC_OPC_TEMPL_X(Opcode, rS, rA, nb); if (nb == 0) nb = 32; uint32 ea = rA ? hCPU->gpr[rA] : 0; @@ -229,7 +229,39 @@ static void PPCInterpreter_STSWI(PPCInterpreter_t* hCPU, uint32 Opcode) { if (i == 0) { - r = hCPU->gpr[rS]; + r = rS < 32 ? hCPU->gpr[rS] : 0; // what happens if rS is out of bounds? + rS++; + rS %= 32; + i = 4; + } + ppcItpCtrl::ppcMem_writeDataU8(hCPU, ea, (r >> 24)); + r <<= 8; + ea++; + i--; + nb--; + } + PPCInterpreter_nextInstruction(hCPU); +} + +static void PPCInterpreter_STSWX(PPCInterpreter_t* hCPU, uint32 Opcode) +{ + sint32 rA, rS, rB; + PPC_OPC_TEMPL_X(Opcode, rS, rA, rB); + sint32 nb = hCPU->spr.XER&0x7F; + if (nb == 0) + { + PPCInterpreter_nextInstruction(hCPU); + return; + } + uint32 ea = rA ? hCPU->gpr[rA] : 0; + ea += hCPU->gpr[rB]; + uint32 r = 0; + int i = 0; + while (nb > 0) + { + if (i == 0) + { + r = rS < 32 ? hCPU->gpr[rS] : 0; // what happens if rS is out of bounds? rS++; rS %= 32; i = 4; @@ -460,7 +492,6 @@ static void PPCInterpreter_LSWI(PPCInterpreter_t* hCPU, uint32 Opcode) PPC_OPC_TEMPL_X(Opcode, rD, rA, nb); if (nb == 0) nb = 32; - uint32 ea = rA ? hCPU->gpr[rA] : 0; uint32 r = 0; int i = 4; @@ -470,7 +501,8 @@ static void PPCInterpreter_LSWI(PPCInterpreter_t* hCPU, uint32 Opcode) if (i == 0) { i = 4; - hCPU->gpr[rD] = r; + if(rD < 32) + hCPU->gpr[rD] = r; rD++; rD %= 32; r = 0; @@ -487,7 +519,52 @@ static void PPCInterpreter_LSWI(PPCInterpreter_t* hCPU, uint32 Opcode) r <<= 8; i--; } - hCPU->gpr[rD] = r; + if(rD < 32) + hCPU->gpr[rD] = r; + PPCInterpreter_nextInstruction(hCPU); +} + +static void PPCInterpreter_LSWX(PPCInterpreter_t* hCPU, uint32 Opcode) +{ + sint32 rA, rD, rB; + PPC_OPC_TEMPL_X(Opcode, rD, rA, rB); + // byte count comes from XER + uint32 nb = (hCPU->spr.XER>>0)&0x7F; + if (nb == 0) + { + PPCInterpreter_nextInstruction(hCPU); + return; // no-op + } + uint32 ea = rA ? hCPU->gpr[rA] : 0; + ea += hCPU->gpr[rB]; + uint32 r = 0; + int i = 4; + uint8 v; + while (nb>0) + { + if (i == 0) + { + i = 4; + if(rD < 32) + hCPU->gpr[rD] = r; + rD++; + rD %= 32; + r = 0; + } + v = ppcItpCtrl::ppcMem_readDataU8(hCPU, ea); + r <<= 8; + r |= v; + ea++; + i--; + nb--; + } + while (i) + { + r <<= 8; + i--; + } + if(rD < 32) + hCPU->gpr[rD] = r; PPCInterpreter_nextInstruction(hCPU); } diff --git a/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterMain.cpp b/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterMain.cpp index 08d6765a..4449f135 100644 --- a/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterMain.cpp +++ b/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterMain.cpp @@ -77,7 +77,8 @@ uint32 PPCInterpreter_getXER(PPCInterpreter_t* hCPU) void PPCInterpreter_setXER(PPCInterpreter_t* hCPU, uint32 v) { - hCPU->spr.XER = v; + const uint32 XER_MASK = 0xE0FFFFFF; // some bits are masked out. Figure out which ones exactly + hCPU->spr.XER = v & XER_MASK; hCPU->xer_ca = (v >> XER_BIT_CA) & 1; hCPU->xer_so = (v >> XER_BIT_SO) & 1; hCPU->xer_ov = (v >> XER_BIT_OV) & 1; diff --git a/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterOPC.cpp b/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterOPC.cpp index d6b643ee..7809a01d 100644 --- a/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterOPC.cpp +++ b/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterOPC.cpp @@ -93,7 +93,6 @@ void PPCInterpreter_MTCRF(PPCInterpreter_t* hCPU, uint32 Opcode) { // frequently used by GCC compiled code (e.g. SM64 port) // tested - uint32 rS; uint32 crfMask; PPC_OPC_TEMPL_XFX(Opcode, rS, crfMask); diff --git a/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterOPC.hpp b/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterOPC.hpp index 718162be..9bfcd53d 100644 --- a/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterOPC.hpp +++ b/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterOPC.hpp @@ -68,6 +68,8 @@ static void PPCInterpreter_TW(PPCInterpreter_t* hCPU, uint32 opcode) PPC_OPC_TEMPL_X(opcode, to, rA, rB); cemu_assert_debug(to == 0); + if(to != 0) + PPCInterpreter_nextInstruction(hCPU); if (rA == DEBUGGER_BP_T_DEBUGGER) debugger_enterTW(hCPU); diff --git a/src/Cafe/OS/libs/coreinit/coreinit_OSScreen.cpp b/src/Cafe/OS/libs/coreinit/coreinit_OSScreen.cpp index 371ead3c..7b51629e 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_OSScreen.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_OSScreen.cpp @@ -96,7 +96,6 @@ namespace coreinit { ppcDefineParamU32(screenIndex, 0); cemu_assert(screenIndex < 2); - cemuLog_logDebug(LogType::Force, "OSScreenFlipBuffersEx {}", screenIndex); LatteGPUState.osScreen.screen[screenIndex].flipRequestCount++; _updateCurrentDrawScreen(screenIndex); osLib_returnFromFunction(hCPU, 0); From 13ccf9a160f38eff5d0b85db28625a6dd38b191d Mon Sep 17 00:00:00 2001 From: Exzap <13877693+Exzap@users.noreply.github.com> Date: Sat, 28 Jun 2025 21:43:40 +0200 Subject: [PATCH 03/31] MMU: Fix bit width for 32bit MMIO reads This resolves the ghost input issue in N64 virtual console --- src/Cafe/HW/MMU/MMU.cpp | 2 +- src/Cafe/HW/MMU/MMU.h | 2 +- src/Cafe/HW/SI/SI.cpp | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Cafe/HW/MMU/MMU.cpp b/src/Cafe/HW/MMU/MMU.cpp index 04ee8877..f88c3d0d 100644 --- a/src/Cafe/HW/MMU/MMU.cpp +++ b/src/Cafe/HW/MMU/MMU.cpp @@ -500,7 +500,7 @@ namespace MMU // todo - instead of passing the physical address to Read/WriteMMIO we should pass an interface id and a relative address? This would allow remapping the hardware address (tho we can just unregister + register at different addresses) - uint16 ReadMMIO_32(PAddr address) + uint32 ReadMMIO_32(PAddr address) { cemu_assert_debug((address & 0x3) == 0); auto itr = g_mmioHandlerR32->find(address); diff --git a/src/Cafe/HW/MMU/MMU.h b/src/Cafe/HW/MMU/MMU.h index 794785fa..a8367f88 100644 --- a/src/Cafe/HW/MMU/MMU.h +++ b/src/Cafe/HW/MMU/MMU.h @@ -261,7 +261,7 @@ namespace MMU void WriteMMIO_32(PAddr address, uint32 value); void WriteMMIO_16(PAddr address, uint16 value); - uint16 ReadMMIO_32(PAddr address); + uint32 ReadMMIO_32(PAddr address); uint16 ReadMMIO_16(PAddr address); } diff --git a/src/Cafe/HW/SI/SI.cpp b/src/Cafe/HW/SI/SI.cpp index 16cfb894..026543d8 100644 --- a/src/Cafe/HW/SI/SI.cpp +++ b/src/Cafe/HW/SI/SI.cpp @@ -87,7 +87,6 @@ namespace HW_SI HWREG::SICOMCSR SI_COMCSR_R32(PAddr addr) { - //cemuLog_logDebug(LogType::Force, "Read SICOMCSR"); return g_si.registerState.sicomcsr; } From 9fb3c76b761d141045914cc907b0b805822c5500 Mon Sep 17 00:00:00 2001 From: Colin Kinloch Date: Sun, 29 Jun 2025 18:36:22 +0100 Subject: [PATCH 04/31] UI: Include wx button header for wxWidgets 3.3 compatibility (#1621) --- src/gui/GettingStartedDialog.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/GettingStartedDialog.cpp b/src/gui/GettingStartedDialog.cpp index 22426cf2..b613c38c 100644 --- a/src/gui/GettingStartedDialog.cpp +++ b/src/gui/GettingStartedDialog.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "config/ActiveSettings.h" #include "gui/CemuApp.h" From 6c392d5a22a827437de7dbab11c47d90d0b443cf Mon Sep 17 00:00:00 2001 From: oltolm Date: Mon, 30 Jun 2025 00:15:23 +0200 Subject: [PATCH 05/31] UI: Fix assertions (#1623) --- src/gui/DownloadGraphicPacksWindow.cpp | 6 +++--- src/gui/input/panels/InputPanel.cpp | 7 +------ 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/gui/DownloadGraphicPacksWindow.cpp b/src/gui/DownloadGraphicPacksWindow.cpp index 9ea9e1dd..f2a90959 100644 --- a/src/gui/DownloadGraphicPacksWindow.cpp +++ b/src/gui/DownloadGraphicPacksWindow.cpp @@ -182,14 +182,14 @@ void DownloadGraphicPacksWindow::UpdateThread() if (checkGraphicPackDownloadedVersion(assetName, hasVersionFile)) { // already up to date - wxMessageBox(_("No updates available."), _("Graphic packs"), wxOK | wxCENTRE, this->GetParent()); + wxMessageBox(_("No updates available."), _("Graphic packs"), wxOK | wxCENTRE, this); m_threadState = ThreadFinished; return; } if (hasVersionFile) { // if a version file already exists (and graphic packs are installed) ask the user if he really wants to update - if (wxMessageBox(_("Updated graphic packs are available. Do you want to download and install them?"), _("Graphic packs"), wxYES_NO, this->GetParent()) != wxYES) + if (wxMessageBox(_("Updated graphic packs are available. Do you want to download and install them?"), _("Graphic packs"), wxYES_NO, this) != wxYES) { // cancel update m_threadState = ThreadFinished; @@ -336,7 +336,7 @@ int DownloadGraphicPacksWindow::ShowModal() { if(CafeSystem::IsTitleRunning()) { - wxMessageBox(_("Graphic packs cannot be updated while a game is running."), _("Graphic packs"), 5, this->GetParent()); + wxMessageBox(_("Graphic packs cannot be updated while a game is running."), _("Graphic packs"), 5, this); return wxID_CANCEL; } m_thread = std::thread(&DownloadGraphicPacksWindow::UpdateThread, this); diff --git a/src/gui/input/panels/InputPanel.cpp b/src/gui/input/panels/InputPanel.cpp index 514461fd..941bbd66 100644 --- a/src/gui/input/panels/InputPanel.cpp +++ b/src/gui/input/panels/InputPanel.cpp @@ -174,12 +174,7 @@ void InputPanel::load_controller(const EmulatedControllerPtr& controller) continue; auto button_name = controller->get_mapping_name(mapping); -#if BOOST_OS_WINDOWS - text->SetLabelText(button_name); -#else - // SetLabelText doesn't seem to work here for some reason on wxGTK - text->ChangeValue(button_name); -#endif + text->ChangeValue(button_name); } } From 35ecfa3f5478a94791b17e8156831fa312ad9cd1 Mon Sep 17 00:00:00 2001 From: qurious-pixel <62252937+qurious-pixel@users.noreply.github.com> Date: Mon, 30 Jun 2025 20:00:11 -0700 Subject: [PATCH 06/31] build: Fix glslang dependency for Fedora 42 (#1622) --- src/Cafe/CMakeLists.txt | 2 +- vcpkg.json | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Cafe/CMakeLists.txt b/src/Cafe/CMakeLists.txt index 64baa337..2900059b 100644 --- a/src/Cafe/CMakeLists.txt +++ b/src/Cafe/CMakeLists.txt @@ -552,7 +552,7 @@ target_include_directories(CemuCafe PUBLIC "../") if (glslang_VERSION VERSION_LESS "15.0.0") set(glslang_target "glslang::SPIRV") else() - set(glslang_target "glslang") + set(glslang_target "glslang::glslang") endif() target_link_libraries(CemuCafe PRIVATE diff --git a/vcpkg.json b/vcpkg.json index 0a46e32e..c746e00c 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -57,6 +57,10 @@ "libusb" ], "overrides": [ + { + "name": "glslang", + "version": "15.1.0" + }, { "name": "sdl2", "version": "2.30.3" From e68c31e5fbc089fddb25b60d51969f12ba909ce0 Mon Sep 17 00:00:00 2001 From: goeiecool9999 <7033575+goeiecool9999@users.noreply.github.com> Date: Wed, 2 Jul 2025 12:41:04 +0200 Subject: [PATCH 07/31] Fix path text encoding creating shortcuts on windows also fix a memory leak (hopefully) fixes: #1627 --- src/gui/components/wxGameList.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/gui/components/wxGameList.cpp b/src/gui/components/wxGameList.cpp index 587374f6..e30b16f5 100644 --- a/src/gui/components/wxGameList.cpp +++ b/src/gui/components/wxGameList.cpp @@ -1589,9 +1589,11 @@ void wxGameList::CreateShortcut(GameInfo2& gameInfo) PWSTR userShortcutFolder; SHGetKnownFolderPath(FOLDERID_Programs, 0, NULL, &userShortcutFolder); const wxString shortcutName = wxString::Format("%s.lnk", titleName); - wxFileDialog shortcutDialog(this, _("Choose shortcut location"), _pathToUtf8(userShortcutFolder), shortcutName, + wxFileDialog shortcutDialog(this, _("Choose shortcut location"), userShortcutFolder, shortcutName, "Shortcut (*.lnk)|*.lnk", wxFD_SAVE | wxFD_CHANGE_DIR | wxFD_OVERWRITE_PROMPT); + CoTaskMemFree(userShortcutFolder); + const auto result = shortcutDialog.ShowModal(); if (result == wxID_CANCEL) return; @@ -1621,7 +1623,7 @@ void wxGameList::CreateShortcut(GameInfo2& gameInfo) } icon_path = folder / fmt::format("{:016x}.ico", titleId); - auto stream = wxFileOutputStream(_pathToUtf8(*icon_path)); + auto stream = wxFileOutputStream(icon_path->wstring()); auto image = bitmap.ConvertToImage(); wxICOHandler icohandler{}; if (!icohandler.SaveFile(&image, stream, false)) From cdca5eaf788ebc9cd1443cb02412528cf595f1db Mon Sep 17 00:00:00 2001 From: AnimeGIF <30175255+Anime37@users.noreply.github.com> Date: Tue, 8 Jul 2025 00:55:57 +0300 Subject: [PATCH 08/31] UI: Add configurable hotkeys + a new fast forward hotkey (#1519) --- src/config/CemuConfig.cpp | 18 + src/config/CemuConfig.h | 55 +++ src/config/XMLConfig.h | 5 +- src/gui/CMakeLists.txt | 2 + src/gui/CemuApp.cpp | 3 + src/gui/MainWindow.cpp | 18 +- src/gui/input/HotkeySettings.cpp | 389 ++++++++++++++++++++ src/gui/input/HotkeySettings.h | 60 +++ src/input/api/Controller.cpp | 4 + src/resource/cemu.rc | 1 + src/resource/embedded/X_HOTKEY_SETTINGS.xpm | 70 ++++ src/resource/embedded/resources.cpp | 1 + src/resource/embedded/resources.h | 1 + src/resource/icons8_hotkeys.ico | Bin 0 -> 16958 bytes src/resource/icons8_hotkeys.png | Bin 0 -> 506 bytes 15 files changed, 619 insertions(+), 8 deletions(-) create mode 100644 src/gui/input/HotkeySettings.cpp create mode 100644 src/gui/input/HotkeySettings.h create mode 100644 src/resource/embedded/X_HOTKEY_SETTINGS.xpm create mode 100644 src/resource/icons8_hotkeys.ico create mode 100644 src/resource/icons8_hotkeys.png diff --git a/src/config/CemuConfig.cpp b/src/config/CemuConfig.cpp index 809a5470..47fc5876 100644 --- a/src/config/CemuConfig.cpp +++ b/src/config/CemuConfig.cpp @@ -354,6 +354,15 @@ void CemuConfig::Load(XMLConfigParser& parser) dsu_client.host = dsuc.get_attribute("host", dsu_client.host); dsu_client.port = dsuc.get_attribute("port", dsu_client.port); + // hotkeys + auto xml_hotkeys = parser.get("Hotkeys"); + hotkeys.modifiers = xml_hotkeys.get("modifiers", sHotkeyCfg{}); + hotkeys.exitFullscreen = xml_hotkeys.get("ExitFullscreen", sHotkeyCfg{uKeyboardHotkey{WXK_ESCAPE}}); + hotkeys.toggleFullscreen = xml_hotkeys.get("ToggleFullscreen", sHotkeyCfg{uKeyboardHotkey{WXK_F11}}); + hotkeys.toggleFullscreenAlt = xml_hotkeys.get("ToggleFullscreenAlt", sHotkeyCfg{uKeyboardHotkey{WXK_CONTROL_M, true}}); // ALT+ENTER + hotkeys.takeScreenshot = xml_hotkeys.get("TakeScreenshot", sHotkeyCfg{uKeyboardHotkey{WXK_F12}}); + hotkeys.toggleFastForward = xml_hotkeys.get("ToggleFastForward", sHotkeyCfg{}); + // emulatedusbdevices auto usbdevices = parser.get("EmulatedUsbDevices"); emulated_usb_devices.emulate_skylander_portal = usbdevices.get("EmulateSkylanderPortal", emulated_usb_devices.emulate_skylander_portal); @@ -557,6 +566,15 @@ void CemuConfig::Save(XMLConfigParser& parser) dsuc.set_attribute("host", dsu_client.host); dsuc.set_attribute("port", dsu_client.port); + // hotkeys + auto xml_hotkeys = config.set("Hotkeys"); + xml_hotkeys.set("modifiers", hotkeys.modifiers); + xml_hotkeys.set("ExitFullscreen", hotkeys.exitFullscreen); + xml_hotkeys.set("ToggleFullscreen", hotkeys.toggleFullscreen); + xml_hotkeys.set("ToggleFullscreenAlt", hotkeys.toggleFullscreenAlt); + xml_hotkeys.set("TakeScreenshot", hotkeys.takeScreenshot); + xml_hotkeys.set("ToggleFastForward", hotkeys.toggleFastForward); + // emulated usb devices auto usbdevices = config.set("EmulatedUsbDevices"); usbdevices.set("EmulateSkylanderPortal", emulated_usb_devices.emulate_skylander_portal.GetValue()); diff --git a/src/config/CemuConfig.h b/src/config/CemuConfig.h index ca896eed..353e4994 100644 --- a/src/config/CemuConfig.h +++ b/src/config/CemuConfig.h @@ -191,6 +191,50 @@ enum class CrashDump ENABLE_ENUM_ITERATORS(CrashDump, CrashDump::Disabled, CrashDump::Enabled); #endif +typedef union +{ + struct + { + uint16 key : 13; // enough bits for all keycodes + uint16 alt : 1; + uint16 ctrl : 1; + uint16 shift : 1; + }; + uint16 raw; +} uKeyboardHotkey; + +typedef sint16 ControllerHotkey_t; + +struct sHotkeyCfg +{ + static constexpr uint8 keyboardNone{WXK_NONE}; + static constexpr sint8 controllerNone{-1}; // no enums to work with, but buttons start from 0 + + uKeyboardHotkey keyboard{keyboardNone}; + ControllerHotkey_t controller{controllerNone}; + + /* for defaults */ + sHotkeyCfg(const uKeyboardHotkey& keyboard = {WXK_NONE}, const ControllerHotkey_t& controller = {-1}) : + keyboard(keyboard), controller(controller) {}; + + /* for reading from xml */ + sHotkeyCfg(const char* xml_values) + { + std::istringstream iss(xml_values); + iss >> keyboard.raw >> controller; + } +}; + +template <> +struct fmt::formatter : formatter +{ + template + auto format(const sHotkeyCfg c, FormatContext &ctx) const { + std::string xml_values = fmt::format("{} {}", c.keyboard.raw, c.controller); + return formatter::format(xml_values, ctx); + } +}; + template <> struct fmt::formatter : formatter { template @@ -499,6 +543,17 @@ struct CemuConfig ConfigValue port{ 26760 }; }dsu_client{}; + // hotkeys + struct + { + sHotkeyCfg modifiers; + sHotkeyCfg toggleFullscreen; + sHotkeyCfg toggleFullscreenAlt; + sHotkeyCfg exitFullscreen; + sHotkeyCfg takeScreenshot; + sHotkeyCfg toggleFastForward; + } hotkeys{}; + // debug ConfigValueBounds crash_dump{ CrashDump::Disabled }; ConfigValue gdb_port{ 1337 }; diff --git a/src/config/XMLConfig.h b/src/config/XMLConfig.h index 2a32dc56..dbec8a6e 100644 --- a/src/config/XMLConfig.h +++ b/src/config/XMLConfig.h @@ -7,6 +7,9 @@ #include #include +template +concept HasConstCharConstructor = requires { T(std::declval()); }; + class XMLConfigParser { public: @@ -43,7 +46,7 @@ public: return element->Int64Text(default_value); else if constexpr (std::is_same_v) // doesnt support real uint64... return (uint64)element->Int64Text((sint64)default_value); - else if constexpr (std::is_same_v || std::is_same_v) + else if constexpr (std::is_same_v || std::is_same_v || HasConstCharConstructor) { const char* text = element->GetText(); return text ? text : default_value; diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 7cdc208e..744ad544 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -71,6 +71,8 @@ add_library(CemuGui helpers/wxLogEvent.h helpers/wxWayland.cpp helpers/wxWayland.h + input/HotkeySettings.cpp + input/HotkeySettings.h input/InputAPIAddWindow.cpp input/InputAPIAddWindow.h input/InputSettings2.cpp diff --git a/src/gui/CemuApp.cpp b/src/gui/CemuApp.cpp index c3606292..37fdbe6d 100644 --- a/src/gui/CemuApp.cpp +++ b/src/gui/CemuApp.cpp @@ -11,6 +11,7 @@ #include "input/InputManager.h" #include "gui/helpers/wxHelpers.h" #include "Cemu/ncrypto/ncrypto.h" +#include "gui/input/HotkeySettings.h" #if BOOST_OS_LINUX && HAS_WAYLAND #include "gui/helpers/wxWayland.h" @@ -331,6 +332,8 @@ bool CemuApp::OnInit() std::unique_lock lock(g_mutex); g_window_info.app_active = true; + HotkeySettings::Init(m_mainFrame); + SetTopWindow(m_mainFrame); m_mainFrame->Show(); diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index bf880e48..3810656c 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -40,6 +40,7 @@ #include "gui/helpers/wxHelpers.h" #include "Cafe/HW/Latte/Renderer/Vulkan/VsyncDriver.h" #include "gui/input/InputSettings2.h" +#include "gui/input/HotkeySettings.h" #include "input/InputManager.h" #if BOOST_OS_WINDOWS @@ -91,6 +92,7 @@ enum MAINFRAME_MENU_ID_OPTIONS_GENERAL2, MAINFRAME_MENU_ID_OPTIONS_AUDIO, MAINFRAME_MENU_ID_OPTIONS_INPUT, + MAINFRAME_MENU_ID_OPTIONS_HOTKEY, MAINFRAME_MENU_ID_OPTIONS_MAC_SETTINGS, // options -> account MAINFRAME_MENU_ID_OPTIONS_ACCOUNT_1 = 20350, @@ -189,6 +191,7 @@ EVT_MENU(MAINFRAME_MENU_ID_OPTIONS_GENERAL, MainWindow::OnOptionsInput) EVT_MENU(MAINFRAME_MENU_ID_OPTIONS_GENERAL2, MainWindow::OnOptionsInput) EVT_MENU(MAINFRAME_MENU_ID_OPTIONS_AUDIO, MainWindow::OnOptionsInput) EVT_MENU(MAINFRAME_MENU_ID_OPTIONS_INPUT, MainWindow::OnOptionsInput) +EVT_MENU(MAINFRAME_MENU_ID_OPTIONS_HOTKEY, MainWindow::OnOptionsInput) EVT_MENU(MAINFRAME_MENU_ID_OPTIONS_MAC_SETTINGS, MainWindow::OnOptionsInput) // tools menu EVT_MENU(MAINFRAME_MENU_ID_TOOLS_MEMORY_SEARCHER, MainWindow::OnToolsInput) @@ -933,6 +936,12 @@ void MainWindow::OnOptionsInput(wxCommandEvent& event) break; } + case MAINFRAME_MENU_ID_OPTIONS_HOTKEY: + { + auto* frame = new HotkeySettings(this); + frame->Show(); + break; + } } } @@ -1446,13 +1455,7 @@ void MainWindow::OnKeyUp(wxKeyEvent& event) if (swkbd_hasKeyboardInputHook()) return; - const auto code = event.GetKeyCode(); - if (code == WXK_ESCAPE) - SetFullScreen(false); - else if (code == WXK_RETURN && event.AltDown() || code == WXK_F11) - SetFullScreen(!IsFullScreen()); - else if (code == WXK_F12) - g_window_info.has_screenshot_request = true; // async screenshot request + HotkeySettings::CaptureInput(event); } void MainWindow::OnKeyDown(wxKeyEvent& event) @@ -2189,6 +2192,7 @@ void MainWindow::RecreateMenu() #endif optionsMenu->Append(MAINFRAME_MENU_ID_OPTIONS_GENERAL2, _("&General settings")); optionsMenu->Append(MAINFRAME_MENU_ID_OPTIONS_INPUT, _("&Input settings")); + optionsMenu->Append(MAINFRAME_MENU_ID_OPTIONS_HOTKEY, _("&Hotkey settings")); optionsMenu->AppendSeparator(); optionsMenu->AppendSubMenu(m_optionsAccountMenu, _("&Active account")); diff --git a/src/gui/input/HotkeySettings.cpp b/src/gui/input/HotkeySettings.cpp new file mode 100644 index 00000000..2586b36d --- /dev/null +++ b/src/gui/input/HotkeySettings.cpp @@ -0,0 +1,389 @@ +#include "gui/input/HotkeySettings.h" +#include +#include +#include "input/InputManager.h" +#include "HotkeySettings.h" + +#if BOOST_OS_LINUX || BOOST_OS_MACOS +#include "resource/embedded/resources.h" +#endif + +extern WindowInfo g_window_info; +const std::unordered_map> HotkeySettings::s_cfgHotkeyToFuncMap{ + {&s_cfgHotkeys.toggleFullscreen, [](void) { s_mainWindow->ShowFullScreen(!s_mainWindow->IsFullScreen()); }}, + {&s_cfgHotkeys.toggleFullscreenAlt, [](void) { s_mainWindow->ShowFullScreen(!s_mainWindow->IsFullScreen()); }}, + {&s_cfgHotkeys.exitFullscreen, [](void) { s_mainWindow->ShowFullScreen(false); }}, + {&s_cfgHotkeys.takeScreenshot, [](void) { g_window_info.has_screenshot_request = true; }}, + {&s_cfgHotkeys.toggleFastForward, [](void) { ActiveSettings::SetTimerShiftFactor((ActiveSettings::GetTimerShiftFactor() < 3) ? 3 : 1); }}, +}; + +struct HotkeyEntry +{ + std::unique_ptr name; + std::unique_ptr keyInput; + std::unique_ptr controllerInput; + sHotkeyCfg& hotkey; + + HotkeyEntry(wxStaticText* name, wxButton* keyInput, wxButton* controllerInput, sHotkeyCfg& hotkey) + : name(name), keyInput(keyInput), controllerInput(controllerInput), hotkey(hotkey) + { + keyInput->SetClientData(&hotkey); + controllerInput->SetClientData(&hotkey); + } +}; + +HotkeySettings::HotkeySettings(wxWindow* parent) + : wxFrame(parent, wxID_ANY, _("Hotkey Settings")) +{ + SetIcon(wxICON(X_HOTKEY_SETTINGS)); + + m_sizer = new wxFlexGridSizer(0, 3, 5, 5); + m_sizer->AddGrowableCol(1); + m_sizer->AddGrowableCol(2); + + m_panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBORDER_SIMPLE); + m_panel->SetSizer(m_sizer); + m_panel->SetBackgroundColour(*wxWHITE); + + Center(); + + SetActiveController(); + + CreateColumnHeaders(); + + /* global modifier */ + CreateHotkeyRow("Hotkey modifier", s_cfgHotkeys.modifiers); + m_hotkeys.at(0).keyInput->Hide(); + + /* hotkeys */ + CreateHotkeyRow("Toggle fullscreen", s_cfgHotkeys.toggleFullscreen); + CreateHotkeyRow("Take screenshot", s_cfgHotkeys.takeScreenshot); + CreateHotkeyRow("Toggle fast-forward", s_cfgHotkeys.toggleFastForward); + + m_controllerTimer = new wxTimer(this); + Bind(wxEVT_TIMER, &HotkeySettings::OnControllerTimer, this); + + m_sizer->SetSizeHints(this); +} + +HotkeySettings::~HotkeySettings() +{ + m_controllerTimer->Stop(); + if (m_needToSave) + { + g_config.Save(); + } +} + +void HotkeySettings::Init(wxFrame* mainWindowFrame) +{ + s_keyboardHotkeyToFuncMap.reserve(s_cfgHotkeyToFuncMap.size()); + for (const auto& [cfgHotkey, func] : s_cfgHotkeyToFuncMap) + { + auto keyboardHotkey = cfgHotkey->keyboard.raw; + if (keyboardHotkey > sHotkeyCfg::keyboardNone) + { + s_keyboardHotkeyToFuncMap[keyboardHotkey] = func; + } + auto controllerHotkey = cfgHotkey->controller; + if (controllerHotkey > sHotkeyCfg::controllerNone) + { + s_controllerHotkeyToFuncMap[controllerHotkey] = func; + } + } + s_mainWindow = mainWindowFrame; +} + +void HotkeySettings::CreateColumnHeaders(void) +{ + auto* emptySpace = new wxStaticText(m_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL); + auto* keyboard = new wxStaticText(m_panel, wxID_ANY, "Keyboard", wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL); + auto* controller = new wxStaticText(m_panel, wxID_ANY, "Controller", wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL); + + keyboard->SetMinSize(m_minButtonSize); + controller->SetMinSize(m_minButtonSize); + + auto flags = wxSizerFlags().Expand(); + m_sizer->Add(emptySpace, flags); + m_sizer->Add(keyboard, flags); + m_sizer->Add(controller, flags); +} + +void HotkeySettings::CreateHotkeyRow(const wxString& label, sHotkeyCfg& cfgHotkey) +{ + auto* name = new wxStaticText(m_panel, wxID_ANY, label); + auto* keyInput = new wxButton(m_panel, wxID_ANY, To_wxString(cfgHotkey.keyboard), wxDefaultPosition, wxDefaultSize, wxWANTS_CHARS | wxBU_EXACTFIT); + auto* controllerInput = new wxButton(m_panel, wxID_ANY, To_wxString(cfgHotkey.controller), wxDefaultPosition, wxDefaultSize, wxWANTS_CHARS | wxBU_EXACTFIT); + + /* for starting input */ + keyInput->Bind(wxEVT_BUTTON, &HotkeySettings::OnKeyboardHotkeyInputLeftClick, this); + controllerInput->Bind(wxEVT_BUTTON, &HotkeySettings::OnControllerHotkeyInputLeftClick, this); + + /* for cancelling and clearing input */ + keyInput->Connect(wxEVT_RIGHT_UP, wxMouseEventHandler(HotkeySettings::OnKeyboardHotkeyInputRightClick), NULL, this); + controllerInput->Connect(wxEVT_RIGHT_UP, wxMouseEventHandler(HotkeySettings::OnControllerHotkeyInputRightClick), NULL, this); + + keyInput->SetMinSize(m_minButtonSize); + controllerInput->SetMinSize(m_minButtonSize); + +#if BOOST_OS_WINDOWS + const wxColour inputButtonColor = 0xfafafa; +#else + const wxColour inputButtonColor = GetBackgroundColour(); +#endif + keyInput->SetBackgroundColour(inputButtonColor); + controllerInput->SetBackgroundColour(inputButtonColor); + + auto flags = wxSizerFlags(1).Expand().Border(wxALL, 5).CenterVertical(); + m_sizer->Add(name, flags); + m_sizer->Add(keyInput, flags); + m_sizer->Add(controllerInput, flags); + + m_hotkeys.emplace_back(name, keyInput, controllerInput, cfgHotkey); +} + +void HotkeySettings::OnControllerTimer(wxTimerEvent& event) +{ + if (m_activeController.expired()) + { + m_controllerTimer->Stop(); + return; + } + auto& controller = *m_activeController.lock(); + auto buttons = controller.update_state().buttons; + if (!buttons.IsIdle()) + { + for (const auto& newHotkey : buttons.GetButtonList()) + { + m_controllerTimer->Stop(); + auto* inputButton = static_cast(m_controllerTimer->GetClientData()); + auto& cfgHotkey = *static_cast(inputButton->GetClientData()); + const auto oldHotkey = cfgHotkey.controller; + const bool isModifier = (&cfgHotkey == &s_cfgHotkeys.modifiers); + /* ignore same hotkeys and block duplicate hotkeys */ + if ((newHotkey != oldHotkey) && (isModifier || (newHotkey != s_cfgHotkeys.modifiers.controller)) && + (s_controllerHotkeyToFuncMap.find(newHotkey) == s_controllerHotkeyToFuncMap.end())) + { + m_needToSave |= true; + cfgHotkey.controller = newHotkey; + /* don't bind modifier to map */ + if (!isModifier) + { + s_controllerHotkeyToFuncMap.erase(oldHotkey); + s_controllerHotkeyToFuncMap[newHotkey] = s_cfgHotkeyToFuncMap.at(&cfgHotkey); + } + } + FinalizeInput(inputButton); + return; + } + } +} + +void HotkeySettings::OnKeyboardHotkeyInputLeftClick(wxCommandEvent& event) +{ + auto* inputButton = static_cast(event.GetEventObject()); + if (m_activeInputButton) + { + /* ignore multiple clicks of the same button */ + if (inputButton == m_activeInputButton) return; + RestoreInputButton(); + } + inputButton->Bind(wxEVT_KEY_UP, &HotkeySettings::OnKeyUp, this); + inputButton->SetLabelText(m_editModeHotkeyText); + m_activeInputButton = inputButton; +} + +void HotkeySettings::OnControllerHotkeyInputLeftClick(wxCommandEvent& event) +{ + auto* inputButton = static_cast(event.GetEventObject()); + if (m_activeInputButton) + { + /* ignore multiple clicks of the same button */ + if (inputButton == m_activeInputButton) return; + RestoreInputButton(); + } + m_controllerTimer->Stop(); + if (!SetActiveController()) + { + return; + } + inputButton->SetLabelText(m_editModeHotkeyText); + m_controllerTimer->SetClientData(inputButton); + m_controllerTimer->Start(25); + m_activeInputButton = inputButton; +} + +void HotkeySettings::OnKeyboardHotkeyInputRightClick(wxMouseEvent& event) +{ + if (m_activeInputButton) + { + RestoreInputButton(); + return; + } + auto* inputButton = static_cast(event.GetEventObject()); + auto& cfgHotkey = *static_cast(inputButton->GetClientData()); + uKeyboardHotkey newHotkey{ sHotkeyCfg::keyboardNone }; + if (cfgHotkey.keyboard.raw != newHotkey.raw) + { + m_needToSave |= true; + s_keyboardHotkeyToFuncMap.erase(cfgHotkey.keyboard.raw); + cfgHotkey.keyboard = newHotkey; + FinalizeInput(inputButton); + } +} + +void HotkeySettings::OnControllerHotkeyInputRightClick(wxMouseEvent& event) +{ + if (m_activeInputButton) + { + RestoreInputButton(); + return; + } + auto* inputButton = static_cast(event.GetEventObject()); + auto& cfgHotkey = *static_cast(inputButton->GetClientData()); + ControllerHotkey_t newHotkey{ sHotkeyCfg::controllerNone }; + if (cfgHotkey.controller != newHotkey) + { + m_needToSave |= true; + s_controllerHotkeyToFuncMap.erase(cfgHotkey.controller); + cfgHotkey.controller = newHotkey; + FinalizeInput(inputButton); + } +} + +bool HotkeySettings::SetActiveController(void) +{ + auto emulatedController = InputManager::instance().get_controller(0); + if (emulatedController.use_count() <= 1) + { + return false; + } + const auto& controllers = emulatedController->get_controllers(); + if (controllers.empty()) + { + return false; + } + m_activeController = controllers.at(0); + return true; +} + +void HotkeySettings::OnKeyUp(wxKeyEvent& event) +{ + auto* inputButton = static_cast(event.GetEventObject()); + auto& cfgHotkey = *static_cast(inputButton->GetClientData()); + if (auto keycode = event.GetKeyCode(); IsValidKeycodeUp(keycode)) + { + auto oldHotkey = cfgHotkey.keyboard; + uKeyboardHotkey newHotkey{}; + newHotkey.key = keycode; + newHotkey.alt = event.AltDown(); + newHotkey.ctrl = event.ControlDown(); + newHotkey.shift = event.ShiftDown(); + if ((newHotkey.raw != oldHotkey.raw) && + (s_keyboardHotkeyToFuncMap.find(newHotkey.raw) == s_keyboardHotkeyToFuncMap.end())) + { + m_needToSave |= true; + cfgHotkey.keyboard = newHotkey; + s_keyboardHotkeyToFuncMap.erase(oldHotkey.raw); + s_keyboardHotkeyToFuncMap[newHotkey.raw] = s_cfgHotkeyToFuncMap.at(&cfgHotkey); + } + } + FinalizeInput(inputButton); +} + +template +void HotkeySettings::FinalizeInput(wxButton* inputButton) +{ + auto& cfgHotkey = *static_cast(inputButton->GetClientData()); + if constexpr (std::is_same_v) + { + inputButton->Unbind(wxEVT_KEY_UP, &HotkeySettings::OnKeyUp, this); + inputButton->SetLabelText(To_wxString(cfgHotkey.keyboard)); + } else if constexpr (std::is_same_v) + { + inputButton->SetLabelText(To_wxString(cfgHotkey.controller)); + } + m_activeInputButton = nullptr; +} + +template +void HotkeySettings::RestoreInputButton(void) +{ + FinalizeInput(m_activeInputButton); +} + +bool HotkeySettings::IsValidKeycodeUp(int keycode) +{ + switch (keycode) + { + case WXK_NONE: + case WXK_ESCAPE: + case WXK_ALT: + case WXK_CONTROL: + case WXK_SHIFT: + return false; + default: + return true; + } +} + +wxString HotkeySettings::To_wxString(uKeyboardHotkey hotkey) +{ + if (hotkey.raw == sHotkeyCfg::keyboardNone) { + return m_disabledHotkeyText; + } + wxString ret{}; + if (hotkey.alt) + { + ret.append(_("Alt + ")); + } + if (hotkey.ctrl) + { + ret.append(_("Ctrl + ")); + } + if (hotkey.shift) + { + ret.append(_("Shift + ")); + } + ret.append(wxAcceleratorEntry(0, hotkey.key).ToString()); + return ret; +} + +wxString HotkeySettings::To_wxString(ControllerHotkey_t hotkey) +{ + if ((hotkey == sHotkeyCfg::controllerNone) || m_activeController.expired()) { + return m_disabledHotkeyText; + } + return m_activeController.lock()->get_button_name(hotkey); +} + +void HotkeySettings::CaptureInput(wxKeyEvent& event) +{ + uKeyboardHotkey hotkey{}; + hotkey.key = event.GetKeyCode(); + hotkey.alt = event.AltDown(); + hotkey.ctrl = event.ControlDown(); + hotkey.shift = event.ShiftDown(); + const auto it = s_keyboardHotkeyToFuncMap.find(hotkey.raw); + if (it != s_keyboardHotkeyToFuncMap.end()) + it->second(); +} + +void HotkeySettings::CaptureInput(const ControllerState& currentState, const ControllerState& lastState) +{ + const auto& modifier = s_cfgHotkeys.modifiers.controller; + if ((modifier >= 0) && currentState.buttons.GetButtonState(modifier)) + { + for (const auto& buttonId : currentState.buttons.GetButtonList()) + { + const auto it = s_controllerHotkeyToFuncMap.find(buttonId); + if (it == s_controllerHotkeyToFuncMap.end()) + continue; + /* only capture clicks */ + if (lastState.buttons.GetButtonState(buttonId)) + break; + it->second(); + break; + } + } +} diff --git a/src/gui/input/HotkeySettings.h b/src/gui/input/HotkeySettings.h new file mode 100644 index 00000000..77478ea9 --- /dev/null +++ b/src/gui/input/HotkeySettings.h @@ -0,0 +1,60 @@ +#pragma once + +#include +#include "config/CemuConfig.h" +#include "input/api/Controller.h" + +class HotkeyEntry; + +class HotkeySettings : public wxFrame +{ +public: + static void Init(wxFrame* mainWindowFrame); + + static void CaptureInput(wxKeyEvent& event); + static void CaptureInput(const ControllerState& currentState, const ControllerState& lastState); + + HotkeySettings(wxWindow* parent); + ~HotkeySettings(); + +private: + inline static wxFrame* s_mainWindow = nullptr; + static const std::unordered_map> s_cfgHotkeyToFuncMap; + inline static std::unordered_map> s_keyboardHotkeyToFuncMap{}; + inline static std::unordered_map> s_controllerHotkeyToFuncMap{}; + inline static auto& s_cfgHotkeys = GetConfig().hotkeys; + + wxPanel* m_panel; + wxFlexGridSizer* m_sizer; + wxButton* m_activeInputButton{ nullptr }; + wxTimer* m_controllerTimer{ nullptr }; + const wxSize m_minButtonSize{ 250, 45 }; + const wxString m_disabledHotkeyText{ _("----") }; + const wxString m_editModeHotkeyText{ _("") }; + + std::vector m_hotkeys; + std::weak_ptr m_activeController{}; + bool m_needToSave = false; + + /* helpers */ + void CreateColumnHeaders(void); + void CreateHotkeyRow(const wxString& label, sHotkeyCfg& cfgHotkey); + wxString To_wxString(uKeyboardHotkey hotkey); + wxString To_wxString(ControllerHotkey_t hotkey); + bool IsValidKeycodeUp(int keycode); + bool SetActiveController(void); + + template + void FinalizeInput(wxButton* inputButton); + + template + void RestoreInputButton(void); + + /* events */ + void OnKeyboardHotkeyInputLeftClick(wxCommandEvent& event); + void OnControllerHotkeyInputLeftClick(wxCommandEvent& event); + void OnKeyboardHotkeyInputRightClick(wxMouseEvent& event); + void OnControllerHotkeyInputRightClick(wxMouseEvent& event); + void OnKeyUp(wxKeyEvent& event); + void OnControllerTimer(wxTimerEvent& event); +}; diff --git a/src/input/api/Controller.cpp b/src/input/api/Controller.cpp index b7831def..07465220 100644 --- a/src/input/api/Controller.cpp +++ b/src/input/api/Controller.cpp @@ -1,4 +1,6 @@ #include "input/api/Controller.h" +#include "config/CemuConfig.h" +#include "gui/input/HotkeySettings.h" #include "gui/guiWrapper.h" @@ -67,6 +69,8 @@ const ControllerState& ControllerBase::update_state() #undef APPLY_AXIS_BUTTON + HotkeySettings::CaptureInput(result, m_last_state); + m_last_state = std::move(result); return m_last_state; } diff --git a/src/resource/cemu.rc b/src/resource/cemu.rc index 6f78bfc3..fb397056 100644 --- a/src/resource/cemu.rc +++ b/src/resource/cemu.rc @@ -37,6 +37,7 @@ X_SETTINGS ICON "resource\\icons8_automatic_26_x X_GAME_PROFILE ICON "resource\\icons8-compose-filled-50.ico" +X_HOTKEY_SETTINGS ICON "resource\\icons8_hotkeys.ico" #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// diff --git a/src/resource/embedded/X_HOTKEY_SETTINGS.xpm b/src/resource/embedded/X_HOTKEY_SETTINGS.xpm new file mode 100644 index 00000000..473dac09 --- /dev/null +++ b/src/resource/embedded/X_HOTKEY_SETTINGS.xpm @@ -0,0 +1,70 @@ +/* XPM */ +const char *X_HOTKEY_SETTINGS_xpm[] = { +"64 64 2 1", +" c None", +". c #000000", +" ... ", +" .... ", +" .... ", +" .. .... ", +" .. ...... ", +" ... ...... ", +" ... ...... ", +" ... ....... ", +" .... ........ ... ", +" .... ......... ... ", +" .... ......... ... ", +" .... .......... .... ", +" .... ......... .... ", +" ..... ........... ..... ", +" ..... .......... ..... ", +" ........ ........... ...... ", +" ........ ... ....... ...... ", +" ........... ... ....... ...... ", +" ........... ..... ...... ....... ", +" ........... ..... ...... ........ ", +" ............. ...... ...... ......... ", +" ........ .... ...... .... ..... .... ", +" ........ .... ....... .... ...... .... ", +" ...... .... ...... ..... ....... ..... ", +" ...... ........... ............ .... ", +" ...... .......... .......... .... ", +" ..... .......... .......... .... ", +" ..... .......... ......... ..... ", +" ..... .......... ........ ..... ", +" ..... ........ ........ ...... ", +" ..... ..... ..... ..... ", +" ..... ..... .... ...... ", +" ..... ..... ", +" ... .... ", +" . ............................ .. ", +" ................................ ", +" ................................ ", +" .................................... ", +" .................................... ", +" .......... ........ .......... ", +" .......... ........ .......... ", +" .......... ........ .......... ", +" .......... ........ .......... ", +" .......... ........ .......... ", +" .......... ........ .......... ", +" .......... ........ .......... ", +" .......... .......... ", +" .......... .......... ", +" .......... .......... ", +" .......... ........ .......... ", +" .......... ........ .......... ", +" .......... ........ .......... ", +" .......... ........ .......... ", +" .......... ........ .......... ", +" .......... ........ .......... ", +" .......... ........ .......... ", +" .......... ........ .......... ", +" .................................... ", +" .................................... ", +" .................................... ", +" .................................... ", +" ................................ ", +" ................................ ", +" ............................. " +}; diff --git a/src/resource/embedded/resources.cpp b/src/resource/embedded/resources.cpp index 5dbb9d14..2b508c10 100644 --- a/src/resource/embedded/resources.cpp +++ b/src/resource/embedded/resources.cpp @@ -2,6 +2,7 @@ #include "M_WND_ICON128.xpm" #include "X_BOX.xpm" #include "X_SETTINGS.xpm" +#include "X_HOTKEY_SETTINGS.xpm" #include "icons8-checkmark-yes-32.hpng" #include "icons8-error-32.hpng" diff --git a/src/resource/embedded/resources.h b/src/resource/embedded/resources.h index 8cb9fe5d..26e9b759 100644 --- a/src/resource/embedded/resources.h +++ b/src/resource/embedded/resources.h @@ -2,6 +2,7 @@ extern const char* X_GAME_PROFILE_xpm[]; extern const char* M_WND_ICON128_xpm[]; extern const char* X_BOX_xpm[]; extern const char* X_SETTINGS_xpm[]; +extern const char* X_HOTKEY_SETTINGS_xpm[]; extern unsigned char PNG_CHECK_YES_png[573]; extern unsigned char PNG_ERROR_png[472]; diff --git a/src/resource/icons8_hotkeys.ico b/src/resource/icons8_hotkeys.ico new file mode 100644 index 0000000000000000000000000000000000000000..68f34ac4604a10bf746b47a8f30f392edcdd4ff7 GIT binary patch literal 16958 zcmeHPJB|}U5FN{bLlY4)gnJ9GI1wjcjR*)i0#~s_z%^z?KstzI0^^~p?HUzttK8k* z?q+RGBm33oRn@C;+a!plS-3y<_ll0tfF=QFMr z)hc#BY!<4U_~S^_=)Y5^x=Kc956+_;j$1hK=l$ss&7XhdGnnp8CBwSE7)LpnM}Oka z_n#ikeE%b#!E|pb8F+6kALUp)j!*m>z5mmGA!FX3uEfoK|3e@9l)ur>pTFl8&ikL9 z!2J2&9PM&@%YpzZ@hiOCOw9W2Uv!|Im^$Gli?|i1o<9 zJp0JY>GKSUR)5K1+u~xJ`4W*szRa_&@p8ntzeKCANU-su1Bjwmelyw%* zigPb3kG*sFJkvr=ix!jhQkRUAEf40{Cl1?;vM#61{VhDF^EEzmv>e6oSUip+Kex|wVi0F*HO$d+6w{8ywfI_( zOJnC|W6qi(dBl-E+FB3fu&;4T#CV>Cp_#IdxY9>k>xCTlHExL*&$BQz)2h?rS}%=9 zv6@HI5IbM1)nZn^6t30dx$#RiXmwW1(x~w*ZmBqGh@FFVnjh+gH6eb9{3RN&#_~gY zu`a|fl~2`ye9e#1D(hnSr8rUt*`b4c%}?nO;?~IH4(Dbf7yWa!l#~1rw`M*?m*k>d zQ*+K)a*t47$(44f?xp8bc9C3Zzw{kL`goUE9`hMPb=Qzj*@d}`*RWr1jl4T!?*7-% zk9TLh2F=gb$p3DI(KY1#39FoO+`0cCz$x$(1@3A5W*lwo*T?*&=tlbfh?n;JS1<1K z$L+cNI*tSFxE{y;VH^*HAJ&IAE06ouVYgontEI!<;U|wh#6Ue+x0ZZ;ox!D4z1I%ny?{%-wummL)ag2)31gH=WjZXhqhaj mcEVo{$932KApFv|1P(VIzYnd)pC|l%IQo8TpKU{4w4Sx>KPX(0ZB-#6pC`vv;D!>Ygf)F`CVz|{wc%NWZ z06L5RN6>YAh+;B@z$l<3SP1Z{;ZmneBt$D9OY40iYah^}k}D$zq*8&FfIG&eE2o{u z`s|4eRe-7p4FMxeqm|%>Xa(F6!z!UuHbPKkNeQqtDN!LIng^`_iTLx$z z2NeSRnp^A-V)fWNKlQk3Q>)yaM-aezIoqC}%9mMNVHmv2U{Un#=kuS~?yk Date: Mon, 7 Jul 2025 20:47:40 -0700 Subject: [PATCH 09/31] build: Build assembly in ih264d with cpp preprocessor (#1631) --- dependencies/ih264d/CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dependencies/ih264d/CMakeLists.txt b/dependencies/ih264d/CMakeLists.txt index 64ac0931..a8ef3776 100644 --- a/dependencies/ih264d/CMakeLists.txt +++ b/dependencies/ih264d/CMakeLists.txt @@ -182,7 +182,10 @@ target_sources(ih264d PRIVATE "decoder/arm/ih264d_function_selector_av8.c" "decoder/arm/ih264d_function_selector.c" ) -target_compile_options(ih264d PRIVATE -DARMV8) +target_compile_options(ih264d PRIVATE -DARMV8 $<$:-Wno-unused-command-line-argument>) +if(NOT MSVC) + set(CMAKE_ASM_FLAGS "${CFLAGS} -x assembler-with-cpp") +endif() if(APPLE) target_sources(ih264d PRIVATE "common/armv8/macos_arm_symbol_aliases.s") endif() From 5f3c2816ec6664b5ad147c26dcced06dda422fd5 Mon Sep 17 00:00:00 2001 From: Exzap <13877693+Exzap@users.noreply.github.com> Date: Tue, 8 Jul 2025 19:01:20 +0200 Subject: [PATCH 10/31] AX: Fix voice dropping --- src/Cafe/OS/libs/snd_core/ax_voice.cpp | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/Cafe/OS/libs/snd_core/ax_voice.cpp b/src/Cafe/OS/libs/snd_core/ax_voice.cpp index 877eecab..2b942739 100644 --- a/src/Cafe/OS/libs/snd_core/ax_voice.cpp +++ b/src/Cafe/OS/libs/snd_core/ax_voice.cpp @@ -401,26 +401,22 @@ namespace snd_core if (vpb != nullptr) { AXVoiceList_AddVoice(vpb, priority); - vpb->userParam = userParam; - vpb->callback = MPTR_NULL; - vpb->callbackEx = callbackEx; - AXVPB_SetVoiceDefault(vpb); } else { - // no free voice available, drop voice with lower priority - AXVPB* droppedVoice = AXVPB_DropVoice(priority); - if (droppedVoice == nullptr) + // no free voice available, try to drop a voice with lower priority + vpb = AXVPB_DropVoice(priority); + if (!vpb) { // no voice available __AXVoiceListSpinlock.unlock(); return nullptr; } - vpb->userParam = userParam; - vpb->callback = MPTR_NULL; - vpb->callbackEx = callbackEx; - AXVPB_SetVoiceDefault(vpb); } + vpb->userParam = userParam; + vpb->callback = MPTR_NULL; + vpb->callbackEx = callbackEx; + AXVPB_SetVoiceDefault(vpb); __AXVoiceListSpinlock.unlock(); return vpb; } From 67de63bed6c54ee158380f683a65874fc0a993ff Mon Sep 17 00:00:00 2001 From: SSimco <37044560+SSimco@users.noreply.github.com> Date: Tue, 15 Jul 2025 05:28:41 +0300 Subject: [PATCH 11/31] UI+build: Isolate wxWidgets code from non-GUI code (#1633) --- .github/workflows/generate_pot.yml | 1 + src/CMakeLists.txt | 4 - src/Cafe/CMakeLists.txt | 4 - src/Cafe/CafeSystem.cpp | 11 +- src/Cafe/Filesystem/FST/KeyCache.cpp | 10 +- src/Cafe/GraphicPack/GraphicPack2.cpp | 2 +- src/Cafe/GraphicPack/GraphicPack2Patches.cpp | 15 +- src/Cafe/HW/Espresso/Debugger/Debugger.cpp | 29 +- src/Cafe/HW/Espresso/Debugger/Debugger.h | 63 ++++ src/Cafe/HW/Latte/Core/LatteOverlay.cpp | 10 +- .../HW/Latte/Core/LattePerformanceMonitor.cpp | 6 +- src/Cafe/HW/Latte/Core/LatteRenderTarget.cpp | 12 +- src/Cafe/HW/Latte/Core/LatteShaderCache.cpp | 37 +- src/Cafe/HW/Latte/Core/LatteThread.cpp | 7 +- .../Latte/Renderer/OpenGL/OpenGLRenderer.cpp | 42 ++- .../HW/Latte/Renderer/OpenGL/OpenGLRenderer.h | 22 ++ src/Cafe/HW/Latte/Renderer/Renderer.cpp | 133 ++----- src/Cafe/HW/Latte/Renderer/Renderer.h | 9 +- .../Latte/Renderer/Vulkan/SwapchainInfoVk.cpp | 4 +- .../HW/Latte/Renderer/Vulkan/VsyncDriver.cpp | 10 +- .../Latte/Renderer/Vulkan/VulkanRenderer.cpp | 50 ++- .../HW/Latte/Renderer/Vulkan/VulkanRenderer.h | 7 +- src/Cafe/HW/MMU/MMU.cpp | 9 +- src/Cafe/IOSU/legacy/iosu_act.cpp | 1 - src/Cafe/OS/RPL/rpl.cpp | 6 +- src/Cafe/OS/libs/erreula/erreula.cpp | 2 - src/Cafe/OS/libs/nn_save/nn_save.cpp | 75 ---- src/Cafe/OS/libs/padscore/padscore.cpp | 4 +- src/Cafe/OS/libs/vpad/vpad.cpp | 4 +- src/Cemu/Logging/CemuLogging.cpp | 64 +++- src/Cemu/Logging/CemuLogging.h | 11 + .../Tools/DownloadManager/DownloadManager.cpp | 38 +- src/Common/precompiled.h | 41 ++ src/audio/CMakeLists.txt | 13 +- src/audio/DirectSoundAPI.cpp | 4 +- src/config/ActiveSettings.cpp | 8 - src/config/ActiveSettings.h | 1 - src/config/CMakeLists.txt | 7 +- src/config/CemuConfig.cpp | 185 +--------- src/config/CemuConfig.h | 149 ++------ src/config/LaunchSettings.cpp | 5 - src/config/NetworkSettings.h | 2 +- src/config/XMLConfig.h | 171 +++++++-- src/gui/CMakeLists.txt | 189 +--------- src/gui/LoggingWindow.h | 44 --- src/gui/canvas/OpenGLCanvas.h | 8 - src/gui/guiWrapper.cpp | 332 ----------------- src/gui/guiWrapper.h | 161 -------- src/gui/helpers/wxHelpers.cpp | 66 ---- src/gui/interface/WindowSystem.h | 126 +++++++ .../wxgui/AudioDebuggerWindow.cpp} | 4 +- .../wxgui/AudioDebuggerWindow.h} | 0 src/gui/wxgui/CMakeLists.txt | 189 ++++++++++ src/gui/{ => wxgui}/CemuApp.cpp | 50 ++- src/gui/{ => wxgui}/CemuApp.h | 0 src/gui/{ => wxgui}/CemuUpdateWindow.cpp | 5 +- src/gui/{ => wxgui}/CemuUpdateWindow.h | 0 src/gui/{ => wxgui}/ChecksumTool.cpp | 8 +- src/gui/{ => wxgui}/ChecksumTool.h | 2 +- .../DownloadGraphicPacksWindow.cpp | 4 +- .../{ => wxgui}/DownloadGraphicPacksWindow.h | 0 .../EmulatedUSBDeviceFrame.cpp | 10 +- .../EmulatedUSBDeviceFrame.h | 0 src/gui/{ => wxgui}/GameProfileWindow.cpp | 4 +- src/gui/{ => wxgui}/GameProfileWindow.h | 0 src/gui/{ => wxgui}/GameUpdateWindow.cpp | 8 +- src/gui/{ => wxgui}/GameUpdateWindow.h | 0 src/gui/{ => wxgui}/GeneralSettings2.cpp | 65 ++-- src/gui/{ => wxgui}/GeneralSettings2.h | 0 src/gui/{ => wxgui}/GettingStartedDialog.cpp | 22 +- src/gui/{ => wxgui}/GettingStartedDialog.h | 0 src/gui/{ => wxgui}/GraphicPacksWindow2.cpp | 10 +- src/gui/{ => wxgui}/GraphicPacksWindow2.h | 0 src/gui/{ => wxgui}/LoggingWindow.cpp | 28 +- src/gui/wxgui/LoggingWindow.h | 29 ++ src/gui/{ => wxgui}/MainWindow.cpp | 142 +++---- src/gui/{ => wxgui}/MainWindow.h | 9 +- src/gui/{ => wxgui}/MemorySearcherTool.cpp | 6 +- src/gui/{ => wxgui}/MemorySearcherTool.h | 2 +- src/gui/{ => wxgui}/PadViewFrame.cpp | 18 +- src/gui/{ => wxgui}/PadViewFrame.h | 0 src/gui/{ => wxgui}/TitleManager.cpp | 22 +- src/gui/{ => wxgui}/TitleManager.h | 0 src/gui/{ => wxgui}/canvas/IRenderCanvas.h | 0 src/gui/{ => wxgui}/canvas/OpenGLCanvas.cpp | 120 ++++-- src/gui/wxgui/canvas/OpenGLCanvas.h | 4 + src/gui/{ => wxgui}/canvas/VulkanCanvas.cpp | 11 +- src/gui/{ => wxgui}/canvas/VulkanCanvas.h | 2 +- src/gui/{ => wxgui}/components/TextList.cpp | 2 +- src/gui/{ => wxgui}/components/TextList.h | 0 .../components/wxDownloadManagerList.cpp | 12 +- .../components/wxDownloadManagerList.h | 2 +- src/gui/{ => wxgui}/components/wxGameList.cpp | 37 +- src/gui/{ => wxgui}/components/wxGameList.h | 0 .../{ => wxgui}/components/wxInputDraw.cpp | 2 +- src/gui/{ => wxgui}/components/wxInputDraw.h | 0 src/gui/{ => wxgui}/components/wxLogCtrl.cpp | 2 +- src/gui/{ => wxgui}/components/wxLogCtrl.h | 0 .../components/wxProgressDialogManager.h | 0 .../components/wxTitleManagerList.cpp | 14 +- .../components/wxTitleManagerList.h | 2 +- .../{ => wxgui}/debugger/BreakpointWindow.cpp | 9 +- .../{ => wxgui}/debugger/BreakpointWindow.h | 2 +- .../{ => wxgui}/debugger/DebuggerWindow2.cpp | 60 ++- .../{ => wxgui}/debugger/DebuggerWindow2.h | 15 +- src/gui/{ => wxgui}/debugger/DisasmCtrl.cpp | 7 +- src/gui/{ => wxgui}/debugger/DisasmCtrl.h | 2 +- src/gui/{ => wxgui}/debugger/DumpCtrl.cpp | 4 +- src/gui/{ => wxgui}/debugger/DumpCtrl.h | 2 +- src/gui/{ => wxgui}/debugger/DumpWindow.cpp | 8 +- src/gui/{ => wxgui}/debugger/DumpWindow.h | 2 +- src/gui/{ => wxgui}/debugger/ModuleWindow.cpp | 9 +- src/gui/{ => wxgui}/debugger/ModuleWindow.h | 0 src/gui/{ => wxgui}/debugger/RegisterCtrl.cpp | 6 +- src/gui/{ => wxgui}/debugger/RegisterCtrl.h | 2 +- .../{ => wxgui}/debugger/RegisterWindow.cpp | 6 +- src/gui/{ => wxgui}/debugger/RegisterWindow.h | 0 src/gui/{ => wxgui}/debugger/SymbolCtrl.cpp | 5 +- src/gui/{ => wxgui}/debugger/SymbolCtrl.h | 0 src/gui/{ => wxgui}/debugger/SymbolWindow.cpp | 7 +- src/gui/{ => wxgui}/debugger/SymbolWindow.h | 2 +- .../CreateAccount/wxCreateAccountDialog.cpp | 2 +- .../CreateAccount/wxCreateAccountDialog.h | 0 .../dialogs/SaveImport/SaveImportWindow.cpp | 2 +- .../dialogs/SaveImport/SaveImportWindow.h | 0 .../dialogs/SaveImport/SaveTransfer.cpp | 2 +- .../dialogs/SaveImport/SaveTransfer.h | 0 src/gui/{ => wxgui}/helpers/wxControlObject.h | 0 src/gui/{ => wxgui}/helpers/wxCustomData.h | 0 .../{ => wxgui}/helpers/wxCustomEvents.cpp | 2 +- src/gui/{ => wxgui}/helpers/wxCustomEvents.h | 0 src/gui/wxgui/helpers/wxHelpers.cpp | 116 ++++++ src/gui/{ => wxgui}/helpers/wxHelpers.h | 3 + src/gui/{ => wxgui}/helpers/wxLogEvent.h | 0 src/gui/{ => wxgui}/helpers/wxWayland.cpp | 2 +- src/gui/{ => wxgui}/helpers/wxWayland.h | 0 src/gui/{ => wxgui}/input/HotkeySettings.cpp | 113 +++++- src/gui/{ => wxgui}/input/HotkeySettings.h | 6 +- .../{ => wxgui}/input/InputAPIAddWindow.cpp | 6 +- src/gui/{ => wxgui}/input/InputAPIAddWindow.h | 2 +- src/gui/{ => wxgui}/input/InputSettings2.cpp | 24 +- src/gui/{ => wxgui}/input/InputSettings2.h | 0 src/gui/{ => wxgui}/input/PairingDialog.cpp | 2 +- src/gui/{ => wxgui}/input/PairingDialog.h | 0 .../panels/ClassicControllerInputPanel.cpp | 8 +- .../panels/ClassicControllerInputPanel.h | 2 +- .../{ => wxgui}/input/panels/InputPanel.cpp | 7 +- src/gui/{ => wxgui}/input/panels/InputPanel.h | 2 +- .../input/panels/ProControllerInputPanel.cpp | 6 +- .../input/panels/ProControllerInputPanel.h | 4 +- .../input/panels/VPADInputPanel.cpp | 8 +- .../{ => wxgui}/input/panels/VPADInputPanel.h | 2 +- .../input/panels/WiimoteInputPanel.cpp | 8 +- .../input/panels/WiimoteInputPanel.h | 2 +- .../settings/DefaultControllerSettings.cpp | 10 +- .../settings/DefaultControllerSettings.h | 0 .../settings/WiimoteControllerSettings.cpp | 10 +- .../settings/WiimoteControllerSettings.h | 0 .../DebugPPCThreadsWindow.cpp | 4 +- .../PPCThreadsViewer/DebugPPCThreadsWindow.h | 0 .../TextureRelationWindow.cpp | 2 +- .../TextureRelationWindow.h | 0 src/gui/wxgui/wxCemuConfig.cpp | 184 +++++++++ src/gui/wxgui/wxCemuConfig.h | 142 +++++++ src/gui/{ => wxgui}/wxHelper.h | 0 src/gui/wxgui/wxWindowSystem.cpp | 349 ++++++++++++++++++ src/gui/{ => wxgui}/wxcomponents/checked.xpm | 0 src/gui/{ => wxgui}/wxcomponents/checked2.xpm | 0 .../{ => wxgui}/wxcomponents/checked_d.xpm | 0 .../{ => wxgui}/wxcomponents/checked_dis.xpm | 0 .../{ => wxgui}/wxcomponents/checked_ld.xpm | 0 .../{ => wxgui}/wxcomponents/checked_mo.xpm | 0 .../wxcomponents/checkedlistctrl.cpp | 10 +- .../wxcomponents/checkedlistctrl.h | 0 .../{ => wxgui}/wxcomponents/checktree.cpp | 18 +- src/gui/{ => wxgui}/wxcomponents/checktree.h | 0 .../{ => wxgui}/wxcomponents/unchecked.xpm | 0 .../{ => wxgui}/wxcomponents/unchecked2.xpm | 0 .../{ => wxgui}/wxcomponents/unchecked_d.xpm | 0 .../wxcomponents/unchecked_dis.xpm | 0 .../{ => wxgui}/wxcomponents/unchecked_ld.xpm | 0 .../{ => wxgui}/wxcomponents/unchecked_mo.xpm | 0 src/gui/{ => wxgui}/wxgui.h | 0 src/imgui/imgui_extension.cpp | 8 +- src/input/CMakeLists.txt | 4 - src/input/api/Controller.cpp | 6 +- .../api/DirectInput/DirectInputController.cpp | 4 +- src/input/api/Keyboard/KeyboardController.cpp | 39 +- src/input/emulated/ClassicController.cpp | 28 +- src/input/emulated/ProController.cpp | 32 +- src/input/emulated/VPADController.cpp | 37 +- src/input/emulated/WPADController.h | 2 - src/input/emulated/WiimoteController.cpp | 19 +- src/main.cpp | 14 +- src/mainLLE.cpp | 6 +- src/util/CMakeLists.txt | 4 - src/util/helpers/helpers.cpp | 29 +- src/util/helpers/helpers.h | 2 - src/util/math/quaternion.h | 2 +- 199 files changed, 2414 insertions(+), 2091 deletions(-) delete mode 100644 src/gui/LoggingWindow.h delete mode 100644 src/gui/canvas/OpenGLCanvas.h delete mode 100644 src/gui/guiWrapper.cpp delete mode 100644 src/gui/guiWrapper.h delete mode 100644 src/gui/helpers/wxHelpers.cpp create mode 100644 src/gui/interface/WindowSystem.h rename src/{audio/audioDebuggerWindow.cpp => gui/wxgui/AudioDebuggerWindow.cpp} (99%) rename src/{audio/audioDebuggerWindow.h => gui/wxgui/AudioDebuggerWindow.h} (100%) create mode 100644 src/gui/wxgui/CMakeLists.txt rename src/gui/{ => wxgui}/CemuApp.cpp (94%) rename src/gui/{ => wxgui}/CemuApp.h (100%) rename src/gui/{ => wxgui}/CemuUpdateWindow.cpp (99%) rename src/gui/{ => wxgui}/CemuUpdateWindow.h (100%) rename src/gui/{ => wxgui}/ChecksumTool.cpp (99%) rename src/gui/{ => wxgui}/ChecksumTool.h (96%) rename src/gui/{ => wxgui}/DownloadGraphicPacksWindow.cpp (99%) rename src/gui/{ => wxgui}/DownloadGraphicPacksWindow.h (100%) rename src/gui/{ => wxgui}/EmulatedUSBDevices/EmulatedUSBDeviceFrame.cpp (99%) rename src/gui/{ => wxgui}/EmulatedUSBDevices/EmulatedUSBDeviceFrame.h (100%) rename src/gui/{ => wxgui}/GameProfileWindow.cpp (99%) rename src/gui/{ => wxgui}/GameProfileWindow.h (100%) rename src/gui/{ => wxgui}/GameUpdateWindow.cpp (98%) rename src/gui/{ => wxgui}/GameUpdateWindow.h (100%) rename src/gui/{ => wxgui}/GeneralSettings2.cpp (97%) rename src/gui/{ => wxgui}/GeneralSettings2.h (100%) rename src/gui/{ => wxgui}/GettingStartedDialog.cpp (95%) rename src/gui/{ => wxgui}/GettingStartedDialog.h (100%) rename src/gui/{ => wxgui}/GraphicPacksWindow2.cpp (99%) rename src/gui/{ => wxgui}/GraphicPacksWindow2.h (100%) rename src/gui/{ => wxgui}/LoggingWindow.cpp (85%) create mode 100644 src/gui/wxgui/LoggingWindow.h rename src/gui/{ => wxgui}/MainWindow.cpp (96%) rename src/gui/{ => wxgui}/MainWindow.h (97%) rename src/gui/{ => wxgui}/MemorySearcherTool.cpp (99%) rename src/gui/{ => wxgui}/MemorySearcherTool.h (99%) rename src/gui/{ => wxgui}/PadViewFrame.cpp (94%) rename src/gui/{ => wxgui}/PadViewFrame.h (100%) rename src/gui/{ => wxgui}/TitleManager.cpp (98%) rename src/gui/{ => wxgui}/TitleManager.h (100%) rename src/gui/{ => wxgui}/canvas/IRenderCanvas.h (100%) rename src/gui/{ => wxgui}/canvas/OpenGLCanvas.cpp (55%) create mode 100644 src/gui/wxgui/canvas/OpenGLCanvas.h rename src/gui/{ => wxgui}/canvas/VulkanCanvas.cpp (85%) rename src/gui/{ => wxgui}/canvas/VulkanCanvas.h (91%) rename src/gui/{ => wxgui}/components/TextList.cpp (99%) rename src/gui/{ => wxgui}/components/TextList.h (100%) rename src/gui/{ => wxgui}/components/wxDownloadManagerList.cpp (98%) rename src/gui/{ => wxgui}/components/wxDownloadManagerList.h (99%) rename src/gui/{ => wxgui}/components/wxGameList.cpp (98%) rename src/gui/{ => wxgui}/components/wxGameList.h (100%) rename src/gui/{ => wxgui}/components/wxInputDraw.cpp (98%) rename src/gui/{ => wxgui}/components/wxInputDraw.h (100%) rename src/gui/{ => wxgui}/components/wxLogCtrl.cpp (98%) rename src/gui/{ => wxgui}/components/wxLogCtrl.h (100%) rename src/gui/{ => wxgui}/components/wxProgressDialogManager.h (100%) rename src/gui/{ => wxgui}/components/wxTitleManagerList.cpp (99%) rename src/gui/{ => wxgui}/components/wxTitleManagerList.h (98%) rename src/gui/{ => wxgui}/debugger/BreakpointWindow.cpp (98%) rename src/gui/{ => wxgui}/debugger/BreakpointWindow.h (92%) rename src/gui/{ => wxgui}/debugger/DebuggerWindow2.cpp (94%) rename src/gui/{ => wxgui}/debugger/DebuggerWindow2.h (86%) rename src/gui/{ => wxgui}/debugger/DisasmCtrl.cpp (99%) rename src/gui/{ => wxgui}/debugger/DisasmCtrl.h (98%) rename src/gui/{ => wxgui}/debugger/DumpCtrl.cpp (99%) rename src/gui/{ => wxgui}/debugger/DumpCtrl.h (95%) rename src/gui/{ => wxgui}/debugger/DumpWindow.cpp (89%) rename src/gui/{ => wxgui}/debugger/DumpWindow.h (90%) rename src/gui/{ => wxgui}/debugger/ModuleWindow.cpp (95%) rename src/gui/{ => wxgui}/debugger/ModuleWindow.h (100%) rename src/gui/{ => wxgui}/debugger/RegisterCtrl.cpp (98%) rename src/gui/{ => wxgui}/debugger/RegisterCtrl.h (93%) rename src/gui/{ => wxgui}/debugger/RegisterWindow.cpp (99%) rename src/gui/{ => wxgui}/debugger/RegisterWindow.h (100%) rename src/gui/{ => wxgui}/debugger/SymbolCtrl.cpp (97%) rename src/gui/{ => wxgui}/debugger/SymbolCtrl.h (100%) rename src/gui/{ => wxgui}/debugger/SymbolWindow.cpp (91%) rename src/gui/{ => wxgui}/debugger/SymbolWindow.h (91%) rename src/gui/{ => wxgui}/dialogs/CreateAccount/wxCreateAccountDialog.cpp (98%) rename src/gui/{ => wxgui}/dialogs/CreateAccount/wxCreateAccountDialog.h (100%) rename src/gui/{ => wxgui}/dialogs/SaveImport/SaveImportWindow.cpp (99%) rename src/gui/{ => wxgui}/dialogs/SaveImport/SaveImportWindow.h (100%) rename src/gui/{ => wxgui}/dialogs/SaveImport/SaveTransfer.cpp (99%) rename src/gui/{ => wxgui}/dialogs/SaveImport/SaveTransfer.h (100%) rename src/gui/{ => wxgui}/helpers/wxControlObject.h (100%) rename src/gui/{ => wxgui}/helpers/wxCustomData.h (100%) rename src/gui/{ => wxgui}/helpers/wxCustomEvents.cpp (86%) rename src/gui/{ => wxgui}/helpers/wxCustomEvents.h (100%) create mode 100644 src/gui/wxgui/helpers/wxHelpers.cpp rename src/gui/{ => wxgui}/helpers/wxHelpers.h (95%) rename src/gui/{ => wxgui}/helpers/wxLogEvent.h (100%) rename src/gui/{ => wxgui}/helpers/wxWayland.cpp (95%) rename src/gui/{ => wxgui}/helpers/wxWayland.h (100%) rename src/gui/{ => wxgui}/input/HotkeySettings.cpp (79%) rename src/gui/{ => wxgui}/input/HotkeySettings.h (93%) rename src/gui/{ => wxgui}/input/InputAPIAddWindow.cpp (98%) rename src/gui/{ => wxgui}/input/InputAPIAddWindow.h (97%) rename src/gui/{ => wxgui}/input/InputSettings2.cpp (98%) rename src/gui/{ => wxgui}/input/InputSettings2.h (100%) rename src/gui/{ => wxgui}/input/PairingDialog.cpp (99%) rename src/gui/{ => wxgui}/input/PairingDialog.h (100%) rename src/gui/{ => wxgui}/input/panels/ClassicControllerInputPanel.cpp (96%) rename src/gui/{ => wxgui}/input/panels/ClassicControllerInputPanel.h (90%) rename src/gui/{ => wxgui}/input/panels/InputPanel.cpp (97%) rename src/gui/{ => wxgui}/input/panels/InputPanel.h (98%) rename src/gui/{ => wxgui}/input/panels/ProControllerInputPanel.cpp (97%) rename src/gui/{ => wxgui}/input/panels/ProControllerInputPanel.h (84%) rename src/gui/{ => wxgui}/input/panels/VPADInputPanel.cpp (97%) rename src/gui/{ => wxgui}/input/panels/VPADInputPanel.h (94%) rename src/gui/{ => wxgui}/input/panels/WiimoteInputPanel.cpp (98%) rename src/gui/{ => wxgui}/input/panels/WiimoteInputPanel.h (95%) rename src/gui/{ => wxgui}/input/settings/DefaultControllerSettings.cpp (98%) rename src/gui/{ => wxgui}/input/settings/DefaultControllerSettings.h (100%) rename src/gui/{ => wxgui}/input/settings/WiimoteControllerSettings.cpp (98%) rename src/gui/{ => wxgui}/input/settings/WiimoteControllerSettings.h (100%) rename src/gui/{ => wxgui}/windows/PPCThreadsViewer/DebugPPCThreadsWindow.cpp (99%) rename src/gui/{ => wxgui}/windows/PPCThreadsViewer/DebugPPCThreadsWindow.h (100%) rename src/gui/{ => wxgui}/windows/TextureRelationViewer/TextureRelationWindow.cpp (99%) rename src/gui/{ => wxgui}/windows/TextureRelationViewer/TextureRelationWindow.h (100%) create mode 100644 src/gui/wxgui/wxCemuConfig.cpp create mode 100644 src/gui/wxgui/wxCemuConfig.h rename src/gui/{ => wxgui}/wxHelper.h (100%) create mode 100644 src/gui/wxgui/wxWindowSystem.cpp rename src/gui/{ => wxgui}/wxcomponents/checked.xpm (100%) rename src/gui/{ => wxgui}/wxcomponents/checked2.xpm (100%) rename src/gui/{ => wxgui}/wxcomponents/checked_d.xpm (100%) rename src/gui/{ => wxgui}/wxcomponents/checked_dis.xpm (100%) rename src/gui/{ => wxgui}/wxcomponents/checked_ld.xpm (100%) rename src/gui/{ => wxgui}/wxcomponents/checked_mo.xpm (100%) rename src/gui/{ => wxgui}/wxcomponents/checkedlistctrl.cpp (98%) rename src/gui/{ => wxgui}/wxcomponents/checkedlistctrl.h (100%) rename src/gui/{ => wxgui}/wxcomponents/checktree.cpp (97%) rename src/gui/{ => wxgui}/wxcomponents/checktree.h (100%) rename src/gui/{ => wxgui}/wxcomponents/unchecked.xpm (100%) rename src/gui/{ => wxgui}/wxcomponents/unchecked2.xpm (100%) rename src/gui/{ => wxgui}/wxcomponents/unchecked_d.xpm (100%) rename src/gui/{ => wxgui}/wxcomponents/unchecked_dis.xpm (100%) rename src/gui/{ => wxgui}/wxcomponents/unchecked_ld.xpm (100%) rename src/gui/{ => wxgui}/wxcomponents/unchecked_mo.xpm (100%) rename src/gui/{ => wxgui}/wxgui.h (100%) diff --git a/.github/workflows/generate_pot.yml b/.github/workflows/generate_pot.yml index b057d441..bd42de46 100644 --- a/.github/workflows/generate_pot.yml +++ b/.github/workflows/generate_pot.yml @@ -31,6 +31,7 @@ jobs: find src -name *.cpp -o -name *.hpp -o -name *.h | xargs xgettext --from-code=utf-8 -w 100 --keyword="_" --keyword="wxTRANSLATE" --keyword="wxPLURAL:1,2" + --keyword="_tr" --keyword="TR_NOOP" --check=space-ellipsis --omit-header -o cemu.pot diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 04b6dfdd..a5ab2154 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -150,7 +150,3 @@ if(UNIX AND NOT APPLE) # most likely not helpful in debugging problems with cemu code target_link_options(CemuBin PRIVATE "$<$:-Xlinker;--strip-debug>") endif() - -if (ENABLE_WXWIDGETS) - target_link_libraries(CemuBin PRIVATE wx::base wx::core) -endif() diff --git a/src/Cafe/CMakeLists.txt b/src/Cafe/CMakeLists.txt index 2900059b..1b0def84 100644 --- a/src/Cafe/CMakeLists.txt +++ b/src/Cafe/CMakeLists.txt @@ -597,10 +597,6 @@ else () target_link_libraries(CemuCafe PRIVATE libusb::libusb) endif () -if (ENABLE_WXWIDGETS) - target_link_libraries(CemuCafe PRIVATE wx::base wx::core) -endif() - if(WIN32) target_link_libraries(CemuCafe PRIVATE iphlpapi) endif() diff --git a/src/Cafe/CafeSystem.cpp b/src/Cafe/CafeSystem.cpp index d20ccd9d..0a145a94 100644 --- a/src/Cafe/CafeSystem.cpp +++ b/src/Cafe/CafeSystem.cpp @@ -1,5 +1,5 @@ #include "Cafe/OS/common/OSCommon.h" -#include "gui/wxgui.h" +#include "WindowSystem.h" #include "Cafe/OS/libs/gx2/GX2.h" #include "Cafe/GameProfile/GameProfile.h" #include "Cafe/HW/Espresso/Interpreter/PPCInterpreterInternal.h" @@ -65,9 +65,6 @@ // HW interfaces #include "Cafe/HW/SI/si.h" -// dependency to be removed -#include "gui/guiWrapper.h" - #include #if BOOST_OS_LINUX @@ -172,7 +169,7 @@ void LoadMainExecutable() applicationRPX = RPLLoader_LoadFromMemory(rpxData, rpxSize, (char*)_pathToExecutable.c_str()); if (!applicationRPX) { - wxMessageBox(_("Failed to run this title because the executable is damaged")); + WindowSystem::ShowErrorDialog(_tr("Failed to run this title because the executable is damaged")); cemuLog_createLogFile(false); cemuLog_waitForFlush(); exit(0); @@ -357,7 +354,7 @@ uint32 LoadSharedData() void cemu_initForGame() { - gui_updateWindowTitles(false, true, 0.0); + WindowSystem::UpdateWindowTitles(false, true, 0.0); // input manager apply game profile InputManager::instance().apply_game_profile(); // log info for launched title @@ -855,7 +852,7 @@ namespace CafeSystem PPCTimer_waitForInit(); // start system sSystemRunning = true; - gui_notifyGameLoaded(); + WindowSystem::NotifyGameLoaded(); std::thread t(_LaunchTitleThread); t.detach(); } diff --git a/src/Cafe/Filesystem/FST/KeyCache.cpp b/src/Cafe/Filesystem/FST/KeyCache.cpp index 29903e84..f85d2b54 100644 --- a/src/Cafe/Filesystem/FST/KeyCache.cpp +++ b/src/Cafe/Filesystem/FST/KeyCache.cpp @@ -1,7 +1,7 @@ -#include #include -#include +#include "Cemu/Logging/CemuLogging.h" +#include "WindowSystem.h" #include "config/ActiveSettings.h" #include "util/crypto/aes128.h" #include "Common/FileStream.h" @@ -75,7 +75,7 @@ void KeyCache_Prepare() } else { - wxMessageBox(_("Unable to create file keys.txt\nThis can happen if Cemu does not have write permission to its own directory, the disk is full or if anti-virus software is blocking Cemu."), _("Error"), wxOK | wxCENTRE | wxICON_ERROR); + WindowSystem::ShowErrorDialog(_tr("Unable to create file keys.txt\nThis can happen if Cemu does not have write permission to its own directory, the disk is full or if anti-virus software is blocking Cemu."), _tr("Error"), WindowSystem::ErrorCategory::KEYS_TXT_CREATION); } mtxKeyCache.unlock(); return; @@ -108,8 +108,8 @@ void KeyCache_Prepare() continue; if( strishex(line) == false ) { - auto errorMsg = formatWxString(_("Error in keys.txt at line {}"), lineNumber); - wxMessageBox(errorMsg, _("Error"), wxOK | wxCENTRE | wxICON_ERROR); + auto errorMsg = _tr("Error in keys.txt at line {}", lineNumber); + WindowSystem::ShowErrorDialog(errorMsg, WindowSystem::ErrorCategory::KEYS_TXT_CREATION); continue; } if(line.size() == 32 ) diff --git a/src/Cafe/GraphicPack/GraphicPack2.cpp b/src/Cafe/GraphicPack/GraphicPack2.cpp index 6ae05c5b..ab4dbd3a 100644 --- a/src/Cafe/GraphicPack/GraphicPack2.cpp +++ b/src/Cafe/GraphicPack/GraphicPack2.cpp @@ -85,7 +85,7 @@ bool GraphicPack2::LoadGraphicPack(const fs::path& rulesPath, IniParser& rules) auto gp = std::make_shared(rulesPath, rules); // check if enabled and preset set - const auto& config_entries = g_config.data().graphic_pack_entries; + const auto& config_entries = GetConfigHandle().data().graphic_pack_entries; // legacy absolute path checking for not breaking compatibility auto file = gp->GetRulesPath(); diff --git a/src/Cafe/GraphicPack/GraphicPack2Patches.cpp b/src/Cafe/GraphicPack/GraphicPack2Patches.cpp index 2c067484..d0d00bf2 100644 --- a/src/Cafe/GraphicPack/GraphicPack2Patches.cpp +++ b/src/Cafe/GraphicPack/GraphicPack2Patches.cpp @@ -1,13 +1,12 @@ #include "Cafe/GraphicPack/GraphicPack2.h" +#include "Cemu/Logging/CemuLogging.h" #include "Common/FileStream.h" +#include "WindowSystem.h" #include "util/helpers/StringParser.h" #include "Cemu/PPCAssembler/ppcAssembler.h" #include "Cafe/OS/RPL/rpl_structs.h" #include "boost/algorithm/string.hpp" -#include "gui/wxgui.h" // for wxMessageBox -#include "gui/helpers/wxHelpers.h" - // error handler void PatchErrorHandler::printError(class PatchGroup* patchGroup, sint32 lineNumber, std::string_view errorMsg) { @@ -40,13 +39,13 @@ void PatchErrorHandler::printError(class PatchGroup* patchGroup, sint32 lineNumb void PatchErrorHandler::showStageErrorMessageBox() { - wxString errorMsg; + std::string errorMsg; if (m_gp) { if (m_stage == STAGE::PARSER) - errorMsg.assign(formatWxString(_("Failed to load patches for graphic pack \'{}\'"), m_gp->GetName())); + errorMsg.assign(_tr("Failed to load patches for graphic pack \'{}\'", m_gp->GetName())); else - errorMsg.assign(formatWxString(_("Failed to apply patches for graphic pack \'{}\'"), m_gp->GetName())); + errorMsg.assign(_tr("Failed to apply patches for graphic pack \'{}\'", m_gp->GetName())); } else { @@ -55,7 +54,7 @@ void PatchErrorHandler::showStageErrorMessageBox() if (cemuLog_isLoggingEnabled(LogType::Patches)) { errorMsg.append("\n \n") - .append(_("Details:")) + .append(_tr("Details:")) .append("\n"); for (auto& itr : errorMessages) { @@ -64,7 +63,7 @@ void PatchErrorHandler::showStageErrorMessageBox() } } - wxMessageBox(errorMsg, _("Graphic pack error")); + WindowSystem::ShowErrorDialog(errorMsg, _tr("Graphic pack error"), WindowSystem::ErrorCategory::GRAPHIC_PACKS); } // loads Cemu-style patches (patch_.asm) diff --git a/src/Cafe/HW/Espresso/Debugger/Debugger.cpp b/src/Cafe/HW/Espresso/Debugger/Debugger.cpp index e84c9fda..fbfc94fe 100644 --- a/src/Cafe/HW/Espresso/Debugger/Debugger.cpp +++ b/src/Cafe/HW/Espresso/Debugger/Debugger.cpp @@ -1,19 +1,20 @@ -#include "gui/guiWrapper.h" +#include "Common/precompiled.h" #include "Debugger.h" #include "Cafe/OS/RPL/rpl_structs.h" #include "Cemu/PPCAssembler/ppcAssembler.h" #include "Cafe/HW/Espresso/Recompiler/PPCRecompiler.h" #include "Cemu/ExpressionParser/ExpressionParser.h" -#include "gui/debugger/DebuggerWindow2.h" - #include "Cafe/OS/libs/coreinit/coreinit.h" +#include "OS/RPL/rpl.h" #include "util/helpers/helpers.h" #if BOOST_OS_WINDOWS #include #endif +DebuggerDispatcher g_debuggerDispatcher; + debuggerState_t debuggerState{ }; DebuggerBreakpoint* debugger_getFirstBP(uint32 address) @@ -337,7 +338,7 @@ void debugger_toggleBreakpoint(uint32 address, bool state, DebuggerBreakpoint* b { bp->enabled = state; debugger_updateExecutionBreakpoint(address); - debuggerWindow_updateViewThreadsafe2(); + g_debuggerDispatcher.UpdateViewThreadsafe(); } else if (bpItr->isMemBP()) { @@ -359,7 +360,7 @@ void debugger_toggleBreakpoint(uint32 address, bool state, DebuggerBreakpoint* b debugger_updateMemoryBreakpoint(bpItr); else debugger_updateMemoryBreakpoint(nullptr); - debuggerWindow_updateViewThreadsafe2(); + g_debuggerDispatcher.UpdateViewThreadsafe(); } return; } @@ -496,7 +497,7 @@ void debugger_stepInto(PPCInterpreter_t* hCPU, bool updateDebuggerWindow = true) debugger_updateExecutionBreakpoint(initialIP); debuggerState.debugSession.instructionPointer = hCPU->instructionPointer; if(updateDebuggerWindow) - debuggerWindow_moveIP(); + g_debuggerDispatcher.MoveIP(); ppcRecompilerEnabled = isRecEnabled; } @@ -515,7 +516,7 @@ bool debugger_stepOver(PPCInterpreter_t* hCPU) // nothing to skip, use step-into debugger_stepInto(hCPU); debugger_updateExecutionBreakpoint(initialIP); - debuggerWindow_moveIP(); + g_debuggerDispatcher.MoveIP(); ppcRecompilerEnabled = isRecEnabled; return false; } @@ -523,7 +524,7 @@ bool debugger_stepOver(PPCInterpreter_t* hCPU) debugger_createCodeBreakpoint(initialIP + 4, DEBUGGER_BP_T_ONE_SHOT); // step over current instruction (to avoid breakpoint) debugger_stepInto(hCPU); - debuggerWindow_moveIP(); + g_debuggerDispatcher.MoveIP(); // restore breakpoints debugger_updateExecutionBreakpoint(initialIP); // run @@ -621,8 +622,8 @@ void debugger_enterTW(PPCInterpreter_t* hCPU) DebuggerBreakpoint* singleshotBP = debugger_getFirstBP(debuggerState.debugSession.instructionPointer, DEBUGGER_BP_T_ONE_SHOT); if (singleshotBP) debugger_deleteBreakpoint(singleshotBP); - debuggerWindow_notifyDebugBreakpointHit2(); - debuggerWindow_updateViewThreadsafe2(); + g_debuggerDispatcher.NotifyDebugBreakpointHit(); + g_debuggerDispatcher.UpdateViewThreadsafe(); // reset step control debuggerState.debugSession.stepInto = false; debuggerState.debugSession.stepOver = false; @@ -639,14 +640,14 @@ void debugger_enterTW(PPCInterpreter_t* hCPU) break; // if true is returned, continue with execution } debugger_createPPCStateSnapshot(hCPU); - debuggerWindow_updateViewThreadsafe2(); + g_debuggerDispatcher.UpdateViewThreadsafe(); debuggerState.debugSession.stepOver = false; } if (debuggerState.debugSession.stepInto) { debugger_stepInto(hCPU); debugger_createPPCStateSnapshot(hCPU); - debuggerWindow_updateViewThreadsafe2(); + g_debuggerDispatcher.UpdateViewThreadsafe(); debuggerState.debugSession.stepInto = false; continue; } @@ -663,8 +664,8 @@ void debugger_enterTW(PPCInterpreter_t* hCPU) debuggerState.debugSession.isTrapped = false; debuggerState.debugSession.hCPU = nullptr; - debuggerWindow_updateViewThreadsafe2(); - debuggerWindow_notifyRun(); + g_debuggerDispatcher.UpdateViewThreadsafe(); + g_debuggerDispatcher.NotifyRun(); } void debugger_shouldBreak(PPCInterpreter_t* hCPU) diff --git a/src/Cafe/HW/Espresso/Debugger/Debugger.h b/src/Cafe/HW/Espresso/Debugger/Debugger.h index c220eb8a..d385cadd 100644 --- a/src/Cafe/HW/Espresso/Debugger/Debugger.h +++ b/src/Cafe/HW/Espresso/Debugger/Debugger.h @@ -15,6 +15,69 @@ #define DEBUGGER_BP_T_GDBSTUB_TW 0x7C010008 #define DEBUGGER_BP_T_DEBUGGER_TW 0x7C020008 +class DebuggerCallbacks +{ + public: + virtual void UpdateViewThreadsafe() {} + virtual void NotifyDebugBreakpointHit() {} + virtual void NotifyRun() {} + virtual void MoveIP() {} + virtual void NotifyModuleLoaded(void* module) {} + virtual void NotifyModuleUnloaded(void* module) {} + virtual ~DebuggerCallbacks() = default; +}; + +class DebuggerDispatcher +{ + private: + static inline class DefaultDebuggerCallbacks : public DebuggerCallbacks + { + } s_defaultDebuggerCallbacks; + DebuggerCallbacks* m_callbacks = &s_defaultDebuggerCallbacks; + + public: + void SetDebuggerCallbacks(DebuggerCallbacks* debuggerCallbacks) + { + cemu_assert_debug(m_callbacks == &s_defaultDebuggerCallbacks); + m_callbacks = debuggerCallbacks; + } + + void ClearDebuggerCallbacks() + { + cemu_assert_debug(m_callbacks != &s_defaultDebuggerCallbacks); + m_callbacks = &s_defaultDebuggerCallbacks; + } + + void UpdateViewThreadsafe() + { + m_callbacks->UpdateViewThreadsafe(); + } + + void NotifyDebugBreakpointHit() + { + m_callbacks->NotifyDebugBreakpointHit(); + } + + void NotifyRun() + { + m_callbacks->NotifyRun(); + } + + void MoveIP() + { + m_callbacks->MoveIP(); + } + + void NotifyModuleLoaded(void* module) + { + m_callbacks->NotifyModuleLoaded(module); + } + + void NotifyModuleUnloaded(void* module) + { + m_callbacks->NotifyModuleUnloaded(module); + } +} extern g_debuggerDispatcher; struct DebuggerBreakpoint { diff --git a/src/Cafe/HW/Latte/Core/LatteOverlay.cpp b/src/Cafe/HW/Latte/Core/LatteOverlay.cpp index e6edb904..7499d743 100644 --- a/src/Cafe/HW/Latte/Core/LatteOverlay.cpp +++ b/src/Cafe/HW/Latte/Core/LatteOverlay.cpp @@ -1,6 +1,6 @@ #include "Cafe/HW/Latte/Core/LatteOverlay.h" #include "Cafe/HW/Latte/Core/LattePerformanceMonitor.h" -#include "gui/guiWrapper.h" +#include "WindowSystem.h" #include "config/CemuConfig.h" @@ -519,17 +519,17 @@ void LatteOverlay_render(bool pad_view) return; sint32 w = 0, h = 0; - if (pad_view && gui_isPadWindowOpen()) - gui_getPadWindowPhysSize(w, h); + if (pad_view && WindowSystem::IsPadWindowOpen()) + WindowSystem::GetPadWindowPhysSize(w, h); else - gui_getWindowPhysSize(w, h); + WindowSystem::GetWindowPhysSize(w, h); if (w == 0 || h == 0) return; const Vector2f window_size{ (float)w,(float)h }; - float fontDPIScale = !pad_view ? gui_getWindowDPIScale() : gui_getPadDPIScale(); + float fontDPIScale = !pad_view ? WindowSystem::GetWindowDPIScale() : WindowSystem::GetPadDPIScale(); float overlayFontSize = 14.0f * (float)config.overlay.text_scale / 100.0f * fontDPIScale; diff --git a/src/Cafe/HW/Latte/Core/LattePerformanceMonitor.cpp b/src/Cafe/HW/Latte/Core/LattePerformanceMonitor.cpp index 14dfe9a9..a3bcb63e 100644 --- a/src/Cafe/HW/Latte/Core/LattePerformanceMonitor.cpp +++ b/src/Cafe/HW/Latte/Core/LattePerformanceMonitor.cpp @@ -1,6 +1,6 @@ #include "Cafe/HW/Latte/Core/LattePerformanceMonitor.h" #include "Cafe/HW/Latte/Core/LatteOverlay.h" -#include "gui/guiWrapper.h" +#include "WindowSystem.h" performanceMonitor_t performanceMonitor{}; @@ -106,12 +106,12 @@ void LattePerformanceMonitor_frameEnd() if (isFirstUpdate) { LatteOverlay_updateStats(0.0, 0, 0); - gui_updateWindowTitles(false, false, 0.0); + WindowSystem::UpdateWindowTitles(false, false, 0.0); } else { LatteOverlay_updateStats(fps, drawCallCounter / elapsedFrames, fastDrawCallCounter / elapsedFrames); - gui_updateWindowTitles(false, false, fps); + WindowSystem::UpdateWindowTitles(false, false, fps); } } } diff --git a/src/Cafe/HW/Latte/Core/LatteRenderTarget.cpp b/src/Cafe/HW/Latte/Core/LatteRenderTarget.cpp index 2efef5bf..be9917e1 100644 --- a/src/Cafe/HW/Latte/Core/LatteRenderTarget.cpp +++ b/src/Cafe/HW/Latte/Core/LatteRenderTarget.cpp @@ -11,7 +11,7 @@ #include "Cafe/HW/Latte/Core/LattePerformanceMonitor.h" #include "Cafe/GraphicPack/GraphicPack2.h" #include "config/ActiveSettings.h" -#include "gui/guiWrapper.h" +#include "WindowSystem.h" #include "Cafe/OS/libs/erreula/erreula.h" #include "input/InputManager.h" #include "Cafe/OS/libs/swkbd/swkbd.h" @@ -838,10 +838,10 @@ sint32 _currentOutputImageHeight = 0; void LatteRenderTarget_getScreenImageArea(sint32* x, sint32* y, sint32* width, sint32* height, sint32* fullWidth, sint32* fullHeight, bool padView) { int w, h; - if(padView && gui_isPadWindowOpen()) - gui_getPadWindowPhysSize(w, h); + if(padView && WindowSystem::IsPadWindowOpen()) + WindowSystem::GetPadWindowPhysSize(w, h); else - gui_getWindowPhysSize(w, h); + WindowSystem::GetWindowPhysSize(w, h); sint32 scaledOutputX; sint32 scaledOutputY; @@ -999,8 +999,8 @@ void LatteRenderTarget_itHLECopyColorBufferToScanBuffer(MPTR colorBufferPtr, uin return {pressed && !toggle, pressed && toggle}; }; - const bool tabPressed = gui_isKeyDown(PlatformKeyCodes::TAB); - const bool ctrlPressed = gui_isKeyDown(PlatformKeyCodes::LCONTROL); + const bool tabPressed = WindowSystem::IsKeyDown(WindowSystem::PlatformKeyCodes::TAB); + const bool ctrlPressed = WindowSystem::IsKeyDown(WindowSystem::PlatformKeyCodes::LCONTROL); const auto [vpad0Active, vpad0Toggle] = getVPADScreenActive(0); const auto [vpad1Active, vpad1Toggle] = getVPADScreenActive(1); diff --git a/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp b/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp index 86035973..737e9201 100644 --- a/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp +++ b/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp @@ -6,7 +6,7 @@ #include "Cafe/HW/Latte/Core/FetchShader.h" #include "Cemu/FileCache/FileCache.h" #include "Cafe/GameProfile/GameProfile.h" -#include "gui/guiWrapper.h" +#include "WindowSystem.h" #include "Cafe/HW/Latte/Renderer/Renderer.h" #include "Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.h" @@ -24,7 +24,6 @@ #include "Cafe/HW/Latte/Common/ShaderSerializer.h" #include "util/helpers/Serializer.h" -#include #include