// Done bool WriteCartNorm(LPGBCART Cart, WORD dwAddress, BYTE *Data) { if (!Cart->bHasRam) { DebugWriteA("RAM write: no RAM\n"); return true; } if (Cart->RomData[0x149] == 1) { // Whoops... Only 1/4 of the RAM space is used. if ((dwAddress >= 0xA000) && (dwAddress <= 0xA7FF)) { // Write to RAM DebugWriteA("RAM write: Unbanked\n"); CopyMemory(&Cart->RamData[dwAddress - 0xA000], Data, 32); } else { DebugWriteA("RAM write: Unbanked (out of range!)\n"); } } else { if ((dwAddress >= 0xA000) && (dwAddress <= 0xBFFF)) { // Write to RAM DebugWriteA("RAM write: Unbanked\n"); CopyMemory(&Cart->RamData[dwAddress - 0xA000], Data, 32); } } return true; }
// Done bool WriteCartMBC1(LPGBCART Cart, WORD dwAddress, BYTE *Data) { if ((dwAddress >= 0x0000) && (dwAddress <= 0x1FFF)) // RAM enable { Cart->bRamEnableState = (Data[0] == 0x0A); DebugWriteA("Set RAM enable: %d\n", Cart->bRamEnableState); } else if ((dwAddress >= 0x2000) && (dwAddress <= 0x3FFF)) // ROM bank select { Cart->iCurrentRomBankNo &= 0x60; // keep MSB Cart->iCurrentRomBankNo |= Data[0] & 0x1F; // emulate quirk: 0x00 -> 0x01, 0x20 -> 0x21, 0x40->0x41, 0x60 -> 0x61 if ((Cart->iCurrentRomBankNo & 0x1F) == 0) { Cart->iCurrentRomBankNo |= 0x01; } DebugWriteA("Set ROM Bank: %02X\n", Cart->iCurrentRomBankNo); } else if ((dwAddress >= 0x4000) && (dwAddress <= 0x5FFF)) // RAM bank select { if (Cart->bMBC1RAMbanking) { Cart->iCurrentRamBankNo = Data[0] & 0x03; DebugWriteA("Set RAM Bank: %02X\n", Cart->iCurrentRamBankNo); } else { Cart->iCurrentRomBankNo &= 0x1F; Cart->iCurrentRomBankNo |= ((Data[0] & 0x03) << 5); // set bits 5 and 6 of ROM bank DebugWriteA("Set ROM Bank MSB, ROM bank now: %02X\n", Cart->iCurrentRomBankNo); } } else if ((dwAddress >= 0x6000) && (dwAddress <= 0x7FFF)) // MBC1 mode select { // this is overly complicated, but it keeps us from having to do bitwise math later // Basically we shuffle the 2 "magic bits" between iCurrentRomBankNo and iCurrentRamBankNo as necessary. if (Cart->bMBC1RAMbanking != (Data[0] & 0x01)) { // we should only alter the ROM and RAM bank numbers if we have changed modes Cart->bMBC1RAMbanking = Data[0] & 0x01; if (Cart->bMBC1RAMbanking) { Cart->iCurrentRamBankNo = Cart->iCurrentRomBankNo >> 5; // set the ram bank to the "magic bits" Cart->iCurrentRomBankNo &= 0x1F; // zero out bits 5 and 6 to keep consistency } else {
HRESULT WriteAdaptoidPak( LPDIRECTINPUTDEVICE8 lpDirectInputDevice, DWORD addr, LPBYTE data ) { DIEFFESCAPE esc; struct { DWORD addr; BYTE data[32]; } buf; buf.addr = addr; CopyMemory( buf.data, data, 32 ); esc.dwSize = sizeof(esc); esc.dwCommand = ADAPT_WRITEPAK; // Write 32 bytes to pak esc.lpvInBuffer = &buf; esc.cbInBuffer = 36; esc.lpvOutBuffer = NULL; esc.cbOutBuffer = 0; HRESULT hr = lpDirectInputDevice->Escape(&esc); #ifdef _DEBUG LPCSTR suc = (SUCCEEDED(hr)) ? "OK" : "FAILED"; DebugWriteA( "Direct Adaptoid WritePak(Addr:%04X): %s (RC:%08X)\n", addr, suc, hr ); #endif // #ifdef _DEBUG return hr; }
/****************************************************************** Function: GetKeys Purpose: To get the current state of the controllers buttons. input: - Controller Number (0 to 3) - A pointer to a BUTTONS structure to be filled with the controller state. output: none *******************************************************************/ EXPORT void CALL GetKeys(int Control, BUTTONS * Keys ) { #ifdef ENABLE_RAWPAK_DEBUG DebugWriteA("CALLED: GetKeys\n"); #endif if( g_bConfiguring ) Keys->Value = 0; else { EnterCriticalSection( &g_critical ); if( g_pcControllers[Control].fPlugged ) { if (Control == g_iFirstController ) { GetDeviceDatas(); CheckShortcuts(); } if( g_pcControllers[Control].xiController.bConnected && g_pcControllers[Control].fXInput ) // reads the xinput controller keys, if connected --tecnicors GetXInputControllerKeys( &g_pcControllers[Control].xiController, &Keys->Value ); else GetNControllerInput( Control, &Keys->Value ); } LeaveCriticalSection( &g_critical ); } return; }
/****************************************************************** Function: RomClosed Purpose: This function is called when a rom is closed. input: none output: none *******************************************************************/ EXPORT void CALL RomClosed(void) { int i; XInputEnable( FALSE ); // disables xinput --tecnicors DebugWriteA("CALLED: RomClosed\n"); EnterCriticalSection( &g_critical ); if (g_sysMouse.didHandle) g_sysMouse.didHandle->SetCooperativeLevel(g_strEmuInfo.hMainWindow, DIB_KEYBOARD); // unlock the mouse, just in case for( i = 0; i < ARRAYSIZE(g_pcControllers); ++i ) { if( g_pcControllers[i].pPakData ) { SaveControllerPak( i ); CloseControllerPak( i ); } // freePakData( &g_pcControllers[i] ); already done by CloseControllerPak --rabid // DON'T free the modifiers! // ZeroMemory( &g_pcControllers[i], sizeof(CONTROLLER) ); } for( i = 0; i < ARRAYSIZE( g_apdiEffect ); ++i ) ReleaseEffect( g_apdiEffect[i] ); ZeroMemory( g_apdiEffect, sizeof(g_apdiEffect) ); g_bRunning = false; LeaveCriticalSection( &g_critical ); return; }
// Use string table refs to generate and throw an error message with title IDS_ERR_TITLE (see string table in resources) // Also if compiled with DEBUG, will log the message with DebugWrite // uID the string table ref to display // dwError if nonzero, will display a Windows error message using FormatMessage (for use when an API function fails) // fUserChoose if true, display buttons Retry and Cancel. if false, display single button OK. // for fUserChoose==true; ErrorMessage returns true if user selects Retry, and false if user selects Cancel. // for fUserChoose==false; ErrorMessage always returns false. bool ErrorMessage( UINT uID, DWORD dwError, bool fUserChoose ) { TCHAR pszFirstLine[DEFAULT_BUFFER]; bool fReturn = false; int iBytes; TCHAR szError[512]; TCHAR tszErrorTitle[DEFAULT_BUFFER]; LoadString( g_hResourceDLL, uID, pszFirstLine, DEFAULT_BUFFER ); LoadString( g_hResourceDLL, IDS_ERR_TITLE, tszErrorTitle, DEFAULT_BUFFER ); if( dwError ) { iBytes = wsprintf( szError, _T("%s\n\n Error description: "), pszFirstLine ); FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError , 0, &szError[iBytes], sizeof(szError) - iBytes, NULL ); } else lstrcpyn( szError, pszFirstLine, 512 ); DebugWrite(_T("ErrorMessage! ID:%d "), uID); DebugFlush(); if( fUserChoose ) fReturn = MessageBox( g_strEmuInfo.hMainWindow, szError, tszErrorTitle, MB_RETRYCANCEL | MB_ICONERROR ) == IDRETRY; else MessageBox( g_strEmuInfo.hMainWindow, szError, tszErrorTitle, MB_OK | MB_ICONERROR ); DebugWriteA(fReturn ? "(user: retry)\n" : "(user: acknowledge)\n"); return fReturn; }
// Post a message box, using string resource uTextID and MessageBox style uType int WarningMessage( UINT uTextID, UINT uType ) { DebugWriteA("WarningMessage: ID:%d Type:%d\n", uTextID, uType); DebugFlush(); TCHAR tszTitle[DEFAULT_BUFFER], tszText[DEFAULT_BUFFER]; LoadString( g_hResourceDLL, uTextID, tszText, DEFAULT_BUFFER ); LoadString( g_hResourceDLL, IDS_DLG_WARN_TITLE, tszTitle, DEFAULT_BUFFER ); return MessageBox( g_strEmuInfo.hMainWindow, tszText, tszTitle, uType ); }
/****************************************************************** Function: GetDllInfo Purpose: This function allows the emulator to gather information about the dll by filling in the PluginInfo structure. input: a pointer to a PLUGIN_INFO stucture that needs to be filled by the function. (see def above) output: none *******************************************************************/ EXPORT void CALL GetDllInfo ( PLUGIN_INFO* PluginInfo ) { DebugWriteA("CALLED: GetDllInfo\n"); strncpy(PluginInfo->Name, STRING_PLUGINNAME " " VERSIONNUMBER #ifndef _UNICODE "-ANSI" #endif #ifdef _DEBUG "-Debugbuild" #endif , sizeof(PluginInfo->Name)); PluginInfo->Type = PLUGIN_TYPE_CONTROLLER; PluginInfo->Version = SPECS_VERSION; }
// Done bool ReadCartNorm(LPGBCART Cart, WORD dwAddress, BYTE *Data) // For all non-MBC carts; fixed 0x8000 ROM; fixed, optional 0x2000 RAM { switch (dwAddress >> 13) // hack: examine highest 3 bits { case 0: case 1: case 2: case 3: // if ((dwAddress >= 0) && (dwAddress <= 0x7FFF)) CopyMemory(Data, &Cart->RomData[dwAddress], 32); DebugWriteA("Nonbanked ROM read - RAW\n"); break; case 5: if (Cart->bHasRam) // no MBC, so no enable state to check { if (Cart->RomData[0x149] == 1 && (dwAddress - 0xA000) / 0x0800 ) // Only 1/4 of the RAM space is used, and we're out of bounds { DebugWriteA("Failed RAM read: Unbanked (out of bounds)"); ZeroMemory(Data, 32); } else { CopyMemory(Data, &Cart->RamData[dwAddress - 0xA000], 32); DebugWriteA("RAM read: Unbanked\n"); } } else { ZeroMemory(Data, 32); DebugWriteA("Failed RAM read: Unbanked (RAM not present)\n"); } break; default: DebugWriteA("Bad read from RAW cart, address %04X\n", dwAddress); } return true; }
// Done bool ReadCartMBC1(LPGBCART Cart, WORD dwAddress, BYTE *Data) { if ((dwAddress >= 0) && (dwAddress <= 0x3FFF)) { CopyMemory(Data, &Cart->RomData[dwAddress], 32); DebugWriteA("Nonbanked ROM read - MBC1\n"); } else if ((dwAddress >= 0x4000) && (dwAddress <= 0x7FFF)) { if (Cart->iCurrentRomBankNo >= Cart->iNumRomBanks) { ZeroMemory(Data, 32); DebugWriteA("Banked ROM read: (Banking Error) Bank %02X\n", Cart->iCurrentRomBankNo); } else { // for (i=0; i<32; i++) Data[i] = Cart->RomData[(dwAddress - 0x4000) + i + (Cart->iCurrentRomBankNo * 0x4000)]; CopyMemory(Data, &Cart->RomData[dwAddress - 0x4000 + (Cart->iCurrentRomBankNo << 14)], 32); DebugWriteA("Banked ROM read: Bank %02X\n", Cart->iCurrentRomBankNo); } } else if ((dwAddress >= 0xA000) && (dwAddress <= 0xBFFF)) { if (Cart->bHasRam/* && Cart->bRamEnableState)*/) { if (Cart->iCurrentRamBankNo >= Cart->iNumRamBanks) { ZeroMemory(Data, 32); DebugWriteA("Failed RAM read: (Banking Error) %02X\n", Cart->iCurrentRamBankNo); } else { CopyMemory(Data, &Cart->RamData[dwAddress - 0xA000 + (Cart->iCurrentRamBankNo << 13)], 32); DebugWriteA("RAM read: Bank %02X\n", Cart->iCurrentRamBankNo); } } else { ZeroMemory(Data, 32); DebugWriteA("Failed RAM read: (RAM not present)\n"); } } else { DebugWriteA("Bad read from MBC1 cart, address %04X\n", dwAddress); } return true; }
/****************************************************************** Function: CloseDLL Purpose: This function is called when the emulator is closing down allowing the dll to de-initialise. input: none output: none *******************************************************************/ EXPORT void CALL CloseDLL (void) { // HACK: THIS IS BROKEN IN PJ64 1.6 (it calls CloseDLL too often) DebugWriteA("CALLED: CloseDLL\n"); if( g_bRunning ) RomClosed(); for( int i = 0; i < 4; i++ ) { freePakData( &g_pcControllers[i] ); freeModifiers( &g_pcControllers[i] ); } // ZeroMemory( g_pcControllers, sizeof(g_pcControllers) ); // why zero the memory if we're just going to close down? FreeDirectInput(); return; }
/****************************************************************** Function: RomOpen Purpose: This function is called when a rom is open. (from the emulation thread) input: none output: none *******************************************************************/ EXPORT void CALL RomOpen (void) { DebugWriteA("CALLED: RomOpen\n"); XInputEnable( TRUE ); // enables xinput --tecnicors if( !g_strEmuInfo.fInitialisedPlugin ) { ErrorMessage(IDS_ERR_NOINIT, 0, false); return; } EnterCriticalSection( &g_critical ); // re-init our paks and shortcuts InitiatePaks( true ); // LoadShortcuts( &g_scShortcuts ); WHY are we loading shortcuts again?? Should already be loaded! LeaveCriticalSection( &g_critical ); g_bRunning = true; return; }
HRESULT ReadAdaptoidPak( LPDIRECTINPUTDEVICE8 lpDirectInputDevice, DWORD addr, LPBYTE data ) { DIEFFESCAPE esc; esc.dwSize = sizeof(esc); esc.dwCommand = ADAPT_READPAK; // Read 32 bytes from pak esc.lpvInBuffer = &addr; esc.cbInBuffer = 4; esc.lpvOutBuffer = data; esc.cbOutBuffer = 32; HRESULT hr = lpDirectInputDevice->Escape(&esc); #ifdef _DEBUG LPCSTR suc = (SUCCEEDED(hr)) ? "OK" : "FAILED"; DebugWriteA( "Direct Adaptoid ReadPak(Addr:%04X): %s (RC:%08X)\n", addr, suc, hr ); #endif // #ifdef _DEBUG return hr; }
/****************************************************************** Function: DllAbout Purpose: This function is optional function that is provided to give further information about the DLL. input: a handle to the window that calls this function output: none *******************************************************************/ EXPORT void CALL DllAbout ( HWND hParent ) { DebugWriteA("CALLED: DllAbout\n"); TCHAR tszTitle[DEFAULT_BUFFER], tszTranslator[DEFAULT_BUFFER]; LoadString( g_hResourceDLL, IDS_DLG_ABOUT_TITLE, tszTitle, DEFAULT_BUFFER ); TCHAR szText[DEFAULT_BUFFER * 4] = _T(STRING_PLUGINNAME) _T("\n\n") \ _T("Visit my site for support: >>http://go.to/nrage<<\n\n") \ _T("Version ") VERSIONINFO _T(" (") _T(__DATE__) _T(")\n") \ _T("Done by N-Rage\n") \ _T("\n") \ _T(" - - - - -\n") \ _T("Transferpak emulation done by MadManMarkAu\n") \ _T("Cleanup, tweaks, and language support by RabidDeity\n"); LoadString( g_hResourceDLL, IDS_DLG_ABOUT, tszTranslator, DEFAULT_BUFFER ); _tcscat(szText, tszTranslator); MessageBox( hParent, szText, tszTitle, MB_OK | MB_ICONINFORMATION); return; }
void UpdateRTC(LPGBCART Cart) { time_t now, dif; int days; now = time(NULL); dif = now - Cart->timerLastUpdate; Cart->TimerData[0] += (BYTE)(dif % 60); dif /= 60; Cart->TimerData[1] += (BYTE)(dif % 60); dif /= 60; Cart->TimerData[2] += (BYTE)(dif % 24); dif /= 24; days = Cart->TimerData[3] + ((Cart->TimerData[4] & 1) << 8) + (int)dif; Cart->TimerData[3] = (days & 0xFF); if(days > 255) { if(days > 511) { days &= 511; Cart->TimerData[4] |= 0x80; } if (days > 255) Cart->TimerData[4] = (Cart->TimerData[4] & 0xFE) | (days > 255 ? 1 : 0); } Cart->timerLastUpdate = now; DebugWriteA("Update RTC: "); DebugWriteByteA(Cart->TimerData[0]); DebugWriteA(":"); DebugWriteByteA(Cart->TimerData[1]); DebugWriteA(":"); DebugWriteByteA(Cart->TimerData[2]); DebugWriteA(":"); DebugWriteByteA(Cart->TimerData[3]); DebugWriteA(":"); DebugWriteByteA(Cart->TimerData[4]); DebugWriteA("\n"); }
/****************************************************************** Function: InitiateControllers Purpose: This function initialises how each of the controllers should be handled. input: - A controller structure that needs to be filled for the emulator to know how to handle each controller. output: none *******************************************************************/ EXPORT void CALL InitiateControllers (CONTROL_INFO ControlInfo) #endif // SPECS_VERSION { DebugWriteA("CALLED: InitiateControllers\n"); if( !prepareHeap()) return; #if SPECS_VERSION == 0x0100 g_strEmuInfo.hMainWindow = hMainWindow; // g_strEmuInfo.HEADER = NULL; #elif SPECS_VERSION >= 0x0101 g_strEmuInfo.hMainWindow = ControlInfo.hMainWindow; // g_strEmuInfo.MemoryBswaped = ControlInfo.MemoryBswaped; // g_strEmuInfo.HEADER = ControlInfo.HEADER; // UNDONE: Instead of just storing the header, figure out what ROM we're running and save that information somewhere #endif // SPECS_VERSION // The emulator expects us to tell what controllers are plugged in and what their paks are at this point. if( !g_pDIHandle ) // if we don't have a directinput handle, we need to make one, attach it to the main window (so it will die if our emulator dies), and enumerate devices { if( InitDirectInput( g_strEmuInfo.hMainWindow )) { EnterCriticalSection ( &g_critical ); InitMouse(); g_pDIHandle->EnumDevices( DI8DEVCLASS_ALL, EnumMakeDeviceList, NULL, DIEDFL_ATTACHEDONLY ); LeaveCriticalSection ( &g_critical ); DebugWriteA("InitDirectInput run in InitiateControllers, g_nDevices=%d\n", g_nDevices); } else return; } int iDevice; EnterCriticalSection( &g_critical ); // ZeroMemory( g_apFFDevice, sizeof(g_apFFDevice) ); // NO, we'll reinit the existing reference if it's already loaded // ZeroMemory( g_apdiEffect, sizeof(g_apdiEffect) ); // NO, we'll release it with CloseControllerPak for( int i = 3; i >= 0; i-- ) { SaveControllerPak( i ); CloseControllerPak( i ); // freePakData( &g_pcControllers[i] ); // already called by CloseControllerPak freeModifiers( &g_pcControllers[i] ); SetControllerDefaults( &g_pcControllers[i] ); } g_pcControllers[0].fPlugged = true; if (! LoadConfigFromINI() ) { DebugWriteA("\tINI load failed, loading defaults from resource\n"); for ( int i = 0; i < 4; i++ ) LoadProfileFromResource( i, false ); LoadShortcutsFromResource(false); } for( int i = 0; i < 4; i++) // initiate xinput controller and plug then if connected --tecnicors { InitiateXInputController( &g_pcControllers[i].xiController, i ); if( g_pcControllers[i].xiController.bConnected ) { g_pcControllers[i].fPlugged = true; g_pcControllers[i].fGamePad = true; } } // END // Init: Find force-feedback devices and init for( int i = 3; i >= 0; i-- ) { DebugWriteA("Controller %d: ", i+1); if( g_pcControllers[i].xiController.bConnected && g_pcControllers[i].fXInput) // if xinput connected, we don't need other config --tecnicors continue; if( g_pcControllers[i].fPlugged ) { // Search for right Controller iDevice = FindDeviceinList( g_pcControllers[i].guidFFDevice ); if( iDevice != -1 && g_devList[iDevice].bEffType ) { DebugWriteA("rumble device set, "); } else // we couldn't find the device specified in the INI file, or it was already null { g_pcControllers[i].guidFFDevice = GUID_NULL; DebugWriteA("no rumble device/effect type set, "); } if( g_pcControllers[i].nModifiers > 0) SetModifier( &g_pcControllers[i] ); g_iFirstController = i; DebugWriteA("plugged in, with paktype %d, ", g_pcControllers[i].PakType); DebugWriteA("RawMode is %d\n", g_pcControllers[i].fRawData); } else { DebugWriteA("unplugged\n"); freePakData( &g_pcControllers[i] ); // we don't need to do this again, but there's not much overhead so I'll leave it --rabid freeModifiers( &g_pcControllers[i] ); } } PrepareInputDevices(); if( g_bExclusiveMouse ) { // g_sysMouse.didHandle->Unacquire(); // g_sysMouse.didHandle->SetCooperativeLevel( g_strEmuInfo.hMainWindow, DIB_MOUSE ); // PrepareInputDevices does this. g_sysMouse.didHandle->Acquire(); } InitiatePaks( true ); g_strEmuInfo.fInitialisedPlugin = true; LeaveCriticalSection( &g_critical ); #if SPECS_VERSION == 0x0100 FillControls(Controls); #elif SPECS_VERSION >= 0x0101 FillControls(ControlInfo.Controls); #endif // SPECS_VERSION return; } // end InitiateControllers
/****************************************************************** Function: DllTest Purpose: This function is optional function that is provided to allow the user to test the dll input: a handle to the window that calls this function output: none *******************************************************************/ EXPORT void CALL DllTest ( HWND hParent ) { DebugWriteA("CALLED: DllTest\n"); return; }
/****************************************************************** Function: DllConfig Purpose: This function is optional function that is provided to allow the user to configure the dll input: a handle to the window that calls this function output: none *******************************************************************/ EXPORT void CALL DllConfig ( HWND hParent ) { DebugWriteA("CALLED: DllConfig\n"); static bool bInitCC = false; if( !prepareHeap()) return; if( !g_pDIHandle ) { if( InitDirectInput( hParent )) { EnterCriticalSection ( &g_critical ); InitMouse(); g_pDIHandle->EnumDevices( DI8DEVCLASS_ALL, EnumMakeDeviceList, NULL, DIEDFL_ATTACHEDONLY ); LeaveCriticalSection ( &g_critical ); DebugWriteA("InitDirectInput run in DllConfig, g_nDevices=%d\n", g_nDevices); } } if( g_pDIHandle && !g_bConfiguring ) { g_bConfiguring = true; if( !bInitCC ) { INITCOMMONCONTROLSEX ccCtrls = { sizeof(INITCOMMONCONTROLSEX), ICC_BAR_CLASSES | ICC_TAB_CLASSES | ICC_LISTVIEW_CLASSES }; InitCommonControlsEx( &ccCtrls ); // needed for TrackBars & Tabs } EnterCriticalSection( &g_critical ); if( g_sysMouse.didHandle ) { // unlock mouse while configuring g_sysMouse.didHandle->SetCooperativeLevel( g_strEmuInfo.hMainWindow, DIB_DEVICE ); g_sysMouse.didHandle->Acquire(); } LeaveCriticalSection( &g_critical ); int iOK = DialogBox( g_hResourceDLL, MAKEINTRESOURCE( IDD_MAINCFGDIALOG ), hParent, MainDlgProc ); // If we go into the dialog box, and the user navigates to the Rumble window, our FF device can get unacquired. // So let's reinit them now if we're running, just to be safe --rabid if( g_bRunning ) { EnterCriticalSection( &g_critical ); // PrepareInputDevices resets g_bExclusiveMouse to false if no mouse keys are bound, and the only way to // re-enable exclusive mouse is with a shortcut. // This is undesirable behavior, but it beats the alternative (and we REALLY need to re-init FF devices here) PrepareInputDevices(); if (iOK) { InitiatePaks( false ); // only re-init the mempaks and such if the user clicked Save or Use } if( g_sysMouse.didHandle ) { if ( g_bExclusiveMouse ) { // if we have exclusive mouse, we need to relock mouse after closing the config g_sysMouse.didHandle->SetCooperativeLevel( g_strEmuInfo.hMainWindow, DIB_MOUSE ); g_sysMouse.didHandle->Acquire(); if (g_strEmuInfo.fDisplayShortPop) { LoadString( g_hResourceDLL, IDS_POP_MOUSELOCKED, g_pszThreadMessage, ARRAYSIZE(g_pszThreadMessage) ); // HWND hMessage = CreateWindowEx( WS_EX_NOPARENTNOTIFY | WS_EX_STATICEDGE | WS_EX_TOPMOST, _T("STATIC"), pszMessage, WS_CHILD | WS_VISIBLE, 10, 10, 200, 30, g_strEmuInfo.hMainWindow, NULL, g_strEmuInfo.hinst, NULL ); // SetTimer( hMessage, TIMER_MESSAGEWINDOW, 2000, MessageTimer ); CreateThread(NULL, 0, MsgThreadFunction, g_pszThreadMessage, 0, NULL); } } else { g_sysMouse.didHandle->SetCooperativeLevel( g_strEmuInfo.hMainWindow, DIB_KEYBOARD ); g_sysMouse.didHandle->Acquire(); } } LeaveCriticalSection( &g_critical ); } g_bConfiguring = false; } return; }
// Create a force feedback effect handle and downloads the effect. Parameters are self-explanatory. bool CreateEffectHandle( HWND hWnd, LPDIRECTINPUTDEVICE8 lpDirectInputDevice, LPDIRECTINPUTEFFECT &pDIEffect, BYTE bRumbleTyp, long lStrength ) { if( pDIEffect ) ReleaseEffect( pDIEffect ); if( !lpDirectInputDevice || bRumbleTyp == RUMBLE_DIRECT ) return false; DWORD nAxes = 0; DWORD rgdwAxes[] = { DIJOFS_X, DIJOFS_Y }; HRESULT hResult; // count the FF - axes of the joystick lpDirectInputDevice->EnumObjects( EnumCountFFAxes, &nAxes, DIDFT_FFACTUATOR | DIDFT_AXIS ); if( nAxes == 0 ) return false; nAxes = min( nAxes, 2 ); // Must be unaquired for setting stuff like Co-op Level hResult = lpDirectInputDevice->Unacquire(); //FF Requires EXCLUSIVE LEVEL, took me hours to find the reason why it wasnt working hResult = lpDirectInputDevice->SetCooperativeLevel( hWnd, DIB_FF ); // fail if we can't set coop level --rabid if (hResult != DI_OK) { DebugWriteA("CreateEffectHandle: couldn't set coop level: %08X\n", hResult); return false; } // Since we will be playing force feedback effects, we should disable the // auto-centering spring. DIPROPDWORD dipdw; dipdw.diph.dwSize = sizeof(DIPROPDWORD); dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); dipdw.diph.dwObj = 0; dipdw.diph.dwHow = DIPH_DEVICE; dipdw.dwData = FALSE; hResult = lpDirectInputDevice->SetProperty( DIPROP_AUTOCENTER, &dipdw.diph ); long rglDirection[] = { 1, 1 }; LPGUID EffectGuid; DIEFFECT eff; ZeroMemory( &eff, sizeof(eff) ); eff.dwSize = sizeof(DIEFFECT); eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; eff.dwGain = lStrength * 100; eff.dwTriggerButton = DIEB_NOTRIGGER; eff.dwTriggerRepeatInterval = 0; eff.cAxes = nAxes; //Number of Axes eff.rgdwAxes = rgdwAxes; eff.rglDirection = rglDirection; eff.lpEnvelope = NULL; eff.dwStartDelay = 0; DICONSTANTFORCE cf; DIRAMPFORCE rf; DIPERIODIC pf; switch( bRumbleTyp ) { case RUMBLE_CONSTANT: EffectGuid = (GUID*)&GUID_ConstantForce; eff.dwDuration = 150000; // microseconds eff.dwSamplePeriod = 0; eff.cbTypeSpecificParams = sizeof(DICONSTANTFORCE); eff.lpvTypeSpecificParams = &cf; cf.lMagnitude = 10000; break; case RUMBLE_RAMP: EffectGuid = (GUID*)&GUID_RampForce; eff.dwDuration = 300000; // microseconds eff.dwSamplePeriod = 0; eff.cbTypeSpecificParams = sizeof(DIRAMPFORCE); eff.lpvTypeSpecificParams = &rf; rf.lStart = 10000; rf.lEnd = 2000; break; case RUMBLE_CONDITION: case RUMBLE_PERIODIC: EffectGuid = (GUID*)&GUID_Sine; eff.dwDuration = 150000; // microseconds eff.dwSamplePeriod = 0; eff.cbTypeSpecificParams = sizeof(DIPERIODIC); eff.lpvTypeSpecificParams = &pf; pf.dwMagnitude = 10000; pf.lOffset = 0; pf.dwPhase = 0; pf.dwPeriod = 2000; break; case RUMBLE_NONE: case RUMBLE_CUSTOM: default: return false; } hResult = lpDirectInputDevice->CreateEffect( *EffectGuid, &eff, &pDIEffect, NULL ); if (hResult == DI_OK) { hResult = lpDirectInputDevice->Acquire(); hResult = pDIEffect->Download(); } else { DebugWriteA("CreateEffectHandle: didn't CreateEffect: %08X\n", hResult); } return SUCCEEDED( hResult ); }
// **if passed an existing DirectInputDevice which matches gGuid // unacquires it, and sets its cooperative level (reinitialize) // **if the existing device does not match the passed gGuid, the existing device is released // **if no device was passed or gGuid did not match // searches for the controller matching gGuid in connected and available devices // creates a DirectInputDevice // sets its data format // sets its cooperative level // for joysticks, calls EnumSetObjectsAxis for each axis // GetInputDevice always leaves the returned device in an UNACQUIRED state. bool GetInputDevice( HWND hWnd, LPDIRECTINPUTDEVICE8 &lpDirectInputDevice, GUID gGuid, DWORD dwDevType, DWORD dwCooperativeLevel ) { DebugWriteA("GetInputDevice: gGuid is {%08.8lX-%04.4hX-%04.4hX-%02.2X%02.2X-%02.2X%02.2X%02.2X%02.2X%02.2X%02.2X}\n", gGuid.Data1, gGuid.Data2, gGuid.Data3, gGuid.Data4[0], gGuid.Data4[1], gGuid.Data4[2], gGuid.Data4[3], gGuid.Data4[4], gGuid.Data4[5], gGuid.Data4[6], gGuid.Data4[7]); if( lpDirectInputDevice != NULL) { DIDEVICEINSTANCE didDev; didDev.dwSize = sizeof(DIDEVICEINSTANCE); lpDirectInputDevice->GetDeviceInfo( &didDev ); if( didDev.guidInstance == gGuid ) { // we've already gotten this device; unacquire it and initialize DebugWriteA("GetInputDevice: already created, attempting to reinit\n"); lpDirectInputDevice->Unacquire(); lpDirectInputDevice->SetCooperativeLevel( hWnd, dwCooperativeLevel ); return true; } else ReleaseDevice( lpDirectInputDevice ); } HRESULT hResult; LPCDIDATAFORMAT ppDiDataFormat = NULL; bool Success = false; switch( LOBYTE(dwDevType) ) { case DI8DEVTYPE_KEYBOARD: ppDiDataFormat = &c_dfDIKeyboard; break; case DI8DEVTYPE_MOUSE: ppDiDataFormat = &c_dfDIMouse2; break; //case DI8DEVTYPE_GAMEPAD: //case DI8DEVTYPE_JOYSTICK: //case DI8DEVTYPE_DRIVING: //case DI8DEVTYPE_1STPERSON: //case DI8DEVTYPE_FLIGHT: default: // assume everything else is a gamepad; probably not the best idea but it works ppDiDataFormat = &c_dfDIJoystick; break; } bool bDeviceAvailable = false; VOID* aRef[2] = { &gGuid, &bDeviceAvailable }; // for each available device in our dwDevType category, run EnumIsDeviceAvailable with params "aRef" g_pDIHandle->EnumDevices( DI8DEVCLASS_ALL, EnumIsDeviceAvailable, (LPVOID)aRef, DIEDFL_ATTACHEDONLY ); if( !bDeviceAvailable ) { DebugWriteA("GetInputDevice: Device does not appear available\n"); return false; } hResult = g_pDIHandle->CreateDevice( gGuid, &lpDirectInputDevice, NULL ); if( SUCCEEDED( hResult )) { hResult = lpDirectInputDevice->SetDataFormat( ppDiDataFormat ); hResult = lpDirectInputDevice->SetCooperativeLevel( hWnd, dwCooperativeLevel ); Success = SUCCEEDED( hResult ); if (!Success) { DebugWriteA("GetInputDevice: SetCooperativeLevel failed\n"); } } else DebugWriteA("GetInputDevice: CreateDevice failed\n"); if( Success && ( ppDiDataFormat == &c_dfDIJoystick )) lpDirectInputDevice->EnumObjects( EnumSetObjectsAxis, lpDirectInputDevice, DIDFT_AXIS ); return Success; }
/****************************************************************** Function: ReadController Purpose: To process the raw data in the pif ram that is about to be read. input: - Controller Number (0 to 3) and -1 signalling end of processing the pif ram. - Pointer of data to be processed. output: none note: This function is only needed if the DLL is allowing raw data. *******************************************************************/ EXPORT void CALL ReadController( int Control, BYTE * Command ) { #ifdef ENABLE_RAWPAK_DEBUG DebugWriteA("CALLED: ReadController\n"); #endif if( Control == -1 ) return; EnterCriticalSection( &g_critical ); if( !g_pcControllers[Control].fPlugged ) { Command[1] |= RD_ERROR; LeaveCriticalSection( &g_critical ); return; } switch( Command[2] ) { case RD_RESETCONTROLLER: WriteDatasA( "ResetController-PreProcessing", Control, Command, 0); case RD_GETSTATUS: // expected: controller gets 1 byte (command), controller sends back 3 bytes // should be: Command[0] == 0x01 // Command[1] == 0x03 #ifdef ENABLE_RAWPAK_DEBUG WriteDatasA( "GetStatus-PreProcessing", Control, Command, 0); #endif Command[3] = RD_GAMEPAD | RD_ABSOLUTE; Command[4] = RD_NOEEPROM; if( g_pcControllers[Control].fPakInitialized && g_pcControllers[Control].pPakData ) { if( *(BYTE*)g_pcControllers[Control].pPakData == PAK_ADAPTOID ) { Command[5] = GetAdaptoidStatus( Control ); if( Command[5] & RD_NOTINITIALIZED ) ((ADAPTOIDPAK*)g_pcControllers[Control].pPakData)->fRumblePak = true; } else { Command[5] = ( *(BYTE*)g_pcControllers[Control].pPakData != PAK_NONE ) ? RD_PLUGIN : RD_NOPLUGIN; if( g_pcControllers[Control].fPakCRCError ) { Command[5] = Command[5] | RD_ADDRCRCERR; g_pcControllers[Control].fPakCRCError = false; } } } else { if( !g_bConfiguring && InitControllerPak( Control ) && g_pcControllers[Control].pPakData ) { g_pcControllers[Control].fPakInitialized = true; if( *(BYTE*)g_pcControllers[Control].pPakData == PAK_ADAPTOID ) Command[5] = GetAdaptoidStatus( Control ); else { Command[5] = ( *(BYTE*)g_pcControllers[Control].pPakData ) ? RD_PLUGIN : RD_NOPLUGIN; Command[5] = Command[5] | ( g_pcControllers[Control].fPakCRCError ? RD_ADDRCRCERR : 0 ); } } else Command[5] = RD_NOPLUGIN | RD_NOTINITIALIZED; } if( g_pcControllers[Control].fPakCRCError ) { Command[5] = Command[5] | RD_ADDRCRCERR; g_pcControllers[Control].fPakCRCError = false; } #ifdef ENABLE_RAWPAK_DEBUG WriteDatasA( "GetStatus-PostProcessing", Control, Command, 0); DebugWriteA( NULL ); #endif break; case RD_READKEYS: // expected: controller gets 1 byte (command), controller sends back 4 bytes // should be: Command[0] == 0x01 // Command[1] == 0x04 if( g_bConfiguring ) Command[3] = Command[4] = Command[5] = Command[6] = 0; else { if (Control == g_iFirstController ) { GetDeviceDatas(); CheckShortcuts(); } if( g_pcControllers[Control].xiController.bConnected && g_pcControllers[Control].fXInput ) // reads xinput controller kesy, if connected --tecnicors GetXInputControllerKeys( &g_pcControllers[Control].xiController, (LPDWORD)&Command[3] ); else GetNControllerInput( Control, (DWORD*)&Command[3] ); } break; case RD_READPAK: #ifdef ENABLE_RAWPAK_DEBUG WriteDatasA( "ReadPak-PreProcessing", Control, Command, 0); #endif if( g_pcControllers[Control].fPakInitialized ) //Command[1] = Command[1] | ReadControllerPak( Control, &Command[3] ); ReadControllerPak( Control, &Command[3] ); else { DebugWriteA("Tried to read, but pak wasn't initialized!!\n"); // InitControllerPak( Control ); Command[1] |= RD_ERROR; //ZeroMemory( &Command[5], 32 ); } #ifdef ENABLE_RAWPAK_DEBUG WriteDatasA( "ReadPak-PostProcessing", Control, Command, 0); DebugWriteA( NULL ); #endif break; case RD_WRITEPAK: #ifdef ENABLE_RAWPAK_DEBUG WriteDatasA( "WritePak-PreProcessing", Control, Command, 0); #endif if( g_pcControllers[Control].fPakInitialized ) //Command[1] = Command[1] | WriteControllerPak( Control, &Command[3] ); WriteControllerPak( Control, &Command[3] ); else { DebugWriteA("Tried to write, but pak wasn't initialized! (paktype was %u)\n", g_pcControllers[Control].PakType); // InitControllerPak( Control ); Command[1] |= RD_ERROR; } #ifdef ENABLE_PAK_WRITES_DEBUG WriteDatasA( "WritePak-PostProcessing", Control, Command, 0); DebugWriteA( NULL ); #endif break; case RD_READEEPROM: // Should be handled by the Emulator WriteDatasA( "ReadEeprom-PreProcessing", Control, Command, 0); WriteDatasA( "ReadEeprom-PostProcessing", Control, Command, 0); DebugWriteA( NULL ); break; case RD_WRITEEPROM: // Should be handled by the Emulator WriteDatasA( "WriteEeprom-PreProcessing", Control, Command, 0); WriteDatasA( "WriteEeprom-PostProcessing", Control, Command, 0); DebugWriteA( NULL ); break; default: // only accessible if the Emulator has bugs.. or maybe the Rom is flawed WriteDatasA( "ReadController: Bad read", Control, Command, 0); DebugWriteA( NULL ); Command[1] = Command[1] | RD_ERROR; } LeaveCriticalSection( &g_critical ); return; }
// Direct Adaptoid debugging stuff. void _debugAd( LPCSTR szMessage, HRESULT res ) { LPCSTR suc = (SUCCEEDED(res)) ? "OK" : "FAILED"; DebugWriteA( "%s: %s (RC:%08X)\n", szMessage, suc, res ); }
// Fill in button states and axis states for controller indexController, into the struct pdwData. // pdwData is a pointer to a 4 byte BUTTONS union, if anyone cares bool GetNControllerInput ( const int indexController, LPDWORD pdwData ) { *pdwData = 0; WORD w_Buttons = 0; // WORD w_Axes = 0; LPCONTROLLER pcController = &g_pcControllers[indexController]; // still needs to be here, but not as important --rabid bool b_Value; long l_Value = 0; long lAxisValueX = ZEROVALUE; long lAxisValueY = ZEROVALUE; // take this info from the N64 controller struct, regardless of input devices float d_ModifierX = (float)pcController->bStickRange / 100.0f; float d_ModifierY = (float)pcController->bStickRange / 100.0f; int i; // do N64-Buttons / modifiers for (i = 0; i < pcController->nModifiers; i++ ) { BUTTON btnButton = pcController->pModifiers[i].btnButton; b_Value = IsBtnPressed( btnButton ); bool fChangeMod = false; if( pcController->pModifiers[i].bModType == MDT_CONFIG ) { // Config-Type if( pcController->pModifiers[i].fToggle ) { if( b_Value && !btnButton.fPrevPressed) { pcController->pModifiers[i].fStatus = !pcController->pModifiers[i].fStatus; fChangeMod = true; } } else { if( b_Value != (bool)(btnButton.fPrevPressed)) fChangeMod = true; } } else { // Move / Macro Type if( pcController->pModifiers[i].fToggle ) { if( b_Value && !btnButton.fPrevPressed ) pcController->pModifiers[i].fStatus = !pcController->pModifiers[i].fStatus; fChangeMod = ( pcController->pModifiers[i].fStatus != 0 ); } else { fChangeMod = b_Value; } } if( fChangeMod ) { switch( pcController->pModifiers[i].bModType ) { case MDT_MOVE: { LPMODSPEC_MOVE args = (LPMODSPEC_MOVE)&pcController->pModifiers[i].dwSpecific; d_ModifierX *= args->XModification / 100.0f; d_ModifierY *= args->YModification / 100.0f; } break; case MDT_MACRO: { LPMODSPEC_MACRO args = (LPMODSPEC_MACRO)&pcController->pModifiers[i].dwSpecific; if (args->fRapidFire) // w00t! Rapid Fire here { if ((unsigned) b_Value != btnButton.fPrevPressed) // New macro pressed { args->fPrevFireState = 0; args->fPrevFireState2 = 0; } if(!args->fPrevFireState) // This round, a firing is needed { w_Buttons |= args->aButtons; if( args->fAnalogRight ) lAxisValueX += MAXAXISVALUE; else if( args->fAnalogLeft ) lAxisValueX -= MAXAXISVALUE; if( args->fAnalogDown ) lAxisValueY -= MAXAXISVALUE; else if( args->fAnalogUp ) // up lAxisValueY += MAXAXISVALUE; } // Ok, update the firing counters here if (args->fRapidFireRate) // Do the rapid fire slowly { // Note that this updates State2 before State... Makes a nice slower square-wave type pulse for the update args->fPrevFireState2 = (args->fPrevFireState2 + 1) & 1; if (!args->fPrevFireState2) { args->fPrevFireState = (args->fPrevFireState + 1) & 1; DebugWriteA("Slow Rapid Fire - Mark 2\n"); } } else // Do a fast rapid fire { args->fPrevFireState = (args->fPrevFireState + 1) & 1; DebugWriteA("Fast Rapid Fire\n"); } } else { w_Buttons |= args->aButtons; // Note this: It lets you push buttons as well as the macro buttons if( args->fAnalogRight ) lAxisValueX += MAXAXISVALUE; else if( args->fAnalogLeft ) lAxisValueX -= MAXAXISVALUE; if( args->fAnalogDown ) lAxisValueY -= MAXAXISVALUE; else if( args->fAnalogUp ) // up lAxisValueY += MAXAXISVALUE; args->fPrevFireState = 0; } } break; case MDT_CONFIG: { LPMODSPEC_CONFIG args = (LPMODSPEC_CONFIG)&pcController->pModifiers[i].dwSpecific; if( args->fChangeAnalogConfig ) { BYTE bConfig = (BYTE)args->fAnalogStickMode; if( bConfig < PF_AXESETS ) pcController->bAxisSet = bConfig; else { if( pcController->bAxisSet == PF_AXESETS-1 ) pcController->bAxisSet = 0; else ++pcController->bAxisSet; } } if( args->fChangeMouseXAxis ) if (pcController->bMouseMoveX == MM_BUFF) pcController->bMouseMoveX = MM_ABS; else if (pcController->bMouseMoveX == MM_ABS) pcController->bMouseMoveX = MM_BUFF; if( args->fChangeMouseYAxis ) if (pcController->bMouseMoveY == MM_BUFF) pcController->bMouseMoveY = MM_ABS; else if (pcController->bMouseMoveY == MM_ABS) pcController->bMouseMoveY = MM_BUFF; if( args->fChangeKeyboardXAxis ) pcController->fKeyAbsoluteX = !pcController->fKeyAbsoluteX; if( args->fChangeKeyboardYAxis ) pcController->fKeyAbsoluteY = !pcController->fKeyAbsoluteY; } break; } } btnButton.fPrevPressed = b_Value; pcController->pModifiers[i].btnButton = btnButton; } // END N64 MODIFIERS for // do N64-Buttons / modifiers for( i = 0; i < PF_APADR; i++ ) { BUTTON btnButton = pcController->aButton[i]; b_Value = IsBtnPressed( btnButton ); w_Buttons |= (((WORD)b_Value) << i); } // END N64 BUTTONS for long lDeadZoneValue = pcController->bPadDeadZone * RANGERELATIVE / 100; float fDeadZoneRelation = (float)RANGERELATIVE / (float)( RANGERELATIVE - lDeadZoneValue ); // do N64 joystick axes for ( i = 0; i < 4; i++ ) { // 0 : right // 1 : left // 2 : down // 3 : up bool fNegInput = (( i == 1 ) || ( i == 2 )); // Input has to be negated BUTTON btnButton = pcController->aButton[PF_APADR + pcController->bAxisSet * 4 + i]; LPLONG plRawState = (LPLONG)&btnButton.parentDevice->stateAs.joyState; switch( btnButton.bBtnType ) { case DT_JOYBUTTON: l_Value = MAXAXISVALUE; b_Value = ( btnButton.parentDevice->stateAs.joyState.rgbButtons[btnButton.bOffset] & 0x80 ) != 0; break; case DT_JOYSLIDER: case DT_JOYAXE: l_Value = plRawState[btnButton.bOffset] - ZEROVALUE; if( btnButton.bAxisID ) // negative Range { fNegInput = !fNegInput; b_Value = ( l_Value <= -lDeadZoneValue ); if( b_Value ) l_Value = (long) ((float)(l_Value + lDeadZoneValue ) * fDeadZoneRelation ); } else { b_Value = ( l_Value >= lDeadZoneValue ); if( b_Value ) l_Value = (long) ((float)(l_Value - lDeadZoneValue ) * fDeadZoneRelation ); } break; case DT_JOYPOV: l_Value = MAXAXISVALUE; b_Value = GetJoyPadPOV( (PDWORD)&plRawState[btnButton.bOffset] , btnButton.bAxisID ); break; case DT_KEYBUTTON: if( btnButton.parentDevice->stateAs.rgbButtons[btnButton.bOffset] & 0x80 ) { b_Value = true; if(( pcController->fKeyAbsoluteX && i < 2 ) || ( pcController->fKeyAbsoluteY && i > 1 )) { if( pcController->wAxeBuffer[i] < MAXAXISVALUE ) { l_Value = pcController->wAxeBuffer[i] = min(( pcController->wAxeBuffer[i] + N64DIVIDER*3), MAXAXISVALUE ); } else l_Value = MAXAXISVALUE; } else { if( pcController->wAxeBuffer[i] < MAXAXISVALUE ) { l_Value = pcController->wAxeBuffer[i] = min(( pcController->wAxeBuffer[i] * 2 + N64DIVIDER*5 ), MAXAXISVALUE ); } else l_Value = MAXAXISVALUE; } } else { if(( pcController->fKeyAbsoluteX && i < 2 ) || ( pcController->fKeyAbsoluteY && i > 1 )) { l_Value = pcController->wAxeBuffer[i]; b_Value = true; } else { if( pcController->wAxeBuffer[i] > N64DIVIDER ) { b_Value = true; l_Value = pcController->wAxeBuffer[i] = pcController->wAxeBuffer[i] / 2 ; } else b_Value = false; } } break; case DT_MOUSEBUTTON: l_Value = MAXAXISVALUE; b_Value = ( btnButton.parentDevice->stateAs.mouseState.rgbButtons[btnButton.bOffset] & 0x80 ) != 0; break; case DT_MOUSEAXE: if( i < 2 ) pcController->wAxeBuffer[i] += plRawState[btnButton.bOffset] * pcController->wMouseSensitivityX * MOUSESCALEVALUE; // l_Value = btnButton.parentDevice->stateAs.mouseState[btnButton.bOffset]; else pcController->wAxeBuffer[i] += plRawState[btnButton.bOffset] * pcController->wMouseSensitivityY * MOUSESCALEVALUE; // l_Value = btnButton.parentDevice->stateAs.mouseState[btnButton.bOffset]; l_Value = pcController->wAxeBuffer[i]; // wAxeBuffer is positive for axes 0 and 3 if buffer remains, else zero // wAxeBuffer is negative for axes 1 and 2 if buffer remains, else zero if(( pcController->bMouseMoveX == MM_ABS && i < 2 ) || ( pcController->bMouseMoveY == MM_ABS && i > 1 )) pcController->wAxeBuffer[i] = min( max( MINAXISVALUE, pcController->wAxeBuffer[i]) , MAXAXISVALUE); else if (( pcController->bMouseMoveX == MM_BUFF && i < 2 ) || ( pcController->bMouseMoveY == MM_BUFF && i > 1 )) pcController->wAxeBuffer[i] = pcController->wAxeBuffer[i] * MOUSEBUFFERDECAY / 100; else // "deadpan" mouse { pcController->wAxeBuffer[i] = 0; } if( btnButton.bAxisID == AI_AXE_N) // the mouse axis has the '-' flag set { fNegInput = !fNegInput; b_Value = ( l_Value < ZEROVALUE ); } else { b_Value = ( l_Value > ZEROVALUE ); } break; case DT_UNASSIGNED: default: b_Value = false; } if ( b_Value ) { if ( fNegInput ) l_Value = -l_Value; if( i < 2 ) lAxisValueX += l_Value; else lAxisValueY += l_Value; } } if( pcController->fKeyboard ) { if( pcController->fKeyAbsoluteX ) { if( pcController->wAxeBuffer[0] > pcController->wAxeBuffer[1] ) { pcController->wAxeBuffer[0] -= pcController->wAxeBuffer[1]; pcController->wAxeBuffer[1] = 0; } else { pcController->wAxeBuffer[1] -= pcController->wAxeBuffer[0]; pcController->wAxeBuffer[0] = 0; } } if( pcController->fKeyAbsoluteY ) { if( pcController->wAxeBuffer[2] > pcController->wAxeBuffer[3] ) { pcController->wAxeBuffer[2] -= pcController->wAxeBuffer[3]; pcController->wAxeBuffer[3] = 0; } else { pcController->wAxeBuffer[3] -= pcController->wAxeBuffer[2]; pcController->wAxeBuffer[2] = 0; } } } if (pcController->bRapidFireEnabled) { if (pcController->bRapidFireCounter >= pcController->bRapidFireRate) { w_Buttons = (w_Buttons & 0xFF1F); pcController->bRapidFireCounter = 0; } else { pcController->bRapidFireCounter = pcController->bRapidFireCounter + 1; } } if( pcController->fRealN64Range && ( lAxisValueX || lAxisValueY )) { long lAbsoluteX = ( lAxisValueX > 0 ) ? lAxisValueX : -lAxisValueX; long lAbsoluteY = ( lAxisValueY > 0 ) ? lAxisValueY : -lAxisValueY; long lRangeX; long lRangeY; if( lAbsoluteX > lAbsoluteY ) { lRangeX = MAXAXISVALUE; lRangeY = lRangeX * lAbsoluteY / lAbsoluteX; } else { lRangeY = MAXAXISVALUE; lRangeX = lRangeY * lAbsoluteX / lAbsoluteY; } // TODO: optimize this --rabid double dRangeDiagonal = sqrt((double)(lRangeX * lRangeX + lRangeY * lRangeY)); // __asm{ // fld fRangeDiagonal // fsqrt // fstp fRangeDiagonal // fwait // } double dRel = MAXAXISVALUE / dRangeDiagonal; *pdwData = MAKELONG(w_Buttons, MAKEWORD( (BYTE)(min( max( MINAXISVALUE, (long)(lAxisValueX * d_ModifierX * dRel )), MAXAXISVALUE) / N64DIVIDER ), (BYTE)(min( max( MINAXISVALUE, (long)(lAxisValueY * d_ModifierY * dRel )), MAXAXISVALUE) / N64DIVIDER ))); } else { *pdwData = MAKELONG(w_Buttons, MAKEWORD( (BYTE)(min( max( MINAXISVALUE, (long)(lAxisValueX * d_ModifierX )), MAXAXISVALUE) / N64DIVIDER ), (BYTE)(min( max( MINAXISVALUE, (long)(lAxisValueY * d_ModifierY )), MAXAXISVALUE) / N64DIVIDER ))); } return true; }
BOOL APIENTRY DllMain( HINSTANCE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch ( ul_reason_for_call ) { case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls( hModule ); if( !prepareHeap()) return FALSE; DebugWriteA("*** DLL Attach (" VERSIONNUMBER "-Debugbuild | built on " __DATE__ " at " __TIME__")\n"); ZeroMemory( &g_strEmuInfo, sizeof(g_strEmuInfo) ); ZeroMemory( g_devList, sizeof(g_devList) ); ZeroMemory( &g_sysMouse, sizeof(g_sysMouse) ); ZeroMemory( g_aszDefFolders, sizeof(g_aszDefFolders) ); ZeroMemory( g_aszLastBrowse, sizeof(g_aszLastBrowse) ); g_strEmuInfo.hinst = hModule; g_strEmuInfo.fDisplayShortPop = true; // display pak switching message windows by default #ifdef _UNICODE { g_strEmuInfo.Language = GetLanguageFromINI(); if ( g_strEmuInfo.Language == 0 ) { g_strEmuInfo.Language = DetectLanguage(); DebugWriteA("Autoselect language: %d\n", g_strEmuInfo.Language); } g_hResourceDLL = LoadLanguageDLL(g_strEmuInfo.Language); // HACK: it's theoretically not safe to call LoadLibraryEx from DllMain... --rabid if( g_hResourceDLL == NULL ) { g_strEmuInfo.Language = 0; g_hResourceDLL = hModule; DebugWriteA("couldn't load language DLL, falling back to defaults\n"); } } #else DebugWriteA(" (compiled in ANSI mode, language detection DISABLED.)\n"); g_strEmuInfo.Language = 0; g_hResourceDLL = hModule; #endif // #ifndef _UNICODE InitializeCriticalSection( &g_critical ); break; case DLL_THREAD_ATTACH: break; case DLL_THREAD_DETACH: break; case DLL_PROCESS_DETACH: //CloseDLL(); if (g_hResourceDLL != g_strEmuInfo.hinst) FreeLibrary(g_hResourceDLL); // HACK: it's not safe to call FreeLibrary from DllMain... but screw it DebugWriteA("*** DLL Detach\n"); CloseDebugFile(); // Moved here from CloseDll DeleteCriticalSection( &g_critical ); // Moved here from CloseDll... Heap is created from DllMain, // and now it's destroyed by DllMain... just safer code --rabid if( g_hHeap != NULL ) { HeapDestroy( g_hHeap ); g_hHeap = NULL; } break; } return TRUE; }
// 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; }
// 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); } }
// PrepareInputDevices rewritten --rabid bool PrepareInputDevices() { bool fKeyboard = false; bool fMouse = false; bool fGamePad = false; for( int i = 0; i < ARRAYSIZE( g_pcControllers ); ++i ) { fGamePad = false; if( g_pcControllers[i].fPlugged ) { CountControllerStructDevs( &g_pcControllers[i] ); fKeyboard = g_pcControllers[i].fKeyboard != 0; fMouse = g_pcControllers[i].fMouse != 0; fGamePad = ( g_pcControllers[i].fGamePad != 0); // we'll assume for now that there's a gamepad to go with those buttons } ReleaseEffect( g_apdiEffect[i] ); if( g_pcControllers[i].guidFFDevice != GUID_NULL && GetInputDevice( g_strEmuInfo.hMainWindow, g_apFFDevice[i], g_pcControllers[i].guidFFDevice, DI8DEVTYPE_JOYSTICK, DIB_FF )) // not necessarily a joystick type device, but we don't use the data anyway { DIDEVICEINSTANCE diDev; diDev.dwSize = sizeof( DIDEVICEINSTANCE ); g_apFFDevice[i]->GetDeviceInfo( &diDev ); if( !lstrcmp( diDev.tszProductName, _T( STRING_ADAPTOID ))) { g_pcControllers[i].fIsAdaptoid = true; DebugWriteA("FF device on controller %d is of type Adaptoid\n", i+1); } else { g_pcControllers[i].fIsAdaptoid = false; } if ( CreateEffectHandle( i, g_pcControllers[i].bRumbleTyp, g_pcControllers[i].bRumbleStrength ) ) { AcquireDevice( g_apFFDevice[i] ); DebugWriteA("Got FF device %d\n", i); } else DebugWriteA("Couldn't get FF device: CreateEffectHandle failed!\n"); } else { g_apFFDevice[i] = NULL; DebugWriteA("Didn't get FF device %d\n", i); } } if( fMouse ) { if( !g_sysMouse.didHandle ) { if( GetInputDevice( g_strEmuInfo.hMainWindow, g_sysMouse.didHandle, GUID_SysMouse, DI8DEVTYPE_MOUSE, g_bExclusiveMouse ? DIB_MOUSE : DIB_KEYBOARD )) { AcquireDevice( g_sysMouse.didHandle ); } } } else { g_bExclusiveMouse = false; } return true; }