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