diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 8e8d3e6e2d..fc53bb8c81 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -22,6 +22,7 @@ #include "ui/ui_context.h" #include "UI/EmuScreen.h" #include "UI/PluginScreen.h" +#include "UI/MenuScreens.h" #include "UI/GameSettingsScreen.h" #include "UI/GameInfoCache.h" #include "UI/MiscScreens.h" @@ -291,6 +292,7 @@ void GlobalSettingsScreen::CreateViews() { list->Add(new CheckBox(&enableReports_, gs->T("Enable Error Reporting"))); list->Add(new CheckBox(&g_Config.bEnableCheats, gs->T("Enable Cheats"))); list->Add(new CheckBox(&g_Config.bScreenshotsAsPNG, gs->T("Screenshots as PNG"))); + list->Add(new Choice(gs->T("Control Mapping")))->OnClick.Handle(this, &GlobalSettingsScreen::OnControlMapping); list->Add(new Choice(gs->T("System Language")))->OnClick.Handle(this, &GlobalSettingsScreen::OnLanguage); list->Add(new Choice(gs->T("Developer Tools")))->OnClick.Handle(this, &GlobalSettingsScreen::OnDeveloperTools); list->Add(new Choice(g->T("Back")))->OnClick.Handle(this, &GlobalSettingsScreen::OnBack); @@ -311,6 +313,12 @@ UI::EventReturn GlobalSettingsScreen::OnDeveloperTools(UI::EventParams &e) { return UI::EVENT_DONE; } +UI::EventReturn GlobalSettingsScreen::OnControlMapping(UI::EventParams &e) { + screenManager()->push(new ControlsScreen()); + return UI::EVENT_DONE; +} + + UI::EventReturn GlobalSettingsScreen::OnBack(UI::EventParams &e) { screenManager()->finishDialog(this, DR_OK); g_Config.sReportHost = enableReports_ ? "report.ppsspp.org" : ""; diff --git a/UI/GameSettingsScreen.h b/UI/GameSettingsScreen.h index 8e5ee91231..e49469700e 100644 --- a/UI/GameSettingsScreen.h +++ b/UI/GameSettingsScreen.h @@ -59,6 +59,7 @@ private: UI::EventReturn OnFactoryReset(UI::EventParams &e); UI::EventReturn OnBack(UI::EventParams &e); UI::EventReturn OnDeveloperTools(UI::EventParams &e); + UI::EventReturn OnControlMapping(UI::EventParams &e); // Temporaries to convert bools to other kinds of settings bool enableReports_; diff --git a/Windows/PPSSPP.vcxproj b/Windows/PPSSPP.vcxproj index 409ad6cee0..c5be521b11 100644 --- a/Windows/PPSSPP.vcxproj +++ b/Windows/PPSSPP.vcxproj @@ -117,7 +117,7 @@ false - XInput.lib;Winmm.lib;Ws2_32.lib;opengl32.lib;..\ffmpeg\Windows\x86\lib\avcodec.lib;..\ffmpeg\Windows\x86\lib\avdevice.lib;..\ffmpeg\Windows\x86\lib\avformat.lib;..\ffmpeg\Windows\x86\lib\avutil.lib;..\ffmpeg\Windows\x86\lib\swresample.lib;..\ffmpeg\Windows\x86\lib\swscale.lib;glu32.lib;comctl32.lib;dsound.lib;xinput.lib;%(AdditionalDependencies) + Winmm.lib;Ws2_32.lib;opengl32.lib;..\ffmpeg\Windows\x86\lib\avcodec.lib;..\ffmpeg\Windows\x86\lib\avdevice.lib;..\ffmpeg\Windows\x86\lib\avformat.lib;..\ffmpeg\Windows\x86\lib\avutil.lib;..\ffmpeg\Windows\x86\lib\swresample.lib;..\ffmpeg\Windows\x86\lib\swscale.lib;glu32.lib;comctl32.lib;dsound.lib;xinput.lib;%(AdditionalDependencies) true Windows MachineX86 @@ -150,7 +150,7 @@ false - XInput.lib;Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86_64\lib\avcodec.lib;..\ffmpeg\Windows\x86_64\lib\avdevice.lib;..\ffmpeg\Windows\x86_64\lib\avformat.lib;..\ffmpeg\Windows\x86_64\lib\avutil.lib;..\ffmpeg\Windows\x86_64\lib\swresample.lib;..\ffmpeg\Windows\x86_64\lib\swscale.lib;comctl32.lib;%(AdditionalDependencies) + Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86_64\lib\avcodec.lib;..\ffmpeg\Windows\x86_64\lib\avdevice.lib;..\ffmpeg\Windows\x86_64\lib\avformat.lib;..\ffmpeg\Windows\x86_64\lib\avutil.lib;..\ffmpeg\Windows\x86_64\lib\swresample.lib;..\ffmpeg\Windows\x86_64\lib\swscale.lib;comctl32.lib;%(AdditionalDependencies) true $(OutDir)$(ProjectName).pdb Windows @@ -184,7 +184,7 @@ false - XInput.lib;Winmm.lib;Ws2_32.lib;opengl32.lib;..\ffmpeg\Windows\x86\lib\avcodec.lib;..\ffmpeg\Windows\x86\lib\avdevice.lib;..\ffmpeg\Windows\x86\lib\avformat.lib;..\ffmpeg\Windows\x86\lib\avutil.lib;..\ffmpeg\Windows\x86\lib\swresample.lib;..\ffmpeg\Windows\x86\lib\swscale.lib;dsound.lib;glu32.lib;comctl32.lib;%(AdditionalDependencies) + Winmm.lib;Ws2_32.lib;opengl32.lib;..\ffmpeg\Windows\x86\lib\avcodec.lib;..\ffmpeg\Windows\x86\lib\avdevice.lib;..\ffmpeg\Windows\x86\lib\avformat.lib;..\ffmpeg\Windows\x86\lib\avutil.lib;..\ffmpeg\Windows\x86\lib\swresample.lib;..\ffmpeg\Windows\x86\lib\swscale.lib;dsound.lib;glu32.lib;comctl32.lib;%(AdditionalDependencies) $(OutDir)$(TargetName)$(TargetExt) %(AdditionalLibraryDirectories) true @@ -225,7 +225,7 @@ false - XInput.lib;Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86_64\lib\avcodec.lib;..\ffmpeg\Windows\x86_64\lib\avdevice.lib;..\ffmpeg\Windows\x86_64\lib\avformat.lib;..\ffmpeg\Windows\x86_64\lib\avutil.lib;..\ffmpeg\Windows\x86_64\lib\swresample.lib;..\ffmpeg\Windows\x86_64\lib\swscale.lib;comctl32.lib;%(AdditionalDependencies) + Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86_64\lib\avcodec.lib;..\ffmpeg\Windows\x86_64\lib\avdevice.lib;..\ffmpeg\Windows\x86_64\lib\avformat.lib;..\ffmpeg\Windows\x86_64\lib\avutil.lib;..\ffmpeg\Windows\x86_64\lib\swresample.lib;..\ffmpeg\Windows\x86_64\lib\swscale.lib;comctl32.lib;%(AdditionalDependencies) %(AdditionalLibraryDirectories) true Windows diff --git a/Windows/XinputDevice.cpp b/Windows/XinputDevice.cpp index 30a1b305e5..294c12ee7d 100644 --- a/Windows/XinputDevice.cpp +++ b/Windows/XinputDevice.cpp @@ -1,4 +1,5 @@ #include + #include "base/NativeApp.h" #include "Core/Config.h" #include "input/input_state.h" @@ -6,11 +7,71 @@ #include "XinputDevice.h" #include "ControlMapping.h" +// Utilities to dynamically load XInput. Adapted from SDL. + +typedef DWORD (WINAPI *XInputGetState_t) (DWORD dwUserIndex, XINPUT_STATE* pState); +typedef DWORD (WINAPI *XInputSetState_t) (DWORD dwUserIndex, XINPUT_VIBRATION* pVibration); +typedef DWORD (WINAPI *XInputGetCapabilities_t) (DWORD dwUserIndex, DWORD dwFlags, XINPUT_CAPABILITIES* pCapabilities); + +XInputGetState_t PPSSPP_XInputGetState = NULL; +XInputSetState_t PPSSPP_XInputSetState = NULL; +XInputGetCapabilities_t PPSSPP_XInputGetCapabilities = NULL; +static DWORD PPSSPP_XInputVersion = 0; +static HMODULE s_pXInputDLL = 0; +static int s_XInputDLLRefCount = 0; + +static void UnloadXInputDLL(); + +static int LoadXInputDLL() { + DWORD version = 0; + + if (s_pXInputDLL) { + s_XInputDLLRefCount++; + return 0; /* already loaded */ + } + + version = (1 << 16) | 4; + s_pXInputDLL = LoadLibrary( "XInput1_4.dll" ); // 1.4 Ships with Windows 8. + if (!s_pXInputDLL) { + version = (1 << 16) | 3; + s_pXInputDLL = LoadLibrary( "XInput1_3.dll" ); // 1.3 Ships with Vista and Win7, can be installed as a restributable component. + } + if (!s_pXInputDLL) { + return -1; + } + + PPSSPP_XInputVersion = version; + s_XInputDLLRefCount = 1; + + /* 100 is the ordinal for _XInputGetStateEx, which returns the same struct as XinputGetState, but with extra data in wButtons for the guide button, we think... */ + PPSSPP_XInputGetState = (XInputGetState_t)GetProcAddress( (HMODULE)s_pXInputDLL, (LPCSTR)100 ); + PPSSPP_XInputSetState = (XInputSetState_t)GetProcAddress( (HMODULE)s_pXInputDLL, "XInputSetState" ); + PPSSPP_XInputGetCapabilities = (XInputGetCapabilities_t)GetProcAddress( (HMODULE)s_pXInputDLL, "XInputGetCapabilities" ); + if ( !PPSSPP_XInputGetState || !PPSSPP_XInputSetState || !PPSSPP_XInputGetCapabilities ) { + UnloadXInputDLL(); + return -1; + } + + return 0; +} + +static void UnloadXInputDLL() { + if ( s_pXInputDLL ) { + if (--s_XInputDLLRefCount == 0) { + FreeLibrary( s_pXInputDLL ); + s_pXInputDLL = NULL; + } + } +} #ifndef XUSER_MAX_COUNT #define XUSER_MAX_COUNT 4 #endif +// Undocumented. Steam annoyingly grabs this button though.... +#define XINPUT_GUIDE_BUTTON 0x400 + + // Permanent map. Actual mapping happens elsewhere. static const struct {int from, to;} xinput_ctrl_map[] = { {XBOX_CODE_LEFTTRIGGER, KEYCODE_BUTTON_L2}, @@ -29,16 +90,24 @@ static const struct {int from, to;} xinput_ctrl_map[] = { {XINPUT_GAMEPAD_DPAD_DOWN, KEYCODE_DPAD_DOWN}, {XINPUT_GAMEPAD_DPAD_LEFT, KEYCODE_DPAD_LEFT}, {XINPUT_GAMEPAD_DPAD_RIGHT, KEYCODE_DPAD_RIGHT}, + {XINPUT_GUIDE_BUTTON, KEYCODE_HOME}, }; static const unsigned int xinput_ctrl_map_size = sizeof(xinput_ctrl_map) / sizeof(xinput_ctrl_map[0]); XinputDevice::XinputDevice() { + if (LoadXInputDLL() != 0) { + ERROR_LOG(HLE, "Failed to load XInput! DLL missing"); + } ZeroMemory( &this->prevState, sizeof(this->prevState) ); this->check_delay = 0; this->gamepad_idx = -1; } +XinputDevice::~XinputDevice() { + UnloadXInputDLL(); +} + struct Stick { float x; float y; @@ -52,11 +121,11 @@ int XinputDevice::UpdateState(InputState &input_state) { DWORD dwResult; if (this->gamepad_idx >= 0) - dwResult = XInputGetState( this->gamepad_idx, &state ); + dwResult = PPSSPP_XInputGetState( this->gamepad_idx, &state ); else { // use the first gamepad that responds for (int i = 0; i < XUSER_MAX_COUNT; i++) { - dwResult = XInputGetState( i, &state ); + dwResult = PPSSPP_XInputGetState( i, &state ); if (dwResult == ERROR_SUCCESS) { this->gamepad_idx = i; break; diff --git a/Windows/XinputDevice.h b/Windows/XinputDevice.h index 926221cc1c..d29f4db27a 100644 --- a/Windows/XinputDevice.h +++ b/Windows/XinputDevice.h @@ -1,12 +1,13 @@ #pragma once + #include "InputDevice.h" #include "Xinput.h" -class XinputDevice : - public InputDevice -{ + +class XinputDevice : public InputDevice { public: XinputDevice(); + ~XinputDevice(); virtual int UpdateState(InputState &input_state); virtual bool IsPad() { return true; } private: @@ -15,5 +16,4 @@ private: int check_delay; XINPUT_STATE prevState; u32 prevButtons; -}; - +}; \ No newline at end of file diff --git a/native b/native index ee0f384827..b7c8b8ddef 160000 --- a/native +++ b/native @@ -1 +1 @@ -Subproject commit ee0f3848272b6eb5446b468a1c55868e3b3c455c +Subproject commit b7c8b8ddef4e22324b768129f53a10382684259a