// Executes the shortcut iShortcut on controller iController // Special case: if iPlayer is -1, run the mouselock shortcut void DoShortcut( int iControl, int iShortcut ) { DebugWriteA("Shortcut: %d %d\n", iControl, iShortcut); TCHAR pszMessage[DEFAULT_BUFFER / 2] = TEXT(""); bool bEjectFirst = false; if (iControl == -1) { EnterCriticalSection( &g_critical ); if( g_sysMouse.didHandle ) { g_sysMouse.didHandle->Unacquire(); if( g_bExclusiveMouse ) { g_sysMouse.didHandle->Unacquire(); g_sysMouse.didHandle->SetCooperativeLevel( g_strEmuInfo.hMainWindow, DIB_KEYBOARD ); g_sysMouse.didHandle->Acquire(); LoadString( g_hResourceDLL, IDS_POP_MOUSEUNLOCKED, pszMessage, ARRAYSIZE(pszMessage) ); } else { g_sysMouse.didHandle->Unacquire(); g_sysMouse.didHandle->SetCooperativeLevel( g_strEmuInfo.hMainWindow, DIB_MOUSE ); g_sysMouse.didHandle->Acquire(); LoadString( g_hResourceDLL, IDS_POP_MOUSELOCKED, pszMessage, ARRAYSIZE(pszMessage) ); } g_sysMouse.didHandle->Acquire(); g_bExclusiveMouse = !g_bExclusiveMouse; } LeaveCriticalSection( &g_critical ); } else if( g_pcControllers[iControl].fPlugged ) { if( g_pcControllers[iControl].pPakData ) { SaveControllerPak( iControl ); CloseControllerPak( iControl ); } switch (iShortcut) { case SC_NOPAK: EnterCriticalSection( &g_critical ); g_pcControllers[iControl].PakType = PAK_NONE; g_pcControllers[iControl].fPakInitialized = false; LoadString( g_hResourceDLL, IDS_P_NONE, pszMessage, ARRAYSIZE(pszMessage) ); LeaveCriticalSection( &g_critical ); break; case SC_MEMPAK: if (PAK_NONE == g_pcControllers[iControl].PakType) { EnterCriticalSection( &g_critical ); g_pcControllers[iControl].PakType = PAK_MEM; g_pcControllers[iControl].fPakInitialized = false; LoadString( g_hResourceDLL, IDS_P_MEMPAK, pszMessage, ARRAYSIZE(pszMessage) ); LeaveCriticalSection( &g_critical ); } else { bEjectFirst = true; } break; case SC_RUMBPAK: if (PAK_NONE == g_pcControllers[iControl].PakType) { EnterCriticalSection( &g_critical ); g_pcControllers[iControl].PakType = PAK_RUMBLE; g_pcControllers[iControl].fPakInitialized = false; if( g_pcControllers[iControl].fRawData ) if (CreateEffectHandle( iControl, g_pcControllers[iControl].bRumbleTyp, g_pcControllers[iControl].bRumbleStrength ) ) { DebugWriteA("CreateEffectHandle for shortcut switch: OK\n"); } else { DebugWriteA("Couldn't CreateEffectHandle for shortcut switch.\n"); } LoadString( g_hResourceDLL, IDS_P_RUMBLEPAK, pszMessage, ARRAYSIZE(pszMessage) ); LeaveCriticalSection( &g_critical ); } else { bEjectFirst = true; } break; case SC_TRANSPAK: if (PAK_NONE == g_pcControllers[iControl].PakType) { EnterCriticalSection( &g_critical ); g_pcControllers[iControl].PakType = PAK_TRANSFER; g_pcControllers[iControl].fPakInitialized = false; LoadString( g_hResourceDLL, IDS_P_TRANSFERPAK, pszMessage, ARRAYSIZE(pszMessage) ); LeaveCriticalSection( &g_critical ); } else { bEjectFirst = true; } break; case SC_VOICEPAK: if (PAK_NONE == g_pcControllers[iControl].PakType) { EnterCriticalSection( &g_critical ); g_pcControllers[iControl].PakType = PAK_VOICE; g_pcControllers[iControl].fPakInitialized = false; LoadString( g_hResourceDLL, IDS_P_VOICEPAK, pszMessage, ARRAYSIZE(pszMessage) ); LeaveCriticalSection( &g_critical ); } else { bEjectFirst = true; } break; case SC_ADAPTPAK: if (PAK_NONE == g_pcControllers[iControl].PakType) { EnterCriticalSection( &g_critical ); g_pcControllers[iControl].PakType = PAK_ADAPTOID; g_pcControllers[iControl].fPakInitialized = false; LoadString( g_hResourceDLL, IDS_P_ADAPTOIDPAK, pszMessage, ARRAYSIZE(pszMessage) ); LeaveCriticalSection( &g_critical ); } else { bEjectFirst = true; } break; case SC_SWMEMRUMB: bEjectFirst = true; if( g_pcControllers[iControl].PakType == PAK_MEM ) { iShortcut = PAK_RUMBLE; } else { iShortcut = PAK_MEM; } break; case SC_SWMEMADAPT: bEjectFirst = true; if( g_pcControllers[iControl].PakType == PAK_MEM ) { iShortcut = PAK_ADAPTOID; } else { iShortcut = PAK_MEM; } break; default: DebugWriteA("Invalid iShortcut passed to DoShortcut\n"); EnterCriticalSection( &g_critical ); g_pcControllers[iControl].fPakInitialized = false; LeaveCriticalSection( &g_critical ); return; } // switch (iShortcut) } // else if // let the game code re-init the pak. if (bEjectFirst) // we need to eject the current pack first; then set a DoShortcut to try again in 1 second { EnterCriticalSection( &g_critical ); g_pcControllers[iControl].PakType = PAK_NONE; g_pcControllers[iControl].fPakInitialized = false; LoadString( g_hResourceDLL, IDS_P_SWITCHING, pszMessage, ARRAYSIZE(pszMessage) ); LeaveCriticalSection( &g_critical ); LPMSHORTCUT lpmNextShortcut = (LPMSHORTCUT)P_malloc(sizeof(MSHORTCUT)); if (!lpmNextShortcut) return; lpmNextShortcut->iControl = iControl; lpmNextShortcut->iShortcut = iShortcut; CreateThread(NULL, 0, DelayedShortcut, lpmNextShortcut, 0, NULL); iControl = -2; // this is just a hack to get around the check that appends "Changing Pak X to ..." } if( g_strEmuInfo.fDisplayShortPop && _tcslen(pszMessage) > 0 ) { if( iControl >= 0 ) { TCHAR tszNotify[DEFAULT_BUFFER / 2]; LoadString( g_hResourceDLL, IDS_POP_CHANGEPAK, tszNotify, ARRAYSIZE(tszNotify)); wsprintf( g_pszThreadMessage, tszNotify, iControl+1, pszMessage ); } else lstrcpyn( g_pszThreadMessage, pszMessage, ARRAYSIZE(g_pszThreadMessage) ); CreateThread(NULL, 0, MsgThreadFunction, g_pszThreadMessage, 0, NULL); } }
// returns true if the ROM was loaded OK bool LoadCart(LPGBCART Cart, LPCTSTR RomFileName, LPCTSTR RamFileName, LPCTSTR TdfFileName) { HANDLE hTemp; DWORD dwFilesize; DWORD NumQuarterBlocks = 0; UnloadCart(Cart); // first, make sure any previous carts have been unloaded Cart->iCurrentRamBankNo = 0; Cart->iCurrentRomBankNo = 1; Cart->bRamEnableState = 0; Cart->bMBC1RAMbanking = 0; // Attempt to load the ROM file. hTemp = CreateFile(RomFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if (hTemp != INVALID_HANDLE_VALUE && (Cart->hRomFile = CreateFileMapping(hTemp, NULL, PAGE_READONLY, 0, 0, NULL) ) ) { // if the first case fails, the file doesn't exist. The second case can fail if the file size is zero. dwFilesize = GetFileSize(hTemp, NULL); CloseHandle(hTemp); Cart->RomData = (LPCBYTE)MapViewOfFile( Cart->hRomFile, FILE_MAP_READ, 0, 0, 0 ); } else { DebugWriteA("Couldn't load the ROM file, GetLastError returned %08x\n", GetLastError()); if (hTemp != INVALID_HANDLE_VALUE) CloseHandle(hTemp); // if file size was zero, make sure we don't leak the handle ErrorMessage(IDS_ERR_GBROM, 0, false); return false; } if (dwFilesize < 0x8000) // a Rom file has to be at least 32kb { DebugWriteA("ROM file wasn't big enough to be a GB ROM!\n"); ErrorMessage(IDS_ERR_GBROM, 0, false); UnloadCart(Cart); return false; } DebugWriteA(" Cartridge Type #:"); DebugWriteByteA(Cart->RomData[0x147]); DebugWriteA("\n"); switch (Cart->RomData[0x147]) { // if we hadn't checked the file size before, this might have caused an access violation case 0x00: Cart->iCartType = GB_NORM; Cart->bHasRam = false; Cart->bHasBattery = false; Cart->bHasTimer = false; Cart->bHasRumble = false; break; case 0x01: Cart->iCartType = GB_MBC1; Cart->bHasRam = false; Cart->bHasBattery = false; Cart->bHasTimer = false; Cart->bHasRumble = false; break; case 0x02: Cart->iCartType = GB_MBC1; Cart->bHasRam = true; Cart->bHasBattery = false; Cart->bHasTimer = false; Cart->bHasRumble = false; break; case 0x03: Cart->iCartType = GB_MBC1; Cart->bHasRam = true; Cart->bHasBattery = true; Cart->bHasTimer = false; Cart->bHasRumble = false; break; case 0x05: Cart->iCartType = GB_MBC2; Cart->bHasRam = false; Cart->bHasBattery = false; Cart->bHasTimer = false; Cart->bHasRumble = false; break; case 0x06: Cart->iCartType = GB_MBC2; Cart->bHasRam = false; Cart->bHasBattery = true; Cart->bHasTimer = false; Cart->bHasRumble = false; break; case 0x08: Cart->iCartType = GB_NORM; Cart->bHasRam = true; Cart->bHasBattery = false; Cart->bHasTimer = false; Cart->bHasRumble = false; break; case 0x09: Cart->iCartType = GB_NORM; Cart->bHasRam = true; Cart->bHasBattery = true; Cart->bHasTimer = false; Cart->bHasRumble = false; break; case 0x0B: Cart->iCartType = GB_MMMO1; Cart->bHasRam = false; Cart->bHasBattery = false; Cart->bHasTimer = false; Cart->bHasRumble = false; break; case 0x0C: Cart->iCartType = GB_MMMO1; Cart->bHasRam = true; Cart->bHasBattery = false; Cart->bHasTimer = false; Cart->bHasRumble = false; break; case 0x0D: Cart->iCartType = GB_MMMO1; Cart->bHasRam = true; Cart->bHasBattery = true; Cart->bHasTimer = false; Cart->bHasRumble = false; break; case 0x0F: Cart->iCartType = GB_MBC3; Cart->bHasRam = false; Cart->bHasBattery = true; Cart->bHasTimer = true; Cart->bHasRumble = false; break; case 0x10: Cart->iCartType = GB_MBC3; Cart->bHasRam = true; Cart->bHasBattery = true; Cart->bHasTimer = true; Cart->bHasRumble = false; break; case 0x11: Cart->iCartType = GB_MBC3; Cart->bHasRam = false; Cart->bHasBattery = false; Cart->bHasTimer = false; Cart->bHasRumble = false; break; case 0x12: Cart->iCartType = GB_MBC3; Cart->bHasRam = true; Cart->bHasBattery = true; Cart->bHasTimer = false; Cart->bHasRumble = false; break; case 0x13: Cart->iCartType = GB_MBC3; Cart->bHasRam = true; Cart->bHasBattery = true; Cart->bHasTimer = false; Cart->bHasRumble = false; break; case 0x19: Cart->iCartType = GB_MBC5; Cart->bHasRam = false; Cart->bHasBattery = false; Cart->bHasTimer = false; Cart->bHasRumble = false; break; case 0x1A: Cart->iCartType = GB_MBC5; Cart->bHasRam = true; Cart->bHasBattery = false; Cart->bHasTimer = false; Cart->bHasRumble = false; break; case 0x1B: Cart->iCartType = GB_MBC5; Cart->bHasRam = true; Cart->bHasBattery = true; Cart->bHasTimer = false; Cart->bHasRumble = false; break; case 0x1C: Cart->iCartType = GB_MBC5; Cart->bHasRam = false; Cart->bHasBattery = false; Cart->bHasTimer = false; Cart->bHasRumble = true; break; case 0x1D: Cart->iCartType = GB_MBC5; Cart->bHasRam = true; Cart->bHasBattery = false; Cart->bHasTimer = false; Cart->bHasRumble = true; break; case 0x1E: Cart->iCartType = GB_MBC5; Cart->bHasRam = true; Cart->bHasBattery = true; Cart->bHasTimer = false; Cart->bHasRumble = true; break; default: WarningMessage( IDS_ERR_GBROM, MB_OK | MB_ICONWARNING); DebugWriteA("TPak: unsupported paktype\n"); UnloadCart(Cart); return false; } // assign read/write handlers switch (Cart->iCartType) { case GB_NORM: // Raw cartridge Cart->ptrfnReadCart = &ReadCartNorm; Cart->ptrfnWriteCart = &WriteCartNorm; break; case GB_MBC1: Cart->ptrfnReadCart = &ReadCartMBC1; Cart->ptrfnWriteCart = &WriteCartMBC1; break; case GB_MBC2: Cart->ptrfnReadCart = &ReadCartMBC2; Cart->ptrfnWriteCart = &WriteCartMBC2; break; case GB_MBC3: Cart->ptrfnReadCart = &ReadCartMBC3; Cart->ptrfnWriteCart = &WriteCartMBC3; break; case GB_MBC5: Cart->ptrfnReadCart = &ReadCartMBC5; Cart->ptrfnWriteCart = &WriteCartMBC5; break; default: // Don't pretend we know how to handle carts we don't support Cart->ptrfnReadCart = NULL; Cart->ptrfnWriteCart = NULL; DebugWriteA("Unsupported paktype: can't read/write cart type %02X\n", Cart->iCartType); UnloadCart(Cart); return false; } // Determine ROM size for paging checks Cart->iNumRomBanks = 2; switch (Cart->RomData[0x148]) { case 0x01: Cart->iNumRomBanks = 4; break; case 0x02: Cart->iNumRomBanks = 8; break; case 0x03: Cart->iNumRomBanks = 16; break; case 0x04: Cart->iNumRomBanks = 32; break; case 0x05: Cart->iNumRomBanks = 64; break; case 0x06: Cart->iNumRomBanks = 128; break; case 0x52: Cart->iNumRomBanks = 72; break; case 0x53: Cart->iNumRomBanks = 80; break; case 0x54: Cart->iNumRomBanks = 96; break; } if (dwFilesize != 0x4000 * Cart->iNumRomBanks) // Now that we know how big the ROM is supposed to be, check it again { ErrorMessage(IDS_ERR_GBROM, 0, false); UnloadCart(Cart); return false; } // Determine RAM size for paging checks Cart->iNumRamBanks = 0; switch (Cart->RomData[0x149]) { case 0x01: Cart->iNumRamBanks = 1; NumQuarterBlocks = 1; break; case 0x02: Cart->iNumRamBanks = 1; NumQuarterBlocks = 4; break; case 0x03: Cart->iNumRamBanks = 4; NumQuarterBlocks = 16; break; case 0x04: Cart->iNumRamBanks = 16; NumQuarterBlocks = 64; break; case 0x05: Cart->iNumRamBanks = 8; NumQuarterBlocks = 32; break; } DebugWriteA("GB cart has %d ROM banks, %d RAM quarter banks\n", Cart->iNumRomBanks, NumQuarterBlocks); if (Cart->bHasTimer) { DebugWriteA("GB cart timer present\n"); } // Attempt to load the SRAM file, but only if RAM is supposed to be present. // For saving back to a file, if we map too much it will expand the file. if (Cart->bHasRam) { if (Cart->bHasBattery) { hTemp = CreateFile( RamFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, 0, NULL ); if( hTemp == INVALID_HANDLE_VALUE ) {// test if Read-only access is possible hTemp = CreateFile( RamFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, 0, NULL ); if (Cart->bHasTimer && Cart->bHasBattery) { Cart->RamData = (LPBYTE)P_malloc(NumQuarterBlocks * 0x0800 + sizeof(gbCartRTC)); ClearData(Cart->RamData, NumQuarterBlocks * 0x0800 + sizeof(gbCartRTC)); } else { Cart->RamData = (LPBYTE)P_malloc(NumQuarterBlocks * 0x0800); ClearData(Cart->RamData, NumQuarterBlocks * 0x0800); } if( hTemp != INVALID_HANDLE_VALUE ) { DWORD dwBytesRead; if (Cart->bHasTimer && Cart->bHasBattery) ReadFile(hTemp, Cart->RamData, NumQuarterBlocks * 0x0800 + sizeof(gbCartRTC), &dwBytesRead, NULL); else ReadFile(hTemp, Cart->RamData, NumQuarterBlocks * 0x0800, &dwBytesRead, NULL); WarningMessage( IDS_DLG_TPAK_READONLY, MB_OK | MB_ICONWARNING); } else { WarningMessage( IDS_ERR_GBSRAMERR, MB_OK | MB_ICONWARNING); return true; } } else { // file is OK, use a mapping if (Cart->bHasTimer && Cart->bHasBattery) Cart->hRamFile = CreateFileMapping( hTemp, NULL, PAGE_READWRITE, 0, NumQuarterBlocks * 0x0800 + sizeof(gbCartRTC), NULL); else Cart->hRamFile = CreateFileMapping( hTemp, NULL, PAGE_READWRITE, 0, NumQuarterBlocks * 0x0800, NULL); if (Cart->hRamFile != NULL) { Cart->RamData = (LPBYTE)MapViewOfFile( Cart->hRamFile, FILE_MAP_ALL_ACCESS, 0, 0, 0 ); } else { // could happen, if the file isn't big enough AND can't be grown to fit DWORD dwBytesRead; if (Cart->bHasTimer && Cart->bHasBattery) { Cart->RamData = (LPBYTE)P_malloc(NumQuarterBlocks * 0x0800 + sizeof(gbCartRTC)); ReadFile(hTemp, Cart->RamData, NumQuarterBlocks * 0x0800 + sizeof(gbCartRTC), &dwBytesRead, NULL); } else { Cart->RamData = (LPBYTE)P_malloc(NumQuarterBlocks * 0x0800); ReadFile(hTemp, Cart->RamData, NumQuarterBlocks * 0x0800, &dwBytesRead, NULL); } if (dwBytesRead < NumQuarterBlocks * 0x0800 + ((Cart->bHasTimer && Cart->bHasBattery) ? sizeof(gbCartRTC) : 0)) { ClearData(Cart->RamData, NumQuarterBlocks * 0x0800 + ((Cart->bHasTimer && Cart->bHasBattery) ? sizeof(gbCartRTC) : 0)); WarningMessage( IDS_ERR_GBSRAMERR, MB_OK | MB_ICONWARNING); } else { WarningMessage( IDS_DLG_TPAK_READONLY, MB_OK | MB_ICONWARNING); } } } if (Cart->bHasTimer && Cart->bHasBattery) { dwFilesize = GetFileSize(hTemp, 0); if (dwFilesize >= (NumQuarterBlocks * 0x0800 + sizeof(gbCartRTC) ) ) { // Looks like there is extra data in the SAV file than just RAM data... assume it is RTC data. gbCartRTC RTCTimer; CopyMemory( &RTCTimer, &Cart->RamData[NumQuarterBlocks * 0x0800], sizeof(RTCTimer) ); Cart->TimerData[0] = (BYTE)RTCTimer.mapperSeconds; Cart->TimerData[1] = (BYTE)RTCTimer.mapperMinutes; Cart->TimerData[2] = (BYTE)RTCTimer.mapperHours; Cart->TimerData[3] = (BYTE)RTCTimer.mapperDays; Cart->TimerData[4] = (BYTE)RTCTimer.mapperControl; Cart->LatchedTimerData[0] = (BYTE)RTCTimer.mapperLSeconds; Cart->LatchedTimerData[1] = (BYTE)RTCTimer.mapperLMinutes; Cart->LatchedTimerData[2] = (BYTE)RTCTimer.mapperLHours; Cart->LatchedTimerData[3] = (BYTE)RTCTimer.mapperLDays; Cart->LatchedTimerData[4] = (BYTE)RTCTimer.mapperLControl; Cart->timerLastUpdate = RTCTimer.mapperLastTime; UpdateRTC(Cart); } else { ReadTDF(Cart); // try to open TDF format, clear/init Cart->TimerData if that fails } } CloseHandle(hTemp); } else { // no battery; just allocate some RAM Cart->RamData = (LPBYTE)P_malloc(Cart->iNumRamBanks * 0x2000); } } Cart->TimerDataLatched = false; return true; }