Add check init Controls Dialog and ControlMapping constructor

This commit is contained in:
nachume 2013-05-17 19:31:06 +09:00 committed by Henrik Rydgard
parent 9af5499b21
commit 4062059c2e
12 changed files with 835 additions and 151 deletions

223
Windows/ControlMapping.cpp Normal file
View file

@ -0,0 +1,223 @@
// Copyright (c) 2012- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "ControlMapping.h"
#include "DinputDevice.h"
#include "XinputDevice.h"
extern unsigned int key_pad_map[];
extern unsigned short analog_ctrl_map[];
extern unsigned int dinput_ctrl_map[];
extern unsigned int xinput_ctrl_map[];
#define DINPUT_CAST(inst) static_cast<std::shared_ptr<DinputDevice>>(inst)
inline UINT* ControlMapping::GetDeviceButtonsMap(UINT curDevice)
{
switch (curDevice)
{
case CONTROLS_KEYBOARD_INDEX:
return pButtonsMap;
case CONTROLS_DIRECT_INPUT_INDEX:
return pButtonsMap + buttonsCount;
case CONTROLS_XINPUT_INDEX:
return pButtonsMap + (buttonsCount * 2);
}
return NULL;
}
ControlMapping * ControlMapping::CreateInstance(UINT nButtons)
{
if (nButtons != (key_pad_map_size / sizeof(key_pad_map[0]) / 2))
return FALSE;
if (nButtons != (dinput_ctrl_map_size / sizeof(dinput_ctrl_map[0]) / 2))
return FALSE;
if (nButtons != (xinput_ctrl_map_size / sizeof(xinput_ctrl_map[0]) / 2))
return FALSE;
if (4 != (analog_ctrl_map_size / sizeof(analog_ctrl_map[0]) / 2))
return FALSE;
auto inst = new ControlMapping(nButtons);
if (!inst->pButtonsMap)
return FALSE;
return inst;
}
ControlMapping::ControlMapping(UINT nButtons) :
currentDevicePage(-1),
currentButtonIndex(-1),
pButtonsMap(0),
buttonsCount(nButtons),
dinput(0),
xinput(0)
{
dinput = std::shared_ptr<DinputDevice>(new DinputDevice());
xinput = std::shared_ptr<XinputDevice>(new XinputDevice());
pButtonsMap = new UINT[3 * nButtons];
ZeroMemory(pButtonsMap, sizeof(UINT) * CONTROLS_DEVICE_NUM * nButtons);
for (int i = 0; i < nButtons; i++) {
*(GetDeviceButtonsMap(CONTROLS_KEYBOARD_INDEX) + i) = key_pad_map[i * 2];
*(GetDeviceButtonsMap(CONTROLS_DIRECT_INPUT_INDEX) + i) = dinput_ctrl_map[i * 2];
*(GetDeviceButtonsMap(CONTROLS_XINPUT_INDEX) + i) = xinput_ctrl_map[i * 2];
}
ZeroMemory(&keyboardAnalogMap, sizeof(keyboardAnalogMap));
for (int i = 0; i < 4; i++) {
keyboardAnalogMap[i] = analog_ctrl_map[i * 2];
}
}
ControlMapping::~ControlMapping()
{
if (pButtonsMap) {
delete [] pButtonsMap;
pButtonsMap = NULL;
}
}
void ControlMapping::UpdateState()
{
rawState.button = -1;
switch(currentDevicePage)
{
case CONTROLS_KEYBOARD_INDEX: // keyboard
{
; // leave it to KeyboardProc.
}
break;
case CONTROLS_DIRECT_INPUT_INDEX: // directinput
{
dinput->UpdateRawStateSingle(rawState);
UINT newButton = (rawState.button != rawState.prevButton && rawState.prevButton == -1)
? rawState.button : -1;
if (newButton != -1) {
SetBindCode(newButton);
}
}
break;
case CONTROLS_XINPUT_INDEX: // xinput
{
xinput->UpdateRawStateSingle(rawState);
UINT newButton = (rawState.button != rawState.prevButton && rawState.prevButton == -1)
? rawState.button : -1;
if (newButton != -1) {
SetBindCode(newButton);
}
}
break;
}
rawState.prevButton = rawState.button;
}
void ControlMapping::BindToDevices()
{
for (int i = 0; i < buttonsCount; i++) {
key_pad_map[i * 2] = *(GetDeviceButtonsMap(CONTROLS_KEYBOARD_INDEX) + i);
dinput_ctrl_map[i * 2] = *(GetDeviceButtonsMap(CONTROLS_DIRECT_INPUT_INDEX) + i);
xinput_ctrl_map[i * 2] = *(GetDeviceButtonsMap(CONTROLS_XINPUT_INDEX) + i);
}
for (int i = 0; i < 4; i++) {
analog_ctrl_map[i * 2] = keyboardAnalogMap[i];
}
}
void ControlMapping::SetBindCode(UINT newCode)
{
SetBindCode(newCode, currentDevicePage, currentButtonIndex);
}
void ControlMapping::SetBindCode(UINT newCode, UINT buttonIdx)
{
SetBindCode(newCode, currentDevicePage, buttonIdx);
}
void ControlMapping::SetBindCode(UINT newCode, UINT deviceIdx, UINT buttonIdx)
{
if (deviceIdx < CONTROLS_DEVICE_NUM && buttonIdx < buttonsCount)
*(GetDeviceButtonsMap(deviceIdx) + buttonIdx) = newCode;
}
UINT ControlMapping::GetBindCode(UINT deviceIdx, UINT buttonIdx)
{
if (deviceIdx < CONTROLS_DEVICE_NUM && buttonIdx < buttonsCount)
return *(GetDeviceButtonsMap(deviceIdx) + buttonIdx);
return -1;
}
UINT ControlMapping::GetBindCode(UINT buttonIdx)
{
return GetBindCode(currentDevicePage, buttonIdx);
}
UINT ControlMapping::GetBindCode()
{
return GetBindCode(currentDevicePage, currentButtonIndex);
}
UINT ControlMapping::GetTargetDevice()
{
return currentDevicePage;
}
void ControlMapping::SetTargetDevice(UINT deviceIdx)
{
rawState.prevButton = -1;
currentDevicePage = deviceIdx;
}
UINT ControlMapping::GetTargetButton()
{
return currentButtonIndex;
}
void ControlMapping::SetTargetButton(UINT buttonIdx)
{
currentButtonIndex = buttonIdx;
}
bool saveControlsToFile() {
FILE *wfp = fopen("PPSSPPControls.dat", "wb");
if (!wfp)
return false;
fwrite(key_pad_map, 1, key_pad_map_size, wfp);
fwrite(analog_ctrl_map, 1, analog_ctrl_map_size, wfp);
fwrite(dinput_ctrl_map, 1, dinput_ctrl_map_size, wfp);
fwrite(xinput_ctrl_map, 1, xinput_ctrl_map_size, wfp);
fclose(wfp);
return true;
}
bool loadControlsFromFile() {
FILE *rfp = fopen("PPSSPPControls.dat", "rb");
if (!rfp)
return false;
fseek(rfp, 0, SEEK_END);
fpos_t fsize = 0;
fgetpos(rfp, &fsize);
if (fsize != (key_pad_map_size + analog_ctrl_map_size + dinput_ctrl_map_size + xinput_ctrl_map_size))
return false;
fseek(rfp, 0, SEEK_SET);
fread(key_pad_map, 1, key_pad_map_size, rfp);
fread(analog_ctrl_map, 1, analog_ctrl_map_size, rfp);
fread(dinput_ctrl_map, 1, dinput_ctrl_map_size, rfp);
fread(xinput_ctrl_map, 1, xinput_ctrl_map_size, rfp);
fclose(rfp);
return true;
}

86
Windows/ControlMapping.h Normal file
View file

@ -0,0 +1,86 @@
// Copyright (c) 2012- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#pragma once
#include "InputDevice.h"
struct RawInputState
{
UINT button;
UINT prevButton;
RawInputState() {
button = 0;
prevButton = 0;
}
};
#define POV_CODE_UP 0x0100
#define POV_CODE_DOWN 0x0200
#define POV_CODE_LEFT 0x0400
#define POV_CODE_RIGHT 0x0800
#define XBOX_CODE_LEFTTRIGER 0x00010000
#define XBOX_CODE_RIGHTTRIGER 0x00020000
#define CONTROLS_KEYBOARD_INDEX 0
#define CONTROLS_DIRECT_INPUT_INDEX 1
#define CONTROLS_XINPUT_INDEX 2
#define CONTROLS_DEVICE_NUM 3
extern bool saveControlsToFile();
extern bool loadControlsFromFile();
extern const unsigned int xinput_ctrl_map_size;
extern const unsigned int key_pad_map_size;
extern const unsigned int analog_ctrl_map_size;
extern const unsigned int dinput_ctrl_map_size;
struct RawInputState;
class DinputDevice;
class XinputDevice;
class ControlMapping
{
public:
static ControlMapping * CreateInstance(UINT nButtons);
virtual ~ControlMapping();
void UpdateState();
void BindToDevices();
void SetTargetDevice(UINT deviceIdx);
UINT GetTargetDevice();
void SetTargetButton(UINT buttonIdx);
UINT GetTargetButton();
void SetBindCode(UINT newCode);
UINT GetBindCode();
UINT GetBindCode(UINT buttonIdx);
UINT GetBindCode(UINT deviceIdx, UINT buttonIdx);
private:
ControlMapping(UINT nButtons);
ControlMapping();
inline UINT* GetDeviceButtonsMap(UINT curDevice);
void SetBindCode(UINT newCode, UINT buttonIdx);
void SetBindCode(UINT newCode, UINT deviceIdx, UINT buttonIdx);
std::shared_ptr<DinputDevice> dinput;
std::shared_ptr<XinputDevice> xinput;
UINT currentDevicePage;
UINT currentButtonIndex;
UINT buttonsCount;
RawInputState rawState;
UINT *pButtonsMap;
USHORT keyboardAnalogMap[4];
};

View file

@ -16,24 +16,36 @@
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include <limits.h>
#include "Core/HLE/sceCtrl.h"
#include "DinputDevice.h"
#include "ControlMapping.h"
#include "Core/Config.h"
#include "input/input_state.h"
#include "Core/Reporting.h"
#include "Xinput.h"
#pragma comment(lib,"dinput8.lib")
static const unsigned int dinput_ctrl_map[] = {
9, PAD_BUTTON_START,
unsigned int dinput_ctrl_map[] = {
11, PAD_BUTTON_MENU, // Open PauseScreen
10, PAD_BUTTON_BACK, // Toggle PauseScreen & Back Setting Page
1, PAD_BUTTON_A, // Cross = XBOX-A
2, PAD_BUTTON_B, // Circle = XBOX-B
0, PAD_BUTTON_X, // Square = XBOX-X
3, PAD_BUTTON_Y, // Triangle = XBOX-Y
8, PAD_BUTTON_SELECT,
4, PAD_BUTTON_LBUMPER,
5, PAD_BUTTON_RBUMPER,
1, PAD_BUTTON_A,
2, PAD_BUTTON_B,
0, PAD_BUTTON_X,
3, PAD_BUTTON_Y,
9, PAD_BUTTON_START,
4, PAD_BUTTON_LBUMPER, // LTrigger = XBOX-LBumper
5, PAD_BUTTON_RBUMPER, // RTrigger = XBOX-RBumper
6, PAD_BUTTON_LEFT_THUMB, // Turbo
7, PAD_BUTTON_RIGHT_THUMB, // Open PauseScreen
POV_CODE_UP, PAD_BUTTON_UP,
POV_CODE_DOWN, PAD_BUTTON_DOWN,
POV_CODE_LEFT, PAD_BUTTON_LEFT,
POV_CODE_RIGHT, PAD_BUTTON_RIGHT,
};
const unsigned int dinput_ctrl_map_size = sizeof(dinput_ctrl_map);
#define DIFF (JOY_POVRIGHT - JOY_POVFORWARD) / 2
#define JOY_POVFORWARD_RIGHT JOY_POVFORWARD + DIFF
#define JOY_POVRIGHT_BACKWARD JOY_POVRIGHT + DIFF
@ -119,6 +131,16 @@ DinputDevice::~DinputDevice()
}
}
static inline int getPadCodeFromVirtualPovCode(unsigned int povCode)
{
int mergedCode = 0;
for (int i = 0; i < dinput_ctrl_map_size / sizeof(dinput_ctrl_map[0]); i += 2) {
if (dinput_ctrl_map[i] > 0xFF && dinput_ctrl_map[i] & povCode)
mergedCode |= dinput_ctrl_map[i + 1];
}
return mergedCode;
}
int DinputDevice::UpdateState(InputState &input_state)
{
if (g_Config.iForceInputDevice == 0) return -1;
@ -134,17 +156,16 @@ int DinputDevice::UpdateState(InputState &input_state)
if(FAILED(pJoystick->GetDeviceState(sizeof(DIJOYSTATE2), &js)))
return -1;
switch (js.rgdwPOV[0])
{
case JOY_POVFORWARD: input_state.pad_buttons |= PAD_BUTTON_UP; break;
case JOY_POVBACKWARD: input_state.pad_buttons |= PAD_BUTTON_DOWN; break;
case JOY_POVLEFT: input_state.pad_buttons |= PAD_BUTTON_LEFT; break;
case JOY_POVRIGHT: input_state.pad_buttons |= PAD_BUTTON_RIGHT; break;
case JOY_POVFORWARD_RIGHT: input_state.pad_buttons |= (PAD_BUTTON_UP | PAD_BUTTON_RIGHT); break;
case JOY_POVRIGHT_BACKWARD: input_state.pad_buttons |= (PAD_BUTTON_RIGHT | PAD_BUTTON_DOWN); break;
case JOY_POVBACKWARD_LEFT: input_state.pad_buttons |= (PAD_BUTTON_DOWN | PAD_BUTTON_LEFT); break;
case JOY_POVLEFT_FORWARD: input_state.pad_buttons |= (PAD_BUTTON_LEFT | PAD_BUTTON_UP); break;
case JOY_POVFORWARD: input_state.pad_buttons |= getPadCodeFromVirtualPovCode(POV_CODE_UP); break;
case JOY_POVBACKWARD: input_state.pad_buttons |= getPadCodeFromVirtualPovCode(POV_CODE_DOWN); break;
case JOY_POVLEFT: input_state.pad_buttons |= getPadCodeFromVirtualPovCode(POV_CODE_LEFT); break;
case JOY_POVRIGHT: input_state.pad_buttons |= getPadCodeFromVirtualPovCode(POV_CODE_RIGHT); break;
case JOY_POVFORWARD_RIGHT: input_state.pad_buttons |= getPadCodeFromVirtualPovCode(POV_CODE_UP | POV_CODE_RIGHT); break;
case JOY_POVRIGHT_BACKWARD: input_state.pad_buttons |= getPadCodeFromVirtualPovCode(POV_CODE_RIGHT | POV_CODE_DOWN); break;
case JOY_POVBACKWARD_LEFT: input_state.pad_buttons |= getPadCodeFromVirtualPovCode(POV_CODE_DOWN | POV_CODE_LEFT); break;
case JOY_POVLEFT_FORWARD: input_state.pad_buttons |= getPadCodeFromVirtualPovCode(POV_CODE_LEFT | POV_CODE_UP); break;
}
if (analog)
@ -155,7 +176,8 @@ int DinputDevice::UpdateState(InputState &input_state)
for (u8 i = 0; i < sizeof(dinput_ctrl_map)/sizeof(dinput_ctrl_map[0]); i += 2)
{
if (js.rgbButtons[dinput_ctrl_map[i]] & 0x80)
// DIJOYSTATE2 supported 128 buttons. for exclude the Virtual POV_CODE bit fields.
if (dinput_ctrl_map[i] < DIRECTINPUT_RGBBUTTONS_MAX && js.rgbButtons[dinput_ctrl_map[i]] & 0x80)
{
input_state.pad_buttons |= dinput_ctrl_map[i+1];
}
@ -164,3 +186,34 @@ int DinputDevice::UpdateState(InputState &input_state)
return UPDATESTATE_SKIP_PAD;
}
int DinputDevice::UpdateRawStateSingle(RawInputState &rawState)
{
if (g_Config.iForceInputDevice == 0) return FALSE;
if (!pJoystick) return FALSE;
DIJOYSTATE2 js;
if (FAILED(pJoystick->Poll()))
{
if(pJoystick->Acquire() == DIERR_INPUTLOST)
return FALSE;
}
if(FAILED(pJoystick->GetDeviceState(sizeof(DIJOYSTATE2), &js)))
return -1;
switch (js.rgdwPOV[0])
{
case JOY_POVFORWARD: rawState.button = POV_CODE_UP; return TRUE;
case JOY_POVBACKWARD: rawState.button = POV_CODE_DOWN; return TRUE;
case JOY_POVLEFT: rawState.button = POV_CODE_LEFT; return TRUE;
case JOY_POVRIGHT: rawState.button = POV_CODE_RIGHT; return TRUE;
}
for (int i = 0; i < DIRECTINPUT_RGBBUTTONS_MAX; i++) {
if (js.rgbButtons[i] & 0x80) {
rawState.button = i;
return TRUE;
}
}
return FALSE;
}

View file

@ -18,9 +18,12 @@
#pragma once
#include <InitGuid.h>
#define DIRECTINPUT_VERSION 0x0800
#define DIRECTINPUT_RGBBUTTONS_MAX 128
#include "InputDevice.h"
#include "dinput.h"
struct RawInputState;
class DinputDevice :
public InputDevice
{
@ -29,9 +32,9 @@ public:
~DinputDevice();
virtual int UpdateState(InputState &input_state);
virtual bool IsPad() { return true; }
int UpdateRawStateSingle(RawInputState &rawState);
private:
LPDIRECTINPUT8 pDI;
LPDIRECTINPUTDEVICE8 pJoystick;
bool analog;
};

View file

@ -1,4 +1,5 @@
#include "input/input_state.h"
#include "ControlMapping.h"
#include "Windows/WndMainWindow.h"
#include "KeyboardDevice.h"
#include "../Common/CommonTypes.h"
@ -6,21 +7,24 @@
#include "WinUser.h"
unsigned int key_pad_map[] = {
VK_TAB, PAD_BUTTON_UNTHROTTLE,
VK_SPACE, PAD_BUTTON_START,
'V', PAD_BUTTON_SELECT,
VK_ESCAPE,PAD_BUTTON_MENU, // Open PauseScreen
VK_BACK, PAD_BUTTON_BACK, // Toggle PauseScreen & Back Setting Page
'Z', PAD_BUTTON_A,
'X', PAD_BUTTON_B,
'A', PAD_BUTTON_X,
'S', PAD_BUTTON_Y,
'X', PAD_BUTTON_B,
'Z', PAD_BUTTON_A,
'V', PAD_BUTTON_SELECT,
VK_SPACE, PAD_BUTTON_START,
'Q', PAD_BUTTON_LBUMPER,
'W', PAD_BUTTON_RBUMPER,
VK_TAB, PAD_BUTTON_LEFT_THUMB, // Turbo
VK_PAUSE, PAD_BUTTON_RIGHT_THUMB, // Open PauseScreen
VK_UP, PAD_BUTTON_UP,
VK_DOWN, PAD_BUTTON_DOWN,
VK_LEFT, PAD_BUTTON_LEFT,
VK_RIGHT, PAD_BUTTON_RIGHT,
VK_F3, PAD_BUTTON_LEFT_THUMB,
};
const unsigned int key_pad_map_size = sizeof(key_pad_map);
unsigned short analog_ctrl_map[] = {
'I', CTRL_UP,
@ -28,6 +32,7 @@ unsigned short analog_ctrl_map[] = {
'J', CTRL_LEFT,
'L', CTRL_RIGHT,
};
const unsigned int analog_ctrl_map_size = sizeof(analog_ctrl_map);
int KeyboardDevice::UpdateState(InputState &input_state) {
if (MainWindow::GetHWND() != GetForegroundWindow()) return -1;
@ -190,22 +195,3 @@ const char * getVirtualKeyName(unsigned char key)
return 0;
}
bool saveControlsToFile() {
FILE *wfp = fopen("PPSSPPControls.dat", "wb");
if (!wfp)
return false;
fwrite(key_pad_map, 1, sizeof(key_pad_map), wfp);
fwrite(analog_ctrl_map, 1, sizeof(analog_ctrl_map), wfp);
fclose(wfp);
return true;
}
bool loadControlsFromFile() {
FILE *rfp = fopen("PPSSPPControls.dat", "rb");
if (!rfp)
return false;
fread(key_pad_map, 1, sizeof(key_pad_map), rfp);
fread(analog_ctrl_map, 1, sizeof(analog_ctrl_map), rfp);
fclose(rfp);
return true;
}

View file

@ -251,6 +251,7 @@
<ForcedIncludeFiles Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
</ForcedIncludeFiles>
</ClCompile>
<ClCompile Include="ControlMapping.cpp" />
<ClCompile Include="Debugger\CtrlDisAsmView.cpp" />
<ClCompile Include="Debugger\CtrlMemView.cpp" />
<ClCompile Include="Debugger\CtrlRegisterList.cpp" />
@ -288,6 +289,7 @@
<ItemGroup>
<ClInclude Include="..\android\jni\ARMEmitterTest.h" />
<ClInclude Include="..\android\jni\TestRunner.h" />
<ClInclude Include="ControlMapping.h" />
<ClInclude Include="Debugger\CtrlDisAsmView.h" />
<ClInclude Include="Debugger\CtrlMemView.h" />
<ClInclude Include="Debugger\CtrlRegisterList.h" />

View file

@ -98,6 +98,9 @@
<ClCompile Include="DinputDevice.cpp">
<Filter>Windows\Input</Filter>
</ClCompile>
<ClCompile Include="ControlMapping.cpp">
<Filter>Windows\Input</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Debugger\CtrlDisAsmView.h">
@ -173,6 +176,9 @@
<ClInclude Include="DinputDevice.h">
<Filter>Windows\Input</Filter>
</ClInclude>
<ClInclude Include="ControlMapping.h">
<Filter>Windows\Input</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="icon1.ico">

View file

@ -35,6 +35,7 @@
#include "GPU/GPUState.h"
#include "native/image/png_load.h"
#include "GPU/GLES/TextureScaler.h"
#include "ControlMapping.h"
#ifdef THEMES
#include "XPTheme.h"
@ -46,13 +47,10 @@ BOOL g_bFullScreen = FALSE;
static RECT g_normalRC = {0};
extern InputState input_state;
extern const char * getVirtualKeyName(unsigned char key);
extern const char * getXinputButtonName(unsigned int button);
#define TIMER_CURSORUPDATE 1
#define CURSORUPDATE_INTERVAL_MS 50
extern unsigned short analog_ctrl_map[];
extern unsigned int key_pad_map[];
extern const char * getVirtualKeyName(unsigned char key);
extern bool saveControlsToFile();
extern bool loadControlsFromFile();
namespace MainWindow
{
@ -922,30 +920,48 @@ namespace MainWindow
return FALSE;
}
#define CONTROLS_IDC_EDIT_BIGIN IDC_EDIT_KEY_MENU
#define CONTROLS_IDC_EDIT_END IDC_EDIT_KEY_ANALOG_RIGHT
#define CONTROLS_BUTTONS_COUNT IDC_EDIT_KEYRIGHT - CONTROLS_IDC_EDIT_BIGIN + 1
#define CONTROLS_BUTTONNAME_MAX 16
// for controls dialog device polling and bind update.
#define TIMER_CONTROLS_BINDUPDATE 1
#define BINDUPDATE_INTERVAL_MS 50
static const char *controllist[] = {
"TURBO MODE\tHold TAB",
"Start\tSpace",
"Select\tV",
"Square\tA",
"Triangle\tS",
"Circle\tX",
"Cross\tZ",
"Left Trigger\tQ",
"Right Trigger\tW",
"Up\tArrow Up",
"Down\tArrow Down",
"Left\tArrow Left",
"Right\tArrow Right",
"Analog Up\tI",
"Analog Down\tK",
"Analog Left\tJ",
"Analog Right\tL",
"Rapid Fire\tShift",
"Menu", // Open PauseScreen
"Back", // Toggle PauseScreen & Back Setting Page.
"Triangle",
"Rectangle",
"Cross",
"Circle",
"Select",
"Start",
"Left Trigger",
"Right Trigger",
"Turbo", // LBUMPER (Turbo)
"Reserved", // RBUMPER (Open PauseScreen)
"Up",
"Down",
"Left",
"Right",
"LY+",
"LY-",
"LX-",
"LX+",
};
static HHOOK pKeydownHook;
static const int control_map_size = IDC_EDIT_KEY_ANALOG_RIGHT - IDC_EDIT_KEY_TURBO + 1;
static u8 control_map[control_map_size];
struct ControlsDlgState {
HHOOK pKeydownHook;
HBITMAP hbmPspImage;
HWND hCtrlTab;
UINT_PTR timerId;
WNDPROC orgPSPImageProc;
ControlMapping *pCtrlMap;
HWND hStaticPspImage;
};
static ControlsDlgState *pCtrlDlgState;
RECT getRedrawRect(HWND hWnd) {
RECT rc;
HWND hDlg = GetParent(hWnd);
@ -962,23 +978,25 @@ namespace MainWindow
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
HWND hEdit = GetFocus();
UINT nCtrlID = GetDlgCtrlID(hEdit);
if (nCtrlID < IDC_EDIT_KEY_TURBO || nCtrlID > IDC_EDIT_KEY_ANALOG_RIGHT) {
return CallNextHookEx(pKeydownHook, nCode, wParam, lParam);
}
if (!(lParam&(1<<31))) {
// key down
HWND hDlg = GetParent(hEdit);
const char *str = getVirtualKeyName(wParam);
if (str) {
control_map[nCtrlID - IDC_EDIT_KEY_TURBO] = wParam;
SetWindowTextA(hEdit, str);
RECT rc = getRedrawRect(hEdit);
InvalidateRect(hDlg, &rc, false);
if (pCtrlDlgState->pCtrlMap->GetTargetDevice() == CONTROLS_KEYBOARD_INDEX) {
HWND hEdit = GetFocus();
UINT nCtrlID = GetDlgCtrlID(hEdit);
if (nCtrlID < CONTROLS_IDC_EDIT_BIGIN || nCtrlID > CONTROLS_IDC_EDIT_END) {
return CallNextHookEx(pCtrlDlgState->pKeydownHook, nCode, wParam, lParam);
}
if (!(lParam&(1<<31))) {
// key down
HWND hDlg = GetParent(hEdit);
const char *str = getVirtualKeyName(wParam);
if (str) {
pCtrlDlgState->pCtrlMap->SetBindCode(wParam);
SetWindowTextA(hEdit, str);
RECT rc = getRedrawRect(hEdit);
InvalidateRect(hDlg, &rc, false);
}
else
MessageBoxA(hDlg, "Not supported!", "controller", MB_OK);
}
else
MessageBoxA(hDlg, "Not supported!", "controller", MB_OK);
}
return 1;
}
@ -1011,22 +1029,85 @@ namespace MainWindow
DeleteObject(hCompDC);
}
// Draw background image of Controls Dialog (pspmode.png) by use static control.
LRESULT CALLBACK PSPImageProc(HWND hStatic, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message) {
case WM_PAINT:
{
PAINTSTRUCT pst;
HDC hdc = BeginPaint(hStatic, &pst);
BITMAP bm;
GetObject(pCtrlDlgState->hbmPspImage, sizeof(BITMAP), &bm);
BitBlt(pCtrlDlgState->hbmPspImage, hdc, 0, 0, bm.bmWidth, bm.bmHeight, 0 , 0);
EndPaint(hStatic, &pst);
return TRUE;
}
default:
break;
}
return CallWindowProc(pCtrlDlgState->orgPSPImageProc, hStatic, message, wParam, lParam);
}
// Message handler for control box.
LRESULT CALLBACK Controls(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
static HBITMAP hbm = 0;
{
switch (message)
{
case WM_INITDIALOG:
W32Util::CenterWindow(hDlg);
{
// IDC_EDIT_xxx is need continuous value to IDC_EDIT_KEY_ANALOG_RIGHT from IDC_EDIT_KEY_MENU.
// it is total 16.
// it is need the same order as the dinput_ctrl_map(and xinput/keyboard).
if (CONTROLS_BUTTONS_COUNT != 16) {
char mes[100];
snprintf(mes, 100, "CONTROLS_BUTTONS_COUNT(%d) is need 16.", CONTROLS_BUTTONS_COUNT);
MessageBoxA(hDlg, mes, "Controls dialog init error.", MB_OK);
}
pCtrlDlgState = new ControlsDlgState();
ZeroMemory(pCtrlDlgState, sizeof(ControlsDlgState));
pCtrlDlgState->pCtrlMap = ControlMapping::CreateInstance(CONTROLS_BUTTONS_COUNT);
if (!pCtrlDlgState->pCtrlMap) {
MessageBoxA(hDlg, "Cannot Created ControlMapping instance.", "Controls dialog init error.", MB_OK);
}
pCtrlDlgState->pCtrlMap->SetTargetDevice(CONTROLS_KEYBOARD_INDEX);
pCtrlDlgState->hCtrlTab = GetDlgItem(hDlg, IDC_TAB_INPUT_DEVICE);
TCITEM tcItem;
ZeroMemory(&tcItem, sizeof(tcItem));
tcItem.mask = TCIF_TEXT;
tcItem.dwState = 0;
tcItem.pszText = "Keyboard";
tcItem.cchTextMax = (int)strlen(tcItem.pszText)+1;
tcItem.iImage = 0;
TabCtrl_InsertItem(pCtrlDlgState->hCtrlTab, TabCtrl_GetItemCount(pCtrlDlgState->hCtrlTab),&tcItem);
tcItem.pszText = "DirectInput";
tcItem.cchTextMax = (int)strlen(tcItem.pszText)+1;
TabCtrl_InsertItem(pCtrlDlgState->hCtrlTab, TabCtrl_GetItemCount(pCtrlDlgState->hCtrlTab),&tcItem);
tcItem.pszText = "XInput";
tcItem.cchTextMax = (int)strlen(tcItem.pszText)+1;
TabCtrl_InsertItem(pCtrlDlgState->hCtrlTab, TabCtrl_GetItemCount(pCtrlDlgState->hCtrlTab),&tcItem);
int tp_w = 0, tp_h = 0;
// TODO: connect to keyboard device instead
{
HBITMAP hResBM = LoadImageFromResource(hInst, MAKEINTRESOURCE(IDB_IMAGE_PSP), "IMAGE");
HDC hDC = GetDC(hDlg);
RECT clientRect;
pCtrlDlgState->hStaticPspImage = GetDlgItem(hDlg,IDC_STATIC_IMAGE_PSP);
RECT clientRect, tabPageRect, imgRect;
GetClientRect(hDlg, &clientRect);
HBITMAP hMemBM = CreateCompatibleBitmap(hDC, clientRect.right, clientRect.bottom);
memcpy(&tabPageRect, &clientRect, sizeof(RECT));
TabCtrl_AdjustRect(pCtrlDlgState->hCtrlTab, FALSE, &tabPageRect);
tp_w = tabPageRect.right - tabPageRect.left;
tp_h = tabPageRect.bottom - tabPageRect.top;
MoveWindow(pCtrlDlgState->hStaticPspImage, tabPageRect.left, tabPageRect.top, tp_w, tp_h, FALSE);
HDC hDC = GetDC(pCtrlDlgState->hStaticPspImage);
HBITMAP hMemBM = CreateCompatibleBitmap(hDC, tp_w, tp_h);
HDC hResDC = CreateCompatibleDC(hDC);
HDC hMemDC = CreateCompatibleDC(hDC);
SelectObject(hResDC, hResBM);
@ -1035,24 +1116,28 @@ namespace MainWindow
BITMAP bm;
GetObject(hResBM, sizeof(BITMAP), &bm);
SetStretchBltMode(hMemDC, HALFTONE);
StretchBlt(hMemDC, 0, 0, clientRect.right, clientRect.bottom, hResDC, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
if (hbm)
DeleteObject(hbm);
hbm = hMemBM;
float scaleX = (float)bm.bmWidth / clientRect.right;
float scaleY = (float)bm.bmHeight / clientRect.bottom;
imgRect.left = (int)(tabPageRect.left * scaleX);
imgRect.top = (int)(tabPageRect.top * scaleY);
imgRect.right= (int)(bm.bmWidth - ((clientRect.right - tabPageRect.right) * scaleX));
imgRect.bottom = (int)(bm.bmHeight - ((clientRect.bottom - tabPageRect.bottom) * scaleY));
StretchBlt(hMemDC, 0, 0, tp_w, tp_h, hResDC, imgRect.left, imgRect.top,
imgRect.right - imgRect.left, imgRect.bottom - imgRect.top, SRCCOPY);
if (pCtrlDlgState->hbmPspImage)
DeleteObject(pCtrlDlgState->hbmPspImage);
pCtrlDlgState->hbmPspImage = hMemBM;
DeleteDC(hMemDC);
DeleteDC(hResDC);
ReleaseDC(hDlg, hDC);
ReleaseDC(pCtrlDlgState->hStaticPspImage, hDC);
DeleteObject(hResBM);
}
int key_pad_size = (IDC_EDIT_KEYRIGHT - IDC_EDIT_KEY_TURBO + 1);
for (u32 i = 0; i <= IDC_EDIT_KEY_ANALOG_RIGHT - IDC_EDIT_KEY_TURBO; i++) {
HWND hEdit = GetDlgItem(hDlg, IDC_EDIT_KEY_TURBO + i);
if (IDC_EDIT_KEY_TURBO + i <= IDC_EDIT_KEYRIGHT)
control_map[i] = key_pad_map[i * 2];
else
control_map[i] = analog_ctrl_map[(i - key_pad_size) * 2];
SetWindowTextA(hEdit, getVirtualKeyName(control_map[i]));
for (u32 i = 0; i <= CONTROLS_IDC_EDIT_END - CONTROLS_IDC_EDIT_BIGIN; i++) {
HWND hEdit = GetDlgItem(hDlg, CONTROLS_IDC_EDIT_BIGIN + i);
SetWindowTextA(hEdit, getVirtualKeyName(pCtrlDlgState->pCtrlMap->GetBindCode(CONTROLS_KEYBOARD_INDEX, i)));
}
ComboBox_AddString(GetDlgItem(hDlg, IDC_FORCE_INPUT_DEVICE), "None");
ComboBox_AddString(GetDlgItem(hDlg, IDC_FORCE_INPUT_DEVICE), "XInput");
@ -1065,28 +1150,171 @@ namespace MainWindow
{
ComboBox_SetCurSel(GetDlgItem(hDlg, IDC_FORCE_INPUT_DEVICE), (g_Config.iForceInputDevice + 1));
}
pCtrlDlgState->orgPSPImageProc = (WNDPROC)GetWindowLong(pCtrlDlgState->hStaticPspImage, GWL_WNDPROC);
SetWindowLong(pCtrlDlgState->hStaticPspImage, GWL_WNDPROC, (LONG)PSPImageProc);
DWORD dwThreadID = GetWindowThreadProcessId(hDlg, NULL);
pKeydownHook = SetWindowsHookEx(WH_KEYBOARD,KeyboardProc, NULL, dwThreadID);
pCtrlDlgState->pKeydownHook = SetWindowsHookEx(WH_KEYBOARD,KeyboardProc, NULL, dwThreadID);
pCtrlDlgState->timerId = SetTimer(hDlg, TIMER_CONTROLS_BINDUPDATE, BINDUPDATE_INTERVAL_MS, 0);
}
return TRUE;
case WM_TIMER:
{
if (wParam == TIMER_CONTROLS_BINDUPDATE &&
pCtrlDlgState->pCtrlMap->GetTargetDevice() != CONTROLS_KEYBOARD_INDEX) {
HWND hEdit = GetFocus();
UINT nCtrlID = GetDlgCtrlID(hEdit);
if (nCtrlID < CONTROLS_IDC_EDIT_BIGIN || nCtrlID > IDC_EDIT_KEYRIGHT) {
break;
}
// device polling and update.
int prevButton = pCtrlDlgState->pCtrlMap->GetBindCode();
pCtrlDlgState->pCtrlMap->UpdateState();
char str[CONTROLS_BUTTONNAME_MAX];
ZeroMemory(str, CONTROLS_BUTTONNAME_MAX * sizeof(char));
int buttonCode = pCtrlDlgState->pCtrlMap->GetBindCode();
if (buttonCode == -1 || prevButton == buttonCode)
break;
switch(pCtrlDlgState->pCtrlMap->GetTargetDevice())
{
case CONTROLS_KEYBOARD_INDEX:
{
; // leave it to KeyboardProc.
}
break;
case CONTROLS_DIRECT_INPUT_INDEX:
{
if (buttonCode > 0xFF) {
int n = 1;
for (int i = buttonCode >> 8; i > 1; i >>= 1) {
n++;
}
snprintf(str, CONTROLS_BUTTONNAME_MAX, "%s",
controllist[(IDC_EDIT_KEYUP - CONTROLS_IDC_EDIT_BIGIN - 1) + n]);
} else {
snprintf(str, CONTROLS_BUTTONNAME_MAX, "%d", buttonCode + 1);
}
SetWindowTextA(hEdit, str);
RECT rc = getRedrawRect(hEdit);
InvalidateRect(hDlg, &rc, FALSE);
}
break;
case CONTROLS_XINPUT_INDEX:
{
SetWindowText(hEdit, getXinputButtonName(buttonCode));
RECT rc = getRedrawRect(hEdit);
InvalidateRect(hDlg, &rc, FALSE);
}
break;
}
}
}
break;
case WM_NOTIFY:
{
switch (((NMHDR *)lParam)->code)
{
case TCN_SELCHANGE:
{
int cursel = TabCtrl_GetCurSel(pCtrlDlgState->hCtrlTab);
pCtrlDlgState->pCtrlMap->SetTargetDevice(cursel);
switch (cursel)
{
case CONTROLS_KEYBOARD_INDEX:
{
for (u32 i = 0; i <= CONTROLS_IDC_EDIT_END - CONTROLS_IDC_EDIT_BIGIN; i++) {
HWND hEdit = GetDlgItem(hDlg, CONTROLS_IDC_EDIT_BIGIN + i);
if (i >= IDC_EDIT_KEY_ANALOG_UP - CONTROLS_IDC_EDIT_BIGIN) {
Edit_SetReadOnly(hEdit, FALSE);
}
SetWindowTextA(hEdit, getVirtualKeyName(pCtrlDlgState->pCtrlMap->GetBindCode(i)));
}
InvalidateRect(hDlg, 0, 0);
}
break;
case CONTROLS_DIRECT_INPUT_INDEX:
{
for (u32 i = 0; i <= CONTROLS_IDC_EDIT_END - CONTROLS_IDC_EDIT_BIGIN; i++) {
HWND hEdit = GetDlgItem(hDlg, CONTROLS_IDC_EDIT_BIGIN + i);
char str[16];
if (i >= IDC_EDIT_KEYUP - CONTROLS_IDC_EDIT_BIGIN) {
if (i >= IDC_EDIT_KEY_ANALOG_UP - CONTROLS_IDC_EDIT_BIGIN) {
Edit_SetReadOnly(hEdit, TRUE);
SetWindowTextA(hEdit, controllist[i]);
} else {
int n = 1;
int buttonCode = pCtrlDlgState->pCtrlMap->GetBindCode(i);
for (int i = buttonCode >> 8; i > 1; i >>= 1) {
n++;
}
snprintf(str, CONTROLS_BUTTONNAME_MAX, "%s",
controllist[(IDC_EDIT_KEYUP - CONTROLS_IDC_EDIT_BIGIN - 1) + n]);
SetWindowTextA(hEdit, str);
}
continue;
}
snprintf(str, CONTROLS_BUTTONNAME_MAX, "%d", pCtrlDlgState->pCtrlMap->GetBindCode(i) + 1);
SetWindowTextA(hEdit, str);
}
InvalidateRect(hDlg, 0, 0);
}
break;
case CONTROLS_XINPUT_INDEX:
{
for (u32 i = 0; i <= CONTROLS_IDC_EDIT_END - CONTROLS_IDC_EDIT_BIGIN; i++) {
HWND hEdit = GetDlgItem(hDlg, CONTROLS_IDC_EDIT_BIGIN + i);
if (i >= IDC_EDIT_KEY_ANALOG_UP - CONTROLS_IDC_EDIT_BIGIN) {
Edit_SetReadOnly(hEdit, TRUE);
SetWindowTextA(hEdit, controllist[i]);
continue;
}
u32 button = pCtrlDlgState->pCtrlMap->GetBindCode(i);
if (button == 0) {
SetWindowTextA(hEdit, "Disabled");
} else {
SetWindowTextA(hEdit, getXinputButtonName(button));
}
}
InvalidateRect(hDlg, 0, 0);
}
break;
default:
break;
} // pCtrlDlgState->curDevice
} // TCN_SELCHANGING:
break;
default:
break;
} // ((NMHDR *)lParam)->code
} // WM_NOTIFY:
break;
case WM_PAINT:
{
PAINTSTRUCT pst;
HDC hdc = BeginPaint(hDlg, &pst);
BITMAP bm;
GetObject(hbm, sizeof(BITMAP), &bm);
int width = bm.bmWidth;
int height = bm.bmHeight;
BitBlt(hbm, hdc, 0, 0, width, height, 0 , 0);
EndPaint(hDlg, &pst);
return TRUE;
return DefWindowProc(hDlg, message, wParam, lParam);
}
case WM_CTLCOLORSTATIC:
{
HDC hdc=(HDC)wParam;
HWND hCtrl = (HWND)lParam;
SetBkMode(hdc, TRANSPARENT);
int ctrlId = GetDlgCtrlID(hCtrl);
if (ctrlId >= IDC_EDIT_KEY_ANALOG_UP && ctrlId <= IDC_EDIT_KEY_ANALOG_RIGHT) {
SetTextColor(hdc, RGB(128,128,128));
RECT rc = getRedrawRect(hCtrl);
TabCtrl_AdjustRect(pCtrlDlgState->hCtrlTab, TRUE, &rc);
RECT clientrc;
GetClientRect(hCtrl, &clientrc);
TabCtrl_AdjustRect(pCtrlDlgState->hCtrlTab, TRUE, &clientrc);
BitBlt(pCtrlDlgState->hbmPspImage, hdc, 0, 0, rc.right - rc.left, rc.bottom - rc.top, rc.left, rc.top);
char str[11];
GetWindowTextA(hCtrl, str, 10);
DrawTextA(hdc, str, (int)strlen(str), &clientrc, DT_CENTER|DT_SINGLELINE);
}
return (LRESULT)GetStockObject(NULL_BRUSH);
}
case WM_CTLCOLOREDIT:
{
if ((HWND)lParam == GetDlgItem(hDlg, IDC_FORCE_INPUT_DEVICE))
@ -1096,9 +1324,11 @@ namespace MainWindow
SetTextColor(hdc, RGB(255, 0, 0));
HWND hEdit = (HWND)lParam;
RECT rc = getRedrawRect(hEdit);
TabCtrl_AdjustRect(pCtrlDlgState->hCtrlTab, TRUE, &rc);
RECT clientrc;
GetClientRect(hEdit, &clientrc);
BitBlt(hbm, hdc, 0, 0, rc.right - rc.left, rc.bottom - rc.top, rc.left, rc.top);
TabCtrl_AdjustRect(pCtrlDlgState->hCtrlTab, TRUE, &clientrc);
BitBlt(pCtrlDlgState->hbmPspImage, hdc, 0, 0, rc.right - rc.left, rc.bottom - rc.top, rc.left, rc.top);
char str[11];
GetWindowTextA(hEdit, str, 10);
DrawTextA(hdc, str, (int)strlen(str), &clientrc, DT_CENTER|DT_SINGLELINE);
@ -1109,22 +1339,31 @@ namespace MainWindow
{
if (LOWORD(wParam) == IDOK) {
g_Config.iForceInputDevice = (ComboBox_GetCurSel(GetDlgItem(hDlg, IDC_FORCE_INPUT_DEVICE)) - 1);
int key_pad_size = (IDC_EDIT_KEYRIGHT - IDC_EDIT_KEY_TURBO + 1);
for (u32 i = 0; i <= IDC_EDIT_KEY_ANALOG_RIGHT - IDC_EDIT_KEY_TURBO; i++) {
if (IDC_EDIT_KEY_TURBO + i <= IDC_EDIT_KEYRIGHT)
key_pad_map[i * 2] = control_map[i];
else
analog_ctrl_map[(i - key_pad_size) * 2] = control_map[i];
}
pCtrlDlgState->pCtrlMap->BindToDevices();
saveControlsToFile();
}
UnhookWindowsHookEx(pKeydownHook);
UnhookWindowsHookEx(pCtrlDlgState->pKeydownHook);
KillTimer(hDlg, pCtrlDlgState->timerId);
SetWindowLong(pCtrlDlgState->hStaticPspImage, GWL_WNDPROC, (LONG)pCtrlDlgState->orgPSPImageProc);
EndDialog(hDlg, LOWORD(wParam));
if (hbm) {
DeleteObject(hbm);
hbm = 0;
if (pCtrlDlgState->hbmPspImage) {
DeleteObject(pCtrlDlgState->hbmPspImage);
pCtrlDlgState->hbmPspImage = 0;
}
if (pCtrlDlgState) {
delete pCtrlDlgState;
pCtrlDlgState = NULL;
}
return TRUE;
} else if (LOWORD(wParam) >= CONTROLS_IDC_EDIT_BIGIN &&
LOWORD(wParam) <= IDC_EDIT_KEYRIGHT &&
HIWORD(wParam) == EN_SETFOCUS) {
// send about buttonsMap-index of current focus Edit-Control to ControlMapping instance.
UINT nCtrlID = LOWORD(wParam);
if (nCtrlID < CONTROLS_IDC_EDIT_BIGIN || nCtrlID > IDC_EDIT_KEYRIGHT) {
break;
}
pCtrlDlgState->pCtrlMap->SetTargetButton(nCtrlID - CONTROLS_IDC_EDIT_BIGIN);
}
break;
}

View file

@ -1,12 +1,36 @@
#include <limits.h>
#include "XinputDevice.h"
#include "Core/Config.h"
#include "input/input_state.h"
#include "XinputDevice.h"
#include "ControlMapping.h"
#ifndef XUSER_MAX_COUNT
#define XUSER_MAX_COUNT 4
#endif
// Yes, this maps more than the PSP has, but that's fine as this lets us
// map buttons to extra functionality like speedup.
unsigned int xinput_ctrl_map[] = {
XBOX_CODE_LEFTTRIGER, PAD_BUTTON_MENU,
XBOX_CODE_RIGHTTRIGER, PAD_BUTTON_BACK,
XINPUT_GAMEPAD_A, PAD_BUTTON_A,
XINPUT_GAMEPAD_B, PAD_BUTTON_B,
XINPUT_GAMEPAD_X, PAD_BUTTON_X,
XINPUT_GAMEPAD_Y, PAD_BUTTON_Y,
XINPUT_GAMEPAD_BACK, PAD_BUTTON_SELECT,
XINPUT_GAMEPAD_START, PAD_BUTTON_START,
XINPUT_GAMEPAD_LEFT_SHOULDER, PAD_BUTTON_LBUMPER,
XINPUT_GAMEPAD_RIGHT_SHOULDER, PAD_BUTTON_RBUMPER,
XINPUT_GAMEPAD_LEFT_THUMB, PAD_BUTTON_LEFT_THUMB, // Turbo
XINPUT_GAMEPAD_RIGHT_THUMB, PAD_BUTTON_RIGHT_THUMB, // Open PauseScreen
XINPUT_GAMEPAD_DPAD_UP, PAD_BUTTON_UP,
XINPUT_GAMEPAD_DPAD_DOWN, PAD_BUTTON_DOWN,
XINPUT_GAMEPAD_DPAD_LEFT, PAD_BUTTON_LEFT,
XINPUT_GAMEPAD_DPAD_RIGHT, PAD_BUTTON_RIGHT,
};
static const unsigned int xinput_ctrl_map_size = sizeof(xinput_ctrl_map);
XinputDevice::XinputDevice() {
ZeroMemory( &this->prevState, sizeof(this->prevState) );
this->check_delay = 0;
@ -95,34 +119,93 @@ static Stick NormalizedDeadzoneFilter(short x, short y) {
return left;
}
// Yes, this maps more than the PSP has, but that's fine as this lets us
// map buttons to extra functionality like speedup.
static const unsigned int xinput_ctrl_map[] = {
XINPUT_GAMEPAD_DPAD_UP, PAD_BUTTON_UP,
XINPUT_GAMEPAD_DPAD_DOWN, PAD_BUTTON_DOWN,
XINPUT_GAMEPAD_DPAD_LEFT, PAD_BUTTON_LEFT,
XINPUT_GAMEPAD_DPAD_RIGHT, PAD_BUTTON_RIGHT,
XINPUT_GAMEPAD_START, PAD_BUTTON_START,
XINPUT_GAMEPAD_BACK, PAD_BUTTON_SELECT,
XINPUT_GAMEPAD_LEFT_SHOULDER, PAD_BUTTON_LBUMPER,
XINPUT_GAMEPAD_RIGHT_SHOULDER, PAD_BUTTON_RBUMPER,
XINPUT_GAMEPAD_A, PAD_BUTTON_A,
XINPUT_GAMEPAD_B, PAD_BUTTON_B,
XINPUT_GAMEPAD_X, PAD_BUTTON_X,
XINPUT_GAMEPAD_Y, PAD_BUTTON_Y,
XINPUT_GAMEPAD_LEFT_THUMB, PAD_BUTTON_LEFT_THUMB,
XINPUT_GAMEPAD_RIGHT_THUMB, PAD_BUTTON_RIGHT_THUMB,
struct xinput_button_name {
unsigned int button;
char name[10];
};
static inline u32 CtrlForXinput(int xinput) {
for (int i = 0; i < sizeof(xinput_ctrl_map)/sizeof(xinput_ctrl_map[0]); i += 2)
if (xinput_ctrl_map[i] == xinput) return (u32) xinput_ctrl_map[i+1];
const xinput_button_name xinput_name_map[] = {
{XBOX_CODE_LEFTTRIGER, "LT"},
{XBOX_CODE_RIGHTTRIGER, "RT"},
{XINPUT_GAMEPAD_A, "A"},
{XINPUT_GAMEPAD_B, "B"},
{XINPUT_GAMEPAD_X, "X"},
{XINPUT_GAMEPAD_Y, "Y"},
{XINPUT_GAMEPAD_BACK, "Back"},
{XINPUT_GAMEPAD_START, "Start"},
{XINPUT_GAMEPAD_LEFT_SHOULDER, "LB"},
{XINPUT_GAMEPAD_RIGHT_SHOULDER, "RB"},
{XINPUT_GAMEPAD_LEFT_THUMB, "LThumb"},
{XINPUT_GAMEPAD_RIGHT_THUMB, "RThumb"},
{XINPUT_GAMEPAD_DPAD_UP, "Up"},
{XINPUT_GAMEPAD_DPAD_DOWN, "Down"},
{XINPUT_GAMEPAD_DPAD_LEFT, "Left"},
{XINPUT_GAMEPAD_DPAD_RIGHT, "Right"},
};
static const int xbutton_name_map_size = sizeof(xinput_name_map) / sizeof(xinput_button_name);
const char * getXinputButtonName(unsigned int button) {
for (int i = 0; i < xbutton_name_map_size; i++) {
if (xinput_name_map[i].button == button)
return xinput_name_map[i].name;
}
return 0;
}
void XinputDevice::ApplyDiff(XINPUT_STATE &state, InputState &input_state) {
for (int i = 1; i < USHRT_MAX; i <<= 1) {
if (state.Gamepad.wButtons & i)
input_state.pad_buttons |= CtrlForXinput(i);
// Skip XBOX_CODE_LIFT/RIGHT TRIGER. it's virtual code for Mapping.
for (int i = 0; i < sizeof(xinput_ctrl_map)/sizeof(xinput_ctrl_map[0]); i += 2) {
if (state.Gamepad.wButtons & (WORD)(xinput_ctrl_map[i])) {
input_state.pad_buttons |= (int)xinput_ctrl_map[i + 1];
}
// Effective use of triggers that are not used.
if (xinput_ctrl_map[i] == XBOX_CODE_LEFTTRIGER &&
state.Gamepad.bLeftTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD) {
input_state.pad_buttons |= xinput_ctrl_map[i + 1];
}
if (xinput_ctrl_map[i] == XBOX_CODE_RIGHTTRIGER &&
state.Gamepad.bRightTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD) {
input_state.pad_buttons |= xinput_ctrl_map[i + 1];
}
}
}
}
int XinputDevice::UpdateRawStateSingle(RawInputState &rawState)
{
if (g_Config.iForceInputDevice > 0) return -1;
XINPUT_STATE state;
ZeroMemory( &state, sizeof(XINPUT_STATE) );
DWORD dwResult;
if (this->gamepad_idx >= 0)
dwResult = 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 );
if (dwResult == ERROR_SUCCESS) {
this->gamepad_idx = i;
break;
}
}
}
if ( dwResult == ERROR_SUCCESS ) {
for (UINT bit = XINPUT_GAMEPAD_DPAD_UP; bit <= XINPUT_GAMEPAD_Y; bit <<= 1) {
if (state.Gamepad.wButtons & bit) {
rawState.button = bit;
break;
}
}
if (state.Gamepad.bLeftTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD) {
rawState.button = XBOX_CODE_LEFTTRIGER;
} else if (state.Gamepad.bRightTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD) {
rawState.button = XBOX_CODE_RIGHTTRIGER;
}
return TRUE;
}
return FALSE;
}

View file

@ -2,6 +2,8 @@
#include "InputDevice.h"
#include "Xinput.h"
struct RawInputState;
class XinputDevice :
public InputDevice
{
@ -9,6 +11,7 @@ public:
XinputDevice();
virtual int UpdateState(InputState &input_state);
virtual bool IsPad() { return true; }
int UpdateRawStateSingle(RawInputState &rawState);
private:
void ApplyDiff(XINPUT_STATE &state, InputState &input_state);
int gamepad_idx;

Binary file not shown.

Binary file not shown.