From b0852c1bef073ac38d7d916a4555ce9188a03b2e Mon Sep 17 00:00:00 2001 From: "sl1nk3.s" Date: Thu, 2 Apr 2009 21:13:58 +0000 Subject: [PATCH] Updated rumble for nJoy, fixed a few glitches with half press button and deadzones too. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2840 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/InputCommon/Src/SDL.h | 1 + .../Plugin_PadSimple/Src/PadSimple.cpp | 6 +- Source/Plugins/Plugin_nJoy_SDL/Src/Config.cpp | 4 + Source/Plugins/Plugin_nJoy_SDL/Src/Config.h | 1 + .../Plugin_nJoy_SDL/Src/GUI/ConfigBox.cpp | 53 +- .../Plugin_nJoy_SDL/Src/GUI/ConfigBox.h | 11 +- .../Plugin_nJoy_SDL/Src/GUI/ConfigJoypad.cpp | 5 +- Source/Plugins/Plugin_nJoy_SDL/Src/Rumble.cpp | 508 +++++++++--------- Source/Plugins/Plugin_nJoy_SDL/Src/nJoy.cpp | 81 +-- Source/Plugins/Plugin_nJoy_SDL/Src/nJoy.h | 29 +- 10 files changed, 365 insertions(+), 334 deletions(-) diff --git a/Source/Core/InputCommon/Src/SDL.h b/Source/Core/InputCommon/Src/SDL.h index 3d6560b147..550b8cc4d0 100644 --- a/Source/Core/InputCommon/Src/SDL.h +++ b/Source/Core/InputCommon/Src/SDL.h @@ -92,6 +92,7 @@ struct CONTROLLER_MAPPING // GC PAD MAPPING int triggertype; // Triggers range std::string SDiagonal; bool bSquareToCircle; + bool rumble; int eventnum; // Linux Event Number, Can't be found dynamically yet }; diff --git a/Source/Plugins/Plugin_PadSimple/Src/PadSimple.cpp b/Source/Plugins/Plugin_PadSimple/Src/PadSimple.cpp index a4b4123d42..b60b5169e5 100644 --- a/Source/Plugins/Plugin_PadSimple/Src/PadSimple.cpp +++ b/Source/Plugins/Plugin_PadSimple/Src/PadSimple.cpp @@ -271,13 +271,15 @@ void DInput_Read(int _numPAD, SPADStatus* _pPADStatus) if (dinput.diks[pad[_numPAD].keyForControl[CTL_L]] & 0xFF) { - _pPADStatus->button |= PAD_TRIGGER_L; + if (triggervalue > 230) + _pPADStatus->button |= PAD_TRIGGER_L; _pPADStatus->triggerLeft = triggervalue; } if (dinput.diks[pad[_numPAD].keyForControl[CTL_R]] & 0xFF) { - _pPADStatus->button |= PAD_TRIGGER_R; + if (triggervalue > 230) + _pPADStatus->button |= PAD_TRIGGER_R; _pPADStatus->triggerRight = triggervalue; } diff --git a/Source/Plugins/Plugin_nJoy_SDL/Src/Config.cpp b/Source/Plugins/Plugin_nJoy_SDL/Src/Config.cpp index 793482cb7c..6073af7746 100644 --- a/Source/Plugins/Plugin_nJoy_SDL/Src/Config.cpp +++ b/Source/Plugins/Plugin_nJoy_SDL/Src/Config.cpp @@ -111,6 +111,7 @@ void Config::Save(int Slot) file.Set("General", "SaveByID", g_Config.bSaveByID); file.Set("General", "CheckForFocus", g_Config.bCheckFocus); file.Set("General", "NoTriggerFilter", g_Config.bNoTriggerFilter); + file.Set("General", "RumbleStrength", g_Config.RumbleStrength); #ifdef RERECORDING file.Set("General", "Recording", g_Config.bRecording); file.Set("General", "Playback", g_Config.bPlayback); @@ -171,6 +172,7 @@ void Config::Save(int Slot) file.Set(SectionName.c_str(), "controllertype", PadMapping[i].controllertype); file.Set(SectionName.c_str(), "TriggerType", PadMapping[i].triggertype); file.Set(SectionName.c_str(), "eventnum", PadMapping[i].eventnum); + file.Set(SectionName.c_str(), "use_rumble", PadMapping[i].rumble); file.Set(SectionName.c_str(), "Diagonal", PadMapping[i].SDiagonal); file.Set(SectionName.c_str(), "SquareToCircle", PadMapping[i].bSquareToCircle); @@ -203,6 +205,7 @@ void Config::Load(bool ChangePad, bool ChangeSaveByID) file.Get("General", "ShowAdvanced", &g_Config.bShowAdvanced, false); file.Get("General", "CheckForFocus", &g_Config.bCheckFocus, false); file.Get("General", "NoTriggerFilter", &g_Config.bNoTriggerFilter, false); + file.Get("General", "RumbleStrength", &g_Config.RumbleStrength, 8); #ifdef RERECORDING file.Get("General", "Recording", &g_Config.bRecording, false); file.Get("General", "Playback", &g_Config.bPlayback, false); @@ -263,6 +266,7 @@ void Config::Load(bool ChangePad, bool ChangeSaveByID) file.Get(SectionName.c_str(), "controllertype", &PadMapping[i].controllertype, 0); file.Get(SectionName.c_str(), "TriggerType", &PadMapping[i].triggertype, 0); file.Get(SectionName.c_str(), "eventnum", &PadMapping[i].eventnum, 0); + file.Get(SectionName.c_str(), "use_rumble", &PadMapping[i].rumble, false); file.Get(SectionName.c_str(), "Diagonal", &PadMapping[i].SDiagonal, "100%"); file.Get(SectionName.c_str(), "SquareToCircle", &Tmp, false); PadMapping[i].bSquareToCircle = Tmp; diff --git a/Source/Plugins/Plugin_nJoy_SDL/Src/Config.h b/Source/Plugins/Plugin_nJoy_SDL/Src/Config.h index a423eb6d12..6ab509cf78 100644 --- a/Source/Plugins/Plugin_nJoy_SDL/Src/Config.h +++ b/Source/Plugins/Plugin_nJoy_SDL/Src/Config.h @@ -30,6 +30,7 @@ struct Config bool bSaveByID; bool bCheckFocus; bool bNoTriggerFilter; + int RumbleStrength; #ifdef RERECORDING bool bRecording; bool bPlayback; diff --git a/Source/Plugins/Plugin_nJoy_SDL/Src/GUI/ConfigBox.cpp b/Source/Plugins/Plugin_nJoy_SDL/Src/GUI/ConfigBox.cpp index b91edccd97..a1d057610a 100644 --- a/Source/Plugins/Plugin_nJoy_SDL/Src/GUI/ConfigBox.cpp +++ b/Source/Plugins/Plugin_nJoy_SDL/Src/GUI/ConfigBox.cpp @@ -6,7 +6,7 @@ // // Author: Falcon4ever (nJoy@falcon4ever.com) // Site: www.multigesture.net -// Copyright (C) 2003-2008 Dolphin Project. +// Copyright (C) 2003-2009 Dolphin Project. // ////////////////////////////////////////////////////////////////////////////////////////// // @@ -80,6 +80,10 @@ BEGIN_EVENT_TABLE(ConfigBox,wxDialog) EVT_COMBOBOX(IDC_TRIGGERTYPE, ConfigBox::ChangeSettings) EVT_COMBOBOX(IDC_DEADZONE, ConfigBox::ChangeSettings) + // Rumble settings + EVT_CHECKBOX(IDC_ENABLERUMBLE, ConfigBox::ChangeSettings) + EVT_COMBOBOX(IDC_RUMBLESTRENGTH, ConfigBox::ChangeSettings) + // Advanced settings EVT_COMBOBOX(IDCB_MAINSTICK_DIAGONAL, ConfigBox::ChangeSettings) EVT_CHECKBOX(IDCB_MAINSTICK_S_TO_C, ConfigBox::ChangeSettings) @@ -203,7 +207,6 @@ void ConfigBox::OKClick(wxCommandEvent& event) if (event.GetId() == ID_OK) { DoSave(); // Save settings - //g_Config.Load(); // Reload settings to PadMapping if(Debugging) PanicAlert("Done"); Close(); // Call OnClose() } @@ -217,7 +220,6 @@ void ConfigBox::CancelClick(wxCommandEvent& event) { // Forget all potential changes to PadMapping by loading the last saved settings g_Config.Load(); - Close(); // Call OnClose() } } @@ -485,7 +487,13 @@ void ConfigBox::ChangeSettings( wxCommandEvent& event ) UpdateGUI(notebookpage); } break; - + case IDC_ENABLERUMBLE: + PadMapping[notebookpage].rumble = m_Rumble[notebookpage]->IsChecked(); + UpdateGUI(notebookpage); + break; + case IDC_RUMBLESTRENGTH: + g_Config.RumbleStrength = m_RStrength[notebookpage]->GetSelection(); + break; case IDC_JOYNAME: DoChangeJoystick(); break; @@ -555,17 +563,17 @@ void ConfigBox::UpdateGUI(int _notebookpage) m_CBShowAdvanced[_notebookpage]->SetValue(g_Config.bShowAdvanced); m_CBCheckFocus[_notebookpage]->SetValue(g_Config.bCheckFocus); m_AdvancedMapFilter[_notebookpage]->SetValue(g_Config.bNoTriggerFilter); + m_RStrength[_notebookpage]->SetSelection(g_Config.RumbleStrength); #ifdef RERECORDING m_CheckRecording[_notebookpage]->SetValue(g_Config.bRecording); m_CheckPlayback[_notebookpage]->SetValue(g_Config.bPlayback); #endif - //LogMsg("Update: %i\n", g_Config.bSaveByID); - - // Disabled pages - bool Enabled = PadMapping[_notebookpage].enabled == 1 ? true : false; // There is no FindItem in linux so this doesn't work #ifdef _WIN32 + // Disabled pages + bool Enabled = PadMapping[_notebookpage].enabled == 1 ? true : false; + // Enable or disable all buttons for(int i = IDB_ANALOG_MAIN_X; i <= IDB_BUTTONHALFPRESS; i++) m_Controller[_notebookpage]->FindItem(i)->Enable(Enabled); @@ -680,11 +688,20 @@ void ConfigBox::CreateGUIControls() wxArrayString wxAS_TriggerType; wxAS_TriggerType.Add(wxString::FromAscii(TriggerType[InputCommon::CTL_TRIGGER_SDL])); wxAS_TriggerType.Add(wxString::FromAscii(TriggerType[InputCommon::CTL_TRIGGER_XINPUT])); - + // -------------------------------------------------------------------- - // Populate the deadzone list + // Populate the deadzone list and the Rumble Strength // ----------------------------- - char buffer [8]; + + char buffer[8]; + + wxArrayString wxAS_RumbleStrength; + for (int i = 1; i < 11; i++) + { + sprintf (buffer, "%d %%", i*10); + wxAS_RumbleStrength.Add(wxString::FromAscii(buffer)); + } + wxArrayString arrayStringFor_Deadzone; for(int x = 1; x <= 100; x++) { @@ -692,7 +709,6 @@ void ConfigBox::CreateGUIControls() arrayStringFor_Deadzone.Add(wxString::FromAscii(buffer)); } - // Populate all four pages for(int i = 0; i < 4; i++) { @@ -880,6 +896,17 @@ void ConfigBox::CreateGUIControls() m_gGenSettingsID[i]->Add(m_CBSaveByID[i], 0, wxEXPAND | wxALL, 3); m_gGenSettingsID[i]->Add(m_CBShowAdvanced[i], 0, wxEXPAND | wxALL, 3); + // Create objects for Rumble settings (general 4) + m_RStrength[i] = new wxComboBox(m_Controller[i], IDC_RUMBLESTRENGTH, wxAS_RumbleStrength[0], wxDefaultPosition, wxSize(85, 20), wxAS_RumbleStrength, wxCB_READONLY); + m_Rumble[i] = new wxCheckBox(m_Controller[i], IDC_ENABLERUMBLE, wxT("Enable Rumble"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); + + // Populate general settings 4 + m_gRumble[i] = new wxStaticBoxSizer( wxVERTICAL, m_Controller[i], wxT("Rumble Settings")); + m_gGBRumble[i] = new wxGridBagSizer(0, 0); + m_gGBRumble[i]->Add(m_Rumble[i], wxGBPosition(0, 0), wxGBSpan(1, 1), (wxTOP), 1); + m_gGBRumble[i]->Add(m_RStrength[i], wxGBPosition(1, 0), wxGBSpan(1, 1), (wxTOP), 6); + m_gRumble[i]->Add(m_gGBRumble[i], 0, wxEXPAND | wxALL, 3); + // Create tooltips m_ControlType[i]->SetToolTip(wxT( "Use a 'hat' on your gamepad or configure a custom button for each direction." @@ -899,6 +926,8 @@ void ConfigBox::CreateGUIControls() m_sSettings[i]->Add(m_gExtrasettings[i], 0, wxEXPAND | wxALL, 0); m_sSettings[i]->Add(m_gGenSettings[i], 0, wxEXPAND | wxLEFT, 5); m_sSettings[i]->Add(m_gGenSettingsID[i], 0, wxEXPAND | wxLEFT, 5); + m_sSettings[i]->Add(m_gRumble[i], 0, wxEXPAND | wxLEFT, 5); + // ------------------------- //////////////////////////// General settings diff --git a/Source/Plugins/Plugin_nJoy_SDL/Src/GUI/ConfigBox.h b/Source/Plugins/Plugin_nJoy_SDL/Src/GUI/ConfigBox.h index 8351e0141e..3144d17cd2 100644 --- a/Source/Plugins/Plugin_nJoy_SDL/Src/GUI/ConfigBox.h +++ b/Source/Plugins/Plugin_nJoy_SDL/Src/GUI/ConfigBox.h @@ -112,16 +112,21 @@ class ConfigBox : public wxDialog wxStaticBoxSizer *m_gGenSettings[4]; wxStaticBoxSizer *m_gGenSettingsID[4]; - wxGridBagSizer * m_gGBGenSettings[4]; + wxGridBagSizer *m_gGBGenSettings[4]; wxCheckBox *m_CBSaveByID[4], *m_CBShowAdvanced[4]; wxStaticText *m_TSControltype[4], *m_TSTriggerType[4]; wxStaticBoxSizer *m_gStatusIn[4], *m_gStatusInSettings[4], *m_gStatusAdvancedSettings[4]; // Advanced settings wxBoxSizer *m_gStatusInSettingsH[4]; - wxGridBagSizer * m_GBAdvancedMainStick[4]; + wxGridBagSizer *m_GBAdvancedMainStick[4]; wxStaticText *m_TStatusIn[4], *m_TStatusOut[4], *m_STDiagonal[4]; wxComboBox *m_CoBDiagonal[4]; wxCheckBox *m_CBS_to_C[4]; wxCheckBox *m_CBCheckFocus[4], *m_AdvancedMapFilter[4]; + + wxCheckBox *m_Rumble[4]; // Rumble settings + wxComboBox *m_RStrength[4]; + wxStaticBoxSizer *m_gRumble[4]; + wxGridBagSizer *m_gGBRumble[4]; wxStaticBoxSizer *m_gStatusTriggers[4]; // Triggers wxStaticText *m_TStatusTriggers[4]; @@ -218,6 +223,8 @@ class ConfigBox : public wxDialog IDG_CONTROLLERTYPE, IDC_CONTROLTYPE, IDC_TRIGGERTYPE, // Controller type IDC_SAVEBYID, IDC_SHOWADVANCED, // Settings + + IDC_ENABLERUMBLE, IDC_RUMBLESTRENGTH, IDT_RUMBLESTRENGTH, // Rumble ID_INSTATUS1, ID_INSTATUS2, ID_INSTATUS3, ID_INSTATUS4, // Advanced status ID_STATUSBMP1, ID_STATUSBMP2, ID_STATUSBMP3, ID_STATUSBMP4, diff --git a/Source/Plugins/Plugin_nJoy_SDL/Src/GUI/ConfigJoypad.cpp b/Source/Plugins/Plugin_nJoy_SDL/Src/GUI/ConfigJoypad.cpp index 23fed32685..c5a230734a 100644 --- a/Source/Plugins/Plugin_nJoy_SDL/Src/GUI/ConfigJoypad.cpp +++ b/Source/Plugins/Plugin_nJoy_SDL/Src/GUI/ConfigJoypad.cpp @@ -80,11 +80,12 @@ void ConfigBox::UpdateGUIButtonMapping(int controller) m_CoBDiagonal[controller]->SetValue(wxString::FromAscii(PadMapping[controller].SDiagonal.c_str())); m_CBS_to_C[controller]->SetValue(PadMapping[controller].bSquareToCircle); m_AdvancedMapFilter[controller]->SetValue(g_Config.bNoTriggerFilter); + // Update Rumble checkbox + m_Rumble[controller]->SetValue(PadMapping[controller].rumble); #ifdef RERECORDING m_CheckRecording[controller]->SetValue(g_Config.bRecording); m_CheckPlayback[controller]->SetValue(g_Config.bPlayback); #endif - //LogMsg("m_TriggerType[%i] = %i\n", controller, PadMapping[controller].triggertype); // Update D-Pad if(PadMapping[controller].controllertype == InputCommon::CTL_DPAD_HAT) @@ -99,8 +100,6 @@ void ConfigBox::UpdateGUIButtonMapping(int controller) tmp << PadMapping[controller].dpad2[InputCommon::CTL_D_PAD_RIGHT]; m_JoyDpadRight[controller]->SetValue(tmp); tmp.clear(); } - // Replace "-1" with "" in the GUI controls - //if(ControlsCreated) ToBlank(); } /* Populate the PadMapping array with the dialog items settings (for example diff --git a/Source/Plugins/Plugin_nJoy_SDL/Src/Rumble.cpp b/Source/Plugins/Plugin_nJoy_SDL/Src/Rumble.cpp index 5d90931a17..a444392914 100644 --- a/Source/Plugins/Plugin_nJoy_SDL/Src/Rumble.cpp +++ b/Source/Plugins/Plugin_nJoy_SDL/Src/Rumble.cpp @@ -37,32 +37,29 @@ ////////////////////////////////////////////////////////////////////////////////////////// -// Enable or disable rumble. Set USE_RUMBLE_DINPUT_HACK in nJoy.h +// Enable or disable rumble. // ŻŻŻŻŻŻŻŻŻ -#ifdef USE_RUMBLE_DINPUT_HACK -bool g_rumbleEnable = FALSE; -#endif // Rumble in windows #ifdef _WIN32 - #ifdef USE_RUMBLE_DINPUT_HACK - LPDIRECTINPUT8 g_pDI = NULL; - LPDIRECTINPUTDEVICE8 g_pDevice = NULL; - LPDIRECTINPUTEFFECT g_pEffect = NULL; - - DWORD g_dwNumForceFeedbackAxis = 0; - INT g_nXForce = 0; - INT g_nYForce = 0; + struct RUMBLE // GC Pad rumble DIDevice + { + LPDIRECTINPUTDEVICE8 g_pDevice; // 4 pads objects + LPDIRECTINPUTEFFECT g_pEffect; + DWORD g_dwNumForceFeedbackAxis; + DIEFFECT eff; + }; #define SAFE_RELEASE(p) { if (p) { (p)->Release(); (p)=NULL; } } - HRESULT InitDirectInput(HWND hDlg); - //VOID FreeDirectInput(); BOOL CALLBACK EnumFFDevicesCallback(const DIDEVICEINSTANCE* pInst, VOID* pContext); BOOL CALLBACK EnumAxesCallback(const DIDEVICEOBJECTINSTANCE* pdidoi, VOID* pContext); - HRESULT SetDeviceForcesXY(); - #endif + void SetDeviceForcesXY(int pad, int nXYForce); + + LPDIRECTINPUT8 g_Rumble; // DInput Rumble object + RUMBLE pRumble[4]; // 4 GC Rumble Pads + extern InputCommon::CONTROLLER_MAPPING PadMapping[4]; #elif defined(__linux__) #include @@ -74,101 +71,36 @@ bool g_rumbleEnable = FALSE; struct ff_effect effect; bool CanRumble = false; #endif + ////////////////////// - - - -// Set PAD rumble. Explanation: Stop = 0, Rumble = 1 -// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -void PAD_Rumble(u8 _numPAD, unsigned int _uType, unsigned int _uStrength) -{ - //if (_numPAD > 0) - // return; - - // SDL can't rumble the gamepad so we need to use platform specific code - #ifdef _WIN32 - #ifdef USE_RUMBLE_DINPUT_HACK - static int a = 0; - - if ((_uType == 0) || (_uType == 2)) - { - a = 0; - } - else if (_uType == 1) - { - a = _uStrength > 2 ? 8000 : 0; - } - - a = int ((float)a * 0.96f); - - if (!g_rumbleEnable) - { - a = 0; - } - else - { - g_nYForce = a; - SetDeviceForcesXY(); - } - #endif - #elif defined(__linux__) - struct input_event event; - if (CanRumble) - { - if (_uType == 1) - { - event.type = EV_FF; - event.code = effect.id; - event.value = 1; - if (write(fd, (const void*) &event, sizeof(event)) == -1) { - perror("Play effect"); - exit(1); - } - } - if ((_uType == 0) || (_uType == 2)) - { - event.type = EV_FF; - event.code = effect.id; - event.value = 0; - if (write(fd, (const void*) &event, sizeof(event)) == -1) { - perror("Stop effect"); - exit(1); - } - } - } - #endif -} - - - // Use PAD rumble // ŻŻŻŻŻŻŻŻŻŻŻŻŻŻ -void Pad_Use_Rumble(u8 _numPAD, SPADStatus* _pPADStatus) + +void Pad_Use_Rumble(u8 _numPAD)//, SPADStatus* _pPADStatus) { #ifdef _WIN32 - #ifdef USE_RUMBLE_DINPUT_HACK - // Enable or disable rumble - if (PadState[_numPAD].halfpress) - if (!g_pDI) - if (FAILED(InitDirectInput(m_hWnd))) - { - MessageBox(NULL, SDL_GetError(), "Could not initialize DirectInput!", MB_ICONERROR); - g_rumbleEnable = FALSE; - //return; - } - else - { - g_rumbleEnable = TRUE; + if (PadMapping[_numPAD].rumble) { + if (!g_Rumble) { + + HWND rumble_hWnd = GetParent(m_hWnd); + HWND TopLevel = GetParent(rumble_hWnd); + + // Support both rendering to main window and not. + if (GetForegroundWindow() == TopLevel) + rumble_hWnd = TopLevel; + if (GetForegroundWindow() == m_hWnd) + rumble_hWnd = m_hWnd; + if (FAILED(InitRumble(rumble_hWnd))) + PanicAlert("Could not initialize Rumble!"); + + } else { + // Acquire gamepad + if (pRumble[_numPAD].g_pDevice != NULL) + pRumble[_numPAD].g_pDevice->Acquire(); + } } - if (g_rumbleEnable) - { - g_pDevice->Acquire(); - - if (g_pEffect) g_pEffect->Start(1, 0); - } - #endif #elif defined(__linux__) if (!fd) { @@ -204,191 +136,257 @@ void Pad_Use_Rumble(u8 _numPAD, SPADStatus* _pPADStatus) #endif } +//////////////////////////////////////////////////// +// Set PAD rumble. Explanation: Stop = 0, Rumble = 1 +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +void PAD_Rumble(u8 _numPAD, unsigned int _uType, unsigned int _uStrength) +{ + Pad_Use_Rumble(_numPAD); + // SDL can't rumble the gamepad so we need to use platform specific code + #ifdef _WIN32 + int a = 0; + if (_uType == 1) + { + // it looks like _uStrength is equal to 3 everytime anyway... + a = _uStrength > 2 ? (1000*(g_Config.RumbleStrength + 1)) : 0; + a = a > 10000 ? 10000 : a; + } + + // a = int ((float)a * 0.96f); + // What is this for ? + // else if ((_uType == 0) || (_uType == 2)) + + if (PadMapping[_numPAD].rumble) // rumble activated + { + // Start Effect + SetDeviceForcesXY(_numPAD, a); + } + + #elif defined(__linux__) + struct input_event event; + if (CanRumble) + { + if (_uType == 1) + { + event.type = EV_FF; + event.code = effect.id; + event.value = 1; + if (write(fd, (const void*) &event, sizeof(event)) == -1) { + perror("Play effect"); + exit(1); + } + } + if ((_uType == 0) || (_uType == 2)) + { + event.type = EV_FF; + event.code = effect.id; + event.value = 0; + if (write(fd, (const void*) &event, sizeof(event)) == -1) { + perror("Stop effect"); + exit(1); + } + } + } + #endif +} #ifdef _WIN32 ////////////////////////////////////////////////////////////////////////////////////////// // Rumble stuff :D! // ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ // -#ifdef USE_RUMBLE_DINPUT_HACK -HRESULT InitDirectInput( HWND hDlg ) + +HRESULT InitRumble(HWND hWnd) { - DIPROPDWORD dipdw; - HRESULT hr; + DIPROPDWORD dipdw; + HRESULT hr; - // Register with the DirectInput subsystem and get a pointer to a IDirectInput interface we can use. - if (FAILED(hr = DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (VOID**)&g_pDI, NULL))) - { - return hr; - } + // Register with the DirectInput subsystem and get a pointer to a IDirectInput interface we can use. + if (FAILED(hr = DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (VOID**)&g_Rumble, NULL))) + return hr; - // Look for a force feedback device we can use - if (FAILED(hr = g_pDI->EnumDevices( DI8DEVCLASS_GAMECTRL, EnumFFDevicesCallback, NULL, DIEDFL_ATTACHEDONLY | DIEDFL_FORCEFEEDBACK))) - { - return hr; - } + // Look for a device we can use + if (FAILED(hr = g_Rumble->EnumDevices( DI8DEVCLASS_GAMECTRL, EnumFFDevicesCallback, NULL, DIEDFL_ATTACHEDONLY | DIEDFL_FORCEFEEDBACK))) + return hr; - if (NULL == g_pDevice) - { - MessageBox(NULL, "Force feedback device not found. nJoy will now disable rumble." ,"FFConst" , MB_ICONERROR | MB_OK); - g_rumbleEnable = FALSE; - - return S_OK; - } + for (int i=0; i<4; i++) + { + if (NULL == pRumble[i].g_pDevice) + PadMapping[i].rumble = false; // Disable Rumble for this pad only. + else + { + pRumble[i].g_pDevice->SetDataFormat(&c_dfDIJoystick); + pRumble[i].g_pDevice->SetCooperativeLevel(hWnd, DISCL_EXCLUSIVE | DISCL_BACKGROUND); + // Request exclusive acces for both background and foreground. - // Set the data format to "simple joystick" - a predefined data format. A - // data format specifies which controls on a device we are interested in, - // and how they should be reported. - // - // This tells DirectInput that we will be passing a DIJOYSTATE structure to - // IDirectInputDevice8::GetDeviceState(). Even though we won't actually do - // it in this sample. But setting the data format is important so that the - // DIJOFS_* values work properly. - if (FAILED(hr = g_pDevice->SetDataFormat(&c_dfDIJoystick))) - return hr; + dipdw.diph.dwSize = sizeof(DIPROPDWORD); + dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); + dipdw.diph.dwObj = 0; + dipdw.diph.dwHow = DIPH_DEVICE; + dipdw.dwData = FALSE; - // Set the cooperative level to let DInput know how this device should - // interact with the system and with other DInput applications. - // Exclusive access is required in order to perform force feedback. - //if (FAILED(hr = g_pDevice->SetCooperativeLevel(hDlg, DISCL_EXCLUSIVE | DISCL_FOREGROUND))) + // if Force Feedback doesn't seem to work... + if (FAILED(pRumble[i].g_pDevice->EnumObjects(EnumAxesCallback, + (void*)&pRumble[i].g_dwNumForceFeedbackAxis, DIDFT_AXIS)) + || FAILED(pRumble[i].g_pDevice->SetProperty(DIPROP_AUTOCENTER, &dipdw.diph))) + { + PanicAlert("Device %d doesn't seem to work ! \nRumble for device %d is now Disabled !", i+1); - if (FAILED(hr = g_pDevice->SetCooperativeLevel(hDlg, DISCL_EXCLUSIVE | DISCL_FOREGROUND))) - { - return hr; - } + PadMapping[i].rumble = false; // Disable Rumble for this pad - // Since we will be playing force feedback effects, we should disable the - // auto-centering spring. - dipdw.diph.dwSize = sizeof(DIPROPDWORD); - dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); - dipdw.diph.dwObj = 0; - dipdw.diph.dwHow = DIPH_DEVICE; - dipdw.dwData = FALSE; + continue; // Next pad + } - if (FAILED(hr = g_pDevice->SetProperty(DIPROP_AUTOCENTER, &dipdw.diph))) - return hr; + if (pRumble[i].g_dwNumForceFeedbackAxis > 2) + pRumble[i].g_dwNumForceFeedbackAxis = 2; - // Enumerate and count the axes of the joystick - if (FAILED(hr = g_pDevice->EnumObjects(EnumAxesCallback, (VOID*)&g_dwNumForceFeedbackAxis, DIDFT_AXIS))) - return hr; + DWORD _rgdwAxes[2] = {DIJOFS_X, DIJOFS_Y}; + long rglDirection[2] = {0, 0}; + DICONSTANTFORCE cf = {0}; - // This simple sample only supports one or two axis joysticks - if (g_dwNumForceFeedbackAxis > 2) - g_dwNumForceFeedbackAxis = 2; + ZeroMemory(&pRumble[i].eff, sizeof(pRumble[i].eff)); + pRumble[i].eff.dwSize = sizeof(DIEFFECT); + pRumble[i].eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; + pRumble[i].eff.dwDuration = INFINITE; // fixed time may be safer (X * DI_SECONDS) + pRumble[i].eff.dwSamplePeriod = 0; + pRumble[i].eff.dwGain = DI_FFNOMINALMAX; + pRumble[i].eff.dwTriggerButton = DIEB_NOTRIGGER; + pRumble[i].eff.dwTriggerRepeatInterval = 0; + pRumble[i].eff.cAxes = pRumble[i].g_dwNumForceFeedbackAxis; + pRumble[i].eff.rgdwAxes = _rgdwAxes; + pRumble[i].eff.rglDirection = rglDirection; + pRumble[i].eff.lpEnvelope = 0; + pRumble[i].eff.cbTypeSpecificParams = sizeof( DICONSTANTFORCE ); + pRumble[i].eff.lpvTypeSpecificParams = &cf; + pRumble[i].eff.dwStartDelay = 0; - // This application needs only one effect: Applying raw forces. - DWORD rgdwAxes[2] = {DIJOFS_X, DIJOFS_Y}; - LONG rglDirection[2] = {0, 0}; - DICONSTANTFORCE cf = {0}; + // Create the prepared effect + if (FAILED(hr = pRumble[i].g_pDevice->CreateEffect(GUID_ConstantForce, &pRumble[i].eff, &pRumble[i].g_pEffect, NULL))) + return hr; + + if (pRumble[i].g_pEffect == NULL) + return E_FAIL; + } + } - DIEFFECT eff; - ZeroMemory(&eff, sizeof(eff)); - eff.dwSize = sizeof(DIEFFECT); - eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; - eff.dwDuration = INFINITE; - eff.dwSamplePeriod = 0; - eff.dwGain = DI_FFNOMINALMAX; - eff.dwTriggerButton = DIEB_NOTRIGGER; - eff.dwTriggerRepeatInterval = 0; - eff.cAxes = g_dwNumForceFeedbackAxis; - eff.rgdwAxes = rgdwAxes; - eff.rglDirection = rglDirection; - eff.lpEnvelope = 0; - eff.cbTypeSpecificParams = sizeof( DICONSTANTFORCE ); - eff.lpvTypeSpecificParams = &cf; - eff.dwStartDelay = 0; + return S_OK; +} - // Create the prepared effect - if (FAILED(hr = g_pDevice->CreateEffect(GUID_ConstantForce, &eff, &g_pEffect, NULL))) - { - return hr; - } +void SetDeviceForcesXY(int npad, int nXYForce) +{ + // Security check + if (pRumble[npad].g_pDevice == NULL) + return; - if (NULL == g_pEffect) - return E_FAIL; + // If nXYForce is null, there's no point to create the effect + // Just stop the force feedback + if (nXYForce == 0) { + pRumble[npad].g_pEffect->Stop(); + return; + } + + long rglDirection[2] = {0}; + DICONSTANTFORCE cf; - return S_OK; + // If only one force feedback axis, then apply only one direction and keep the direction at zero + if (pRumble[npad].g_dwNumForceFeedbackAxis == 1) + { + rglDirection[0] = 0; + cf.lMagnitude = nXYForce; // max should be 10000 + } + // If two force feedback axis, then apply magnitude from both directions + else + { + rglDirection[0] = nXYForce; + rglDirection[1] = nXYForce; + cf.lMagnitude = 1.4142f*nXYForce; + } + + ZeroMemory(&pRumble[npad].eff, sizeof(pRumble[npad].eff)); + pRumble[npad].eff.dwSize = sizeof(DIEFFECT); + pRumble[npad].eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; + pRumble[npad].eff.cAxes = pRumble[npad].g_dwNumForceFeedbackAxis; + pRumble[npad].eff.rglDirection = rglDirection; + pRumble[npad].eff.lpEnvelope = 0; + pRumble[npad].eff.cbTypeSpecificParams = sizeof(DICONSTANTFORCE); + pRumble[npad].eff.lpvTypeSpecificParams = &cf; + pRumble[npad].eff.dwStartDelay = 0; + + // Now set the new parameters.. + pRumble[npad].g_pEffect->SetParameters(&pRumble[npad].eff, DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_START); + // ..And start the effect immediately. + if (pRumble[npad].g_pEffect != NULL) + pRumble[npad].g_pEffect->Start(1, 0); +} + +BOOL CALLBACK EnumFFDevicesCallback(const DIDEVICEINSTANCE* pInst, VOID* pContext) +{ + LPDIRECTINPUTDEVICE8 pDevice; + DIPROPDWORD dipdw; + HRESULT hr; + + int JoystickID; + + dipdw.diph.dwSize = sizeof(DIPROPDWORD); + dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); + dipdw.diph.dwObj = 0; + dipdw.diph.dwHow = DIPH_DEVICE; + + g_Rumble->CreateDevice(pInst->guidInstance, &pDevice, NULL); // Create a DInput pad device + + if (SUCCEEDED(hr = pDevice->GetProperty(DIPROP_JOYSTICKID, &dipdw.diph))) // Get DInput Device ID + JoystickID = dipdw.dwData; + else + return DIENUM_CONTINUE; + + //PanicAlert("DInput ID : %d \nSDL ID (1-4) : %d / %d / %d / %d\n", JoystickID, PadMapping[0].ID, PadMapping[1].ID, PadMapping[2].ID, PadMapping[3].ID); + + for (int i=0; i<4; i++) + { + if (PadMapping[i].ID == JoystickID) // if SDL ID = DInput ID -> we're dealing with the same device + { + // a DInput device is created even if rumble is disabled on startup + // this way, you can toggle the rumble setting while in game + if (PadMapping[i].enabled) // && PadMapping[i].rumble + { + pRumble[i].g_pDevice = pDevice; // everything looks good, save the DInput device + } + } + } + + return DIENUM_CONTINUE; +} + +BOOL CALLBACK EnumAxesCallback(const DIDEVICEOBJECTINSTANCE* pdidoi, VOID* pContext) +{ + DWORD* pdwNumForceFeedbackAxis = (DWORD*)pContext; // Enum Rumble Axis + if ((pdidoi->dwFlags & DIDOI_FFACTUATOR) != 0) + (*pdwNumForceFeedbackAxis)++; + + return DIENUM_CONTINUE; } VOID FreeDirectInput() { // Unacquire the device one last time just in case // the app tried to exit while the device is still acquired. - if (g_pDevice) - g_pDevice->Unacquire(); - // Release any DirectInput objects. - SAFE_RELEASE(g_pEffect); - SAFE_RELEASE(g_pDevice); - SAFE_RELEASE(g_pDI); + for (int i=0; i<4; i++) // Free all pads + { + if (pRumble[i].g_pDevice) { + pRumble[i].g_pEffect->Stop(); + pRumble[i].g_pDevice->Unacquire(); + } + + SAFE_RELEASE(pRumble[i].g_pEffect); + SAFE_RELEASE(pRumble[i].g_pDevice); + } + + SAFE_RELEASE(g_Rumble); // Rumble object } -BOOL CALLBACK EnumFFDevicesCallback( const DIDEVICEINSTANCE* pInst, VOID* pContext ) -{ - LPDIRECTINPUTDEVICE8 pDevice; - HRESULT hr; - - // Obtain an interface to the enumerated force feedback device. - hr = g_pDI->CreateDevice(pInst->guidInstance, &pDevice, NULL); - - // If it failed, then we can't use this device for some bizarre reason. - // (Maybe the user unplugged it while we were in the middle of enumerating it.) So continue enumerating - if (FAILED(hr)) - return DIENUM_CONTINUE; - - // We successfully created an IDirectInputDevice8. So stop looking for another one. - g_pDevice = pDevice; - - return DIENUM_STOP; -} - -BOOL CALLBACK EnumAxesCallback(const DIDEVICEOBJECTINSTANCE* pdidoi, VOID* pContext) -{ - DWORD* pdwNumForceFeedbackAxis = (DWORD*)pContext; - if ((pdidoi->dwFlags & DIDOI_FFACTUATOR) != 0) - (*pdwNumForceFeedbackAxis)++; - - return DIENUM_CONTINUE; -} - -HRESULT SetDeviceForcesXY() -{ - // Modifying an effect is basically the same as creating a new one, except you need only specify the parameters you are modifying - LONG rglDirection[2] = { 0, 0 }; - - DICONSTANTFORCE cf; - - if (g_dwNumForceFeedbackAxis == 1) - { - // If only one force feedback axis, then apply only one direction and keep the direction at zero - cf.lMagnitude = g_nXForce; - rglDirection[0] = 0; - } - else - { - // If two force feedback axis, then apply magnitude from both directions - rglDirection[0] = g_nXForce; - rglDirection[1] = g_nYForce; - cf.lMagnitude = (DWORD)sqrt((double)g_nXForce * (double)g_nXForce + (double)g_nYForce * (double)g_nYForce ); - } - - DIEFFECT eff; - ZeroMemory(&eff, sizeof(eff)); - eff.dwSize = sizeof(DIEFFECT); - eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; - eff.cAxes = g_dwNumForceFeedbackAxis; - eff.rglDirection = rglDirection; - eff.lpEnvelope = 0; - eff.cbTypeSpecificParams = sizeof(DICONSTANTFORCE); - eff.lpvTypeSpecificParams = &cf; - eff.dwStartDelay = 0; - - // Now set the new parameters and start the effect immediately. - return g_pEffect->SetParameters(&eff, DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_START); -} -#endif #endif diff --git a/Source/Plugins/Plugin_nJoy_SDL/Src/nJoy.cpp b/Source/Plugins/Plugin_nJoy_SDL/Src/nJoy.cpp index cd0f900cc6..e04655918c 100644 --- a/Source/Plugins/Plugin_nJoy_SDL/Src/nJoy.cpp +++ b/Source/Plugins/Plugin_nJoy_SDL/Src/nJoy.cpp @@ -6,7 +6,7 @@ // // Author: Falcon4ever (nJoy@falcon4ever.com) // Site: www.multigesture.net -// Copyright (C) 2003-2008 Dolphin Project. +// Copyright (C) 2003-2009 Dolphin Project. // ////////////////////////////////////////////////////////////////////////////////////////// // @@ -38,6 +38,7 @@ The StrangeHack in ConfigAdvanced.cpp doesn't work in Linux, it still wont resize the window correctly. So currently in Linux you have to have advanced controls enabled when you open the window to see them. + // TODO : we should not need a Hack in the first place :/ ////////////////////////*/ @@ -80,7 +81,6 @@ // Variables // ŻŻŻŻŻŻŻŻŻ -// Rumble in windows #define _EXCLUDE_MAIN_ // Avoid certain declarations in nJoy.h FILE *pFile; HINSTANCE nJoy_hInst = NULL; @@ -95,14 +95,11 @@ int NumPads = 0, NumGoodPads = 0, LastPad = 0; SPADInitialize *g_PADInitialize = NULL; PLUGIN_GLOBALS* globals = NULL; -// Rumble -#ifdef _WIN32 - -#elif defined(__linux__) +// Rumble +#if defined(__linux__) extern int fd; #endif - ////////////////////////////////////////////////////////////////////////////////////////// // wxWidgets // ŻŻŻŻŻŻŻŻŻ @@ -249,15 +246,15 @@ void Initialize(void *init) INFO_LOG(CONSOLE, "Initialize: %i\n", SDL_WasInit(0)); g_PADInitialize = (SPADInitialize*)init; g_EmulatorRunning = true; + + #ifdef _WIN32 + m_hWnd = (HWND)g_PADInitialize->hWnd; + #endif #ifdef _DEBUG DEBUG_INIT(); #endif - #ifdef _WIN32 - m_hWnd = (HWND)g_PADInitialize->hWnd; - #endif - // Populate joyinfo for all attached devices if the configuration window is not already open #if defined(HAVE_WX) && HAVE_WX if(!m_frame) @@ -327,9 +324,7 @@ void Shutdown() g_PADInitialize = NULL; #ifdef _WIN32 - #ifdef USE_RUMBLE_DINPUT_HACK - FreeDirectInput(); - #endif + FreeDirectInput(); #elif defined(__linux__) close(fd); #endif @@ -415,6 +410,7 @@ void PAD_GetStatus(u8 _numPAD, SPADStatus* _pPADStatus) return; } #endif + // ---------------------- // Clear pad status @@ -426,6 +422,7 @@ void PAD_GetStatus(u8 _numPAD, SPADStatus* _pPADStatus) // Get type int TriggerType = PadMapping[_numPAD].triggertype; + int TriggerValue = PadState[_numPAD].halfpress ? 100 : 255; /////////////////////////////////////////////////// // The analog controls @@ -440,7 +437,7 @@ void PAD_GetStatus(u8 _numPAD, SPADStatus* _pPADStatus) int TriggerRight = PadState[_numPAD].axis[InputCommon::CTL_R_SHOULDER]; // Check if we should make adjustments - if(PadMapping[_numPAD].bSquareToCircle) + if (PadMapping[_numPAD].bSquareToCircle) { std::vector main_xy = InputCommon::Square2Circle(i_main_stick_x, i_main_stick_y, _numPAD, PadMapping[_numPAD].SDiagonal); i_main_stick_x = main_xy.at(0); @@ -454,54 +451,61 @@ void PAD_GetStatus(u8 _numPAD, SPADStatus* _pPADStatus) u8 sub_stick_y = InputCommon::Pad_Convert(i_sub_stick_y); // Convert the triggers values, if we are using analog triggers at all - if(PadMapping[_numPAD].triggertype == InputCommon::CTL_TRIGGER_SDL) + if (PadMapping[_numPAD].triggertype == InputCommon::CTL_TRIGGER_SDL) { - if(PadMapping[_numPAD].buttons[InputCommon::CTL_L_SHOULDER] >= 1000) TriggerLeft = InputCommon::Pad_Convert(TriggerLeft); - if(PadMapping[_numPAD].buttons[InputCommon::CTL_R_SHOULDER] >= 1000) TriggerRight = InputCommon::Pad_Convert(TriggerRight); + if (PadMapping[_numPAD].buttons[InputCommon::CTL_L_SHOULDER] >= 1000) TriggerLeft = InputCommon::Pad_Convert(TriggerLeft); + if (PadMapping[_numPAD].buttons[InputCommon::CTL_R_SHOULDER] >= 1000) TriggerRight = InputCommon::Pad_Convert(TriggerRight); } - // Set Deadzones (perhaps out of function?) - int deadzone = (int)(((float)(128.00/100.00)) * (float)(PadMapping[_numPAD].deadzone + 1)); - int deadzone2 = (int)(((float)(-128.00/100.00)) * (float)(PadMapping[_numPAD].deadzone + 1)); + // Set Deadzone + float deadzone = (128.00 * (float)(PadMapping[_numPAD].deadzone + 1.00)) / 100.00; + float distance_main = (float)sqrt((float)(main_stick_x * main_stick_x) + (float)(main_stick_y * main_stick_y)); + float distance_sub = (float)sqrt((float)(sub_stick_x * sub_stick_x) + (float)(sub_stick_y * sub_stick_y)); // Send values to Dolpin if they are outside the deadzone - if ((main_stick_x < deadzone2) || (main_stick_x > deadzone)) _pPADStatus->stickX = main_stick_x; - if ((main_stick_y < deadzone2) || (main_stick_y > deadzone)) _pPADStatus->stickY = main_stick_y; - if ((sub_stick_x < deadzone2) || (sub_stick_x > deadzone)) _pPADStatus->substickX = sub_stick_x; - if ((sub_stick_y < deadzone2) || (sub_stick_y > deadzone)) _pPADStatus->substickY = sub_stick_y; - + if (distance_main > deadzone) + { + _pPADStatus->stickX = main_stick_x; + _pPADStatus->stickY = main_stick_y; + } + if (distance_sub > deadzone) + { + _pPADStatus->substickX = sub_stick_x; + _pPADStatus->substickY = sub_stick_y; + } /////////////////////////////////////////////////// // The L and R triggers - // ----------- - int TriggerValue = 255; - if (PadState[_numPAD].halfpress) TriggerValue = 100; + // ----------- - _pPADStatus->button |= PAD_USE_ORIGIN; // Neutral value, no button pressed + // Neutral value, no button pressed + _pPADStatus->button |= PAD_USE_ORIGIN; // Check if the digital L button is pressed if (PadState[_numPAD].buttons[InputCommon::CTL_L_SHOULDER]) { - _pPADStatus->button |= PAD_TRIGGER_L; + if (!PadState[_numPAD].halfpress) + _pPADStatus->button |= PAD_TRIGGER_L; _pPADStatus->triggerLeft = TriggerValue; } // no the digital L button is not pressed, but the analog left trigger is - else if(TriggerLeft > 0) + else if (TriggerLeft > 0) _pPADStatus->triggerLeft = TriggerLeft; // Check if the digital R button is pressed if (PadState[_numPAD].buttons[InputCommon::CTL_R_SHOULDER]) { - _pPADStatus->button |= PAD_TRIGGER_R; + if (!PadState[_numPAD].halfpress) + _pPADStatus->button |= PAD_TRIGGER_R; _pPADStatus->triggerRight = TriggerValue; } // no the digital R button is not pressed, but the analog right trigger is - else if(TriggerRight > 0) + else if (TriggerRight > 0) _pPADStatus->triggerRight = TriggerRight; - // Update the buttons in analog mode to - if(TriggerLeft == 0xff) _pPADStatus->button |= PAD_TRIGGER_L; - if(TriggerRight == 0xff) _pPADStatus->button |= PAD_TRIGGER_R; + // Update the buttons in analog mode too + if (TriggerLeft > 0xf0) _pPADStatus->button |= PAD_TRIGGER_L; + if (TriggerRight > 0xf0) _pPADStatus->button |= PAD_TRIGGER_R; /////////////////////////////////////////////////// @@ -548,9 +552,6 @@ void PAD_GetStatus(u8 _numPAD, SPADStatus* _pPADStatus) // Update error code _pPADStatus->err = PAD_ERR_NONE; - // Use rumble - Pad_Use_Rumble(_numPAD, _pPADStatus); - // ------------------------------------------- // Rerecording // ---------------------- diff --git a/Source/Plugins/Plugin_nJoy_SDL/Src/nJoy.h b/Source/Plugins/Plugin_nJoy_SDL/Src/nJoy.h index 1b1241adce..4bd9d5c49b 100644 --- a/Source/Plugins/Plugin_nJoy_SDL/Src/nJoy.h +++ b/Source/Plugins/Plugin_nJoy_SDL/Src/nJoy.h @@ -33,15 +33,6 @@ #ifndef __NJOY_h__ #define __NJOY_h__ - -////////////////////////////////////////////////////////////////////////////////////////// -// Settings -// ŻŻŻŻŻŻŻŻŻŻ -// Set this if you want to use the rumble 'hack' for controller one -//#define USE_RUMBLE_DINPUT_HACK -////////////////////////// - - ////////////////////////////////////////////////////////////////////////////////////////// // Includes // ŻŻŻŻŻŻŻŻŻŻ @@ -71,13 +62,12 @@ #define DIRECTINPUT_VERSION 0x0800 #define WIN32_LEAN_AND_MEAN - #ifdef USE_RUMBLE_DINPUT_HACK - #pragma comment(lib, "dxguid.lib") - #pragma comment(lib, "dinput8.lib") - #pragma comment(lib, "winmm.lib") - #include - VOID FreeDirectInput(); // Needed in both nJoy.cpp and Rumble.cpp - #endif + #pragma comment(lib, "dxguid.lib") + #pragma comment(lib, "dinput8.lib") + #pragma comment(lib, "winmm.lib") + #include + void FreeDirectInput(); // Needed in both nJoy.cpp and Rumble.cpp + #endif // _WIN32 #ifdef _WIN32 @@ -142,11 +132,10 @@ void DEBUG_INIT(); void DEBUG_QUIT(); bool IsFocus(); bool ReloadDLL(); +#ifdef _WIN32 +HRESULT InitRumble(HWND hWnd); +#endif -void Pad_Use_Rumble(u8 _numPAD, SPADStatus* _pPADStatus); // Rumble - -//void SaveConfig(); -//void LoadConfig(); ////////////////////////////////