mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Add check init Controls Dialog and ControlMapping constructor
This commit is contained in:
parent
9af5499b21
commit
4062059c2e
12 changed files with 835 additions and 151 deletions
223
Windows/ControlMapping.cpp
Normal file
223
Windows/ControlMapping.cpp
Normal 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
86
Windows/ControlMapping.h
Normal 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];
|
||||
};
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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.
Loading…
Add table
Reference in a new issue