mirror of https://github.com/PCSX2/pcsx2.git
PAD: beginning windows initial merge
This commit is contained in:
parent
a90d588167
commit
eed1e4fe8a
pcsx2/PAD/Windows
Config.cppConfig.hDefault.iniDeviceEnumerator.cppDeviceEnumerator.hDiagnostics.cppDiagnostics.hDirectInput.cppDirectInput.hDualShock3.cppDualShock3.hGlobal.cppGlobal.hHidDevice.cppHidDevice.hInputManager.cppInputManager.hKeyboardQueue.cppKeyboardQueue.hLilyPad.cppLilyPad.rcRawInput.cppRawInput.hTooltips.cppTooltips.hVKey.cppVKey.hWindowsKeyboard.cppWindowsKeyboard.hWindowsMessaging.cppWindowsMessaging.hWindowsMouse.cppWindowsMouse.hWndProcEater.cppWndProcEater.hXInputEnum.cppXInputEnum.hfrog.icoresource.husb.h
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,83 @@
|
|||
/* LilyPad - Pad plugin for PS2 Emulator
|
||||
* Copyright (C) 2002-2017 PCSX2 Dev Team/ChickenLiver
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Found- ation, either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* PCSX2 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 for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with PCSX2. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
extern const wchar_t *padTypes[numPadTypes];
|
||||
|
||||
struct PadConfig
|
||||
{
|
||||
PadType type;
|
||||
};
|
||||
|
||||
struct GeneralConfig
|
||||
{
|
||||
public:
|
||||
PadConfig padConfigs[2][4];
|
||||
|
||||
int deviceSelect[2][4];
|
||||
|
||||
DeviceAPI keyboardApi;
|
||||
DeviceAPI mouseApi;
|
||||
|
||||
// Derived value, calculated by GetInput().
|
||||
u8 configureOnBind;
|
||||
bool bind;
|
||||
|
||||
bool specialInputs[2][4];
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
u8 forceHide;
|
||||
u8 mouseUnfocus;
|
||||
u8 background;
|
||||
u8 multipleBinding;
|
||||
|
||||
struct
|
||||
{
|
||||
u8 directInput;
|
||||
u8 xInput;
|
||||
u8 dualShock3;
|
||||
} gameApis;
|
||||
|
||||
u8 multitap[2];
|
||||
|
||||
u8 debug;
|
||||
|
||||
u8 GH2;
|
||||
};
|
||||
u8 bools[15];
|
||||
};
|
||||
|
||||
wchar_t lastSaveConfigPath[MAX_PATH + 1];
|
||||
wchar_t lastSaveConfigFileName[MAX_PATH + 1];
|
||||
};
|
||||
|
||||
extern GeneralConfig config;
|
||||
|
||||
void UnloadConfigs();
|
||||
|
||||
int LoadSettings(int force = 0, wchar_t *file = 0);
|
||||
|
||||
// Refreshes the set of enabled devices.
|
||||
void RefreshEnabledDevices(int updateDeviceList = 0);
|
||||
|
||||
void Configure();
|
||||
#endif
|
|
@ -0,0 +1,191 @@
|
|||
[General Settings]
|
||||
Last Config Path=inis
|
||||
Last Config Name=LilyPad.lily
|
||||
Force Cursor Hide=0
|
||||
Mouse Unfocus=1
|
||||
Background=1
|
||||
Multiple Bindings=0
|
||||
DirectInput Game Devices=1
|
||||
XInput=1
|
||||
DualShock 3=0
|
||||
Multitap 1=0
|
||||
Multitap 2=0
|
||||
Logging=0
|
||||
GH2=0
|
||||
Keyboard Mode=2
|
||||
Mouse Mode=0
|
||||
[Pad Settings]
|
||||
Configure On Bind=0
|
||||
[Pad 0 0]
|
||||
Mode=1
|
||||
[Pad 0 1]
|
||||
Mode=1
|
||||
[Pad 0 2]
|
||||
Mode=1
|
||||
[Pad 0 3]
|
||||
Mode=1
|
||||
[Pad 1 0]
|
||||
Mode=1
|
||||
[Pad 1 1]
|
||||
Mode=1
|
||||
[Pad 1 2]
|
||||
Mode=1
|
||||
[Pad 1 3]
|
||||
Mode=1
|
||||
[Device 0]
|
||||
Display Name=XInput Pad 0
|
||||
Instance ID=XInput Pad 0
|
||||
API=4
|
||||
Type=3
|
||||
Binding 0=0x00200000, 0, 20, 65536, 0, 0, 1, 1
|
||||
Binding 1=0x00200001, 0, 22, 65536, 0, 0, 1, 1
|
||||
Binding 2=0x00200002, 0, 23, 65536, 0, 0, 1, 1
|
||||
Binding 3=0x00200003, 0, 21, 65536, 0, 0, 1, 1
|
||||
Binding 4=0x00200004, 0, 19, 65536, 0, 0, 1, 1
|
||||
Binding 5=0x00200005, 0, 16, 65536, 0, 0, 1, 1
|
||||
Binding 6=0x00200006, 0, 17, 65536, 0, 0, 1, 1
|
||||
Binding 7=0x00200007, 0, 18, 65536, 0, 0, 1, 1
|
||||
Binding 8=0x00200008, 0, 26, 65536, 0, 0, 1, 1
|
||||
Binding 9=0x00200009, 0, 27, 65536, 0, 0, 1, 1
|
||||
Binding 10=0x0020000A, 0, 40, 65536, 0, 0, 1, 1
|
||||
Binding 11=0x0020000C, 0, 30, 65536, 0, 0, 1, 1
|
||||
Binding 12=0x0020000D, 0, 29, 65536, 0, 0, 1, 1
|
||||
Binding 13=0x0020000E, 0, 31, 65536, 0, 0, 1, 1
|
||||
Binding 14=0x0020000F, 0, 28, 65536, 0, 0, 1, 1
|
||||
Binding 15=0x00200010, 0, 24, 65536, 0, 0, 1, 1
|
||||
Binding 16=0x00200011, 0, 25, 65536, 0, 0, 1, 1
|
||||
Binding 17=0x01020013, 0, 33, 87183, 0, 0, 13172, 1
|
||||
Binding 18=0x02020013, 0, 35, 87183, 0, 0, 13172, 1
|
||||
Binding 19=0x01020014, 0, 32, 87183, 0, 0, 13172, 1
|
||||
Binding 20=0x02020014, 0, 34, 87183, 0, 0, 13172, 1
|
||||
Binding 21=0x01020015, 0, 37, 87183, 0, 0, 13172, 1
|
||||
Binding 22=0x02020015, 0, 39, 87183, 0, 0, 13172, 1
|
||||
Binding 23=0x01020016, 0, 36, 87183, 0, 0, 13172, 1
|
||||
Binding 24=0x02020016, 0, 38, 87183, 0, 0, 13172, 1
|
||||
Binding 25=0x00200000, 0, 20, 65536, 0, 0, 1, 2
|
||||
Binding 26=0x00200001, 0, 22, 65536, 0, 0, 1, 2
|
||||
Binding 27=0x00200004, 0, 19, 65536, 0, 0, 1, 2
|
||||
Binding 28=0x00200005, 0, 16, 65536, 0, 0, 1, 2
|
||||
Binding 29=0x00200008, 0, 25, 65536, 0, 0, 1, 2
|
||||
Binding 30=0x00200009, 0, 28, 65536, 0, 0, 1, 2
|
||||
Binding 31=0x0020000F, 0, 30, 65536, 0, 0, 1, 2
|
||||
Binding 32=0x00200010, 0, 29, 65536, 0, 0, 1, 2
|
||||
Binding 33=0x00200011, 0, 31, 65536, 0, 0, 1, 2
|
||||
Binding 34=0x01020014, 0, 32, 65536, 0, 0, 13172, 2
|
||||
Binding 35=0x02020014, 0, 34, 65536, 0, 0, 13172, 2
|
||||
Binding 36=0x00200002, 0, 28, 65536, 0, 0, 1, 3
|
||||
Binding 37=0x00200003, 0, 27, 65536, 0, 0, 1, 3
|
||||
Binding 38=0x00200004, 0, 19, 65536, 0, 0, 1, 3
|
||||
Binding 39=0x00200005, 0, 16, 65536, 0, 0, 1, 3
|
||||
Binding 40=0x00200008, 0, 30, 65536, 0, 0, 1, 3
|
||||
Binding 41=0x00200009, 0, 31, 65536, 0, 0, 1, 3
|
||||
Binding 42=0x0020000C, 0, 25, 65536, 0, 0, 1, 3
|
||||
Binding 43=0x0020000D, 0, 24, 65536, 0, 0, 1, 3
|
||||
Binding 44=0x0020000E, 0, 26, 65536, 0, 0, 1, 3
|
||||
Binding 45=0x00200010, 0, 29, 65536, 0, 0, 1, 3
|
||||
Binding 46=0x00200011, 0, 20, 65536, 0, 0, 1, 3
|
||||
Binding 47=0x00200008, 0, 29, 65536, 0, 0, 1, 4
|
||||
Binding 48=0x00200009, 0, 30, 65536, 0, 0, 1, 4
|
||||
Binding 49=0x01020013, 0, 33, 3000, 0, 0, 13172, 4
|
||||
Binding 50=0x02020013, 0, 35, 3000, 0, 0, 13172, 4
|
||||
Binding 51=0x01020014, 0, 32, 3000, 0, 0, 13172, 4
|
||||
Binding 52=0x02020014, 0, 34, 3000, 0, 0, 13172, 4
|
||||
Binding 53=0x00200000, 0, 20, 65536, 0, 0, 1, 5
|
||||
Binding 54=0x00200001, 0, 22, 65536, 0, 0, 1, 5
|
||||
Binding 55=0x00200002, 0, 23, 65536, 0, 0, 1, 5
|
||||
Binding 56=0x00200003, 0, 21, 65536, 0, 0, 1, 5
|
||||
Binding 57=0x00200004, 0, 19, 65536, 0, 0, 1, 5
|
||||
Binding 58=0x00200008, 0, 26, 65536, 0, 0, 1, 5
|
||||
Binding 59=0x00200009, 0, 27, 65536, 0, 0, 1, 5
|
||||
Binding 60=0x0020000C, 0, 30, 65536, 0, 0, 1, 5
|
||||
Binding 61=0x0020000D, 0, 29, 65536, 0, 0, 1, 5
|
||||
Binding 62=0x0020000E, 0, 31, 65536, 0, 0, 1, 5
|
||||
Binding 63=0x0020000F, 0, 28, 65536, 0, 0, 1, 5
|
||||
Binding 64=0x01020013, 0, 33, 87183, 0, 0, 13172, 5
|
||||
Binding 65=0x02020013, 0, 35, 87183, 0, 0, 13172, 5
|
||||
FF Binding 0=Constant 0, 0, 0, 1, 0, 65536, 1, 0
|
||||
FF Binding 1=Constant 0, 1, 0, 1, 0, 0, 1, 65536
|
||||
[Device 1]
|
||||
Display Name=XInput Pad 1
|
||||
Instance ID=XInput Pad 1
|
||||
API=4
|
||||
Type=3
|
||||
Binding 0=0x00200000, 1, 20, 65536, 0, 0, 1, 1
|
||||
Binding 1=0x00200001, 1, 22, 65536, 0, 0, 1, 1
|
||||
Binding 2=0x00200002, 1, 23, 65536, 0, 0, 1, 1
|
||||
Binding 3=0x00200003, 1, 21, 65536, 0, 0, 1, 1
|
||||
Binding 4=0x00200004, 1, 19, 65536, 0, 0, 1, 1
|
||||
Binding 5=0x00200005, 1, 16, 65536, 0, 0, 1, 1
|
||||
Binding 6=0x00200006, 1, 17, 65536, 0, 0, 1, 1
|
||||
Binding 7=0x00200007, 1, 18, 65536, 0, 0, 1, 1
|
||||
Binding 8=0x00200008, 1, 26, 65536, 0, 0, 1, 1
|
||||
Binding 9=0x00200009, 1, 27, 65536, 0, 0, 1, 1
|
||||
Binding 10=0x0020000A, 1, 40, 65536, 0, 0, 1, 1
|
||||
Binding 11=0x0020000C, 1, 30, 65536, 0, 0, 1, 1
|
||||
Binding 12=0x0020000D, 1, 29, 65536, 0, 0, 1, 1
|
||||
Binding 13=0x0020000E, 1, 31, 65536, 0, 0, 1, 1
|
||||
Binding 14=0x0020000F, 1, 28, 65536, 0, 0, 1, 1
|
||||
Binding 15=0x00200010, 1, 24, 65536, 0, 0, 1, 1
|
||||
Binding 16=0x00200011, 1, 25, 65536, 0, 0, 1, 1
|
||||
Binding 17=0x01020013, 1, 33, 87183, 0, 0, 13172, 1
|
||||
Binding 18=0x02020013, 1, 35, 87183, 0, 0, 13172, 1
|
||||
Binding 19=0x01020014, 1, 32, 87183, 0, 0, 13172, 1
|
||||
Binding 20=0x02020014, 1, 34, 87183, 0, 0, 13172, 1
|
||||
Binding 21=0x01020015, 1, 37, 87183, 0, 0, 13172, 1
|
||||
Binding 22=0x02020015, 1, 39, 87183, 0, 0, 13172, 1
|
||||
Binding 23=0x01020016, 1, 36, 87183, 0, 0, 13172, 1
|
||||
Binding 24=0x02020016, 1, 38, 87183, 0, 0, 13172, 1
|
||||
Binding 25=0x00200000, 1, 20, 65536, 0, 0, 1, 2
|
||||
Binding 26=0x00200001, 1, 22, 65536, 0, 0, 1, 2
|
||||
Binding 27=0x00200004, 1, 19, 65536, 0, 0, 1, 2
|
||||
Binding 28=0x00200005, 1, 16, 65536, 0, 0, 1, 2
|
||||
Binding 29=0x00200008, 1, 25, 65536, 0, 0, 1, 2
|
||||
Binding 30=0x00200009, 1, 28, 65536, 0, 0, 1, 2
|
||||
Binding 31=0x0020000F, 1, 30, 65536, 0, 0, 1, 2
|
||||
Binding 32=0x00200010, 1, 29, 65536, 0, 0, 1, 2
|
||||
Binding 33=0x00200011, 1, 31, 65536, 0, 0, 1, 2
|
||||
Binding 34=0x01020014, 1, 32, 65536, 0, 0, 13172, 2
|
||||
Binding 35=0x02020014, 1, 34, 65536, 0, 0, 13172, 2
|
||||
Binding 36=0x00200002, 1, 28, 65536, 0, 0, 1, 3
|
||||
Binding 37=0x00200003, 1, 27, 65536, 0, 0, 1, 3
|
||||
Binding 38=0x00200004, 1, 19, 65536, 0, 0, 1, 3
|
||||
Binding 39=0x00200005, 1, 16, 65536, 0, 0, 1, 3
|
||||
Binding 40=0x00200008, 1, 30, 65536, 0, 0, 1, 3
|
||||
Binding 41=0x00200009, 1, 31, 65536, 0, 0, 1, 3
|
||||
Binding 42=0x0020000C, 1, 25, 65536, 0, 0, 1, 3
|
||||
Binding 43=0x0020000D, 1, 24, 65536, 0, 0, 1, 3
|
||||
Binding 44=0x0020000E, 1, 26, 65536, 0, 0, 1, 3
|
||||
Binding 45=0x00200010, 1, 29, 65536, 0, 0, 1, 3
|
||||
Binding 46=0x00200011, 1, 20, 65536, 0, 0, 1, 3
|
||||
Binding 47=0x00200008, 1, 29, 65536, 0, 0, 1, 4
|
||||
Binding 48=0x00200009, 1, 30, 65536, 0, 0, 1, 4
|
||||
Binding 49=0x01020013, 1, 33, 3000, 0, 0, 13172, 4
|
||||
Binding 50=0x02020013, 1, 35, 3000, 0, 0, 13172, 4
|
||||
Binding 51=0x01020014, 1, 32, 3000, 0, 0, 13172, 4
|
||||
Binding 52=0x02020014, 1, 34, 3000, 0, 0, 13172, 4
|
||||
Binding 53=0x00200000, 1, 20, 65536, 0, 0, 1, 5
|
||||
Binding 54=0x00200001, 1, 22, 65536, 0, 0, 1, 5
|
||||
Binding 55=0x00200002, 1, 23, 65536, 0, 0, 1, 5
|
||||
Binding 56=0x00200003, 1, 21, 65536, 0, 0, 1, 5
|
||||
Binding 57=0x00200004, 1, 19, 65536, 0, 0, 1, 5
|
||||
Binding 58=0x00200008, 1, 26, 65536, 0, 0, 1, 5
|
||||
Binding 59=0x00200009, 1, 27, 65536, 0, 0, 1, 5
|
||||
Binding 60=0x0020000C, 1, 30, 65536, 0, 0, 1, 5
|
||||
Binding 61=0x0020000D, 1, 29, 65536, 0, 0, 1, 5
|
||||
Binding 62=0x0020000E, 1, 31, 65536, 0, 0, 1, 5
|
||||
Binding 63=0x0020000F, 1, 28, 65536, 0, 0, 1, 5
|
||||
Binding 64=0x01020013, 1, 33, 87183, 0, 0, 13172, 5
|
||||
Binding 65=0x02020013, 1, 35, 87183, 0, 0, 13172, 5
|
||||
FF Binding 0=Constant 1, 0, 0, 1, 0, 65536, 1, 0
|
||||
FF Binding 1=Constant 1, 1, 0, 1, 0, 0, 1, 65536
|
||||
[Device 12]
|
||||
Display Name=XInput Pad 2
|
||||
Instance ID=XInput Pad 2
|
||||
API=4
|
||||
Type=3
|
||||
[Device 13]
|
||||
Display Name=XInput Pad 3
|
||||
Instance ID=XInput Pad 3
|
||||
API=4
|
||||
Type=3
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
/* LilyPad - Pad plugin for PS2 Emulator
|
||||
* Copyright (C) 2002-2014 PCSX2 Dev Team/ChickenLiver
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Found- ation, either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* PCSX2 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 for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with PCSX2. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Global.h"
|
||||
#include "InputManager.h"
|
||||
|
||||
#include "DeviceEnumerator.h"
|
||||
#ifdef _WIN32
|
||||
#include "WindowsMessaging.h"
|
||||
#include "DirectInput.h"
|
||||
#include "RawInput.h"
|
||||
#include "XInputEnum.h"
|
||||
#include "HidDevice.h"
|
||||
#include "DualShock3.h"
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#include "Linux/KeyboardMouse.h"
|
||||
#include "Linux/JoyEvdev.h"
|
||||
#endif
|
||||
|
||||
void EnumDevices(int hideDXXinput)
|
||||
{
|
||||
// Needed for enumeration of some device types.
|
||||
dm->ReleaseInput();
|
||||
InputDeviceManager *oldDm = dm;
|
||||
dm = new InputDeviceManager();
|
||||
|
||||
#ifdef _MSC_VER
|
||||
EnumWindowsMessagingDevices();
|
||||
EnumRawInputDevices();
|
||||
EnumDualShock3s();
|
||||
EnumXInputDevices();
|
||||
EnumDirectInputDevices(hideDXXinput);
|
||||
#else
|
||||
EnumLnx();
|
||||
EnumJoystickEvdev();
|
||||
#endif
|
||||
|
||||
dm->CopyBindings(oldDm->numDevices, oldDm->devices);
|
||||
|
||||
delete oldDm;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/* LilyPad - Pad plugin for PS2 Emulator
|
||||
* Copyright (C) 2002-2014 PCSX2 Dev Team/ChickenLiver
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Found- ation, either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* PCSX2 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 for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with PCSX2. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
void EnumDevices(int hideDXXinput);
|
|
@ -0,0 +1,145 @@
|
|||
/* LilyPad - Pad plugin for PS2 Emulator
|
||||
* Copyright (C) 2002-2014 PCSX2 Dev Team/ChickenLiver
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Found- ation, either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* PCSX2 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 for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with PCSX2. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Global.h"
|
||||
#include "DeviceEnumerator.h"
|
||||
#include "KeyboardQueue.h"
|
||||
|
||||
#include "resource.h"
|
||||
#include "InputManager.h"
|
||||
#include "WndProcEater.h"
|
||||
|
||||
Device *dev;
|
||||
|
||||
INT_PTR CALLBACK DiagDialog(HWND hWnd, unsigned int uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
int i;
|
||||
HWND hWndList = GetDlgItem(hWnd, IDC_DIAG_LIST);
|
||||
static int fullRefresh;
|
||||
if (dev) {
|
||||
switch (uMsg) {
|
||||
case WM_INITDIALOG: {
|
||||
fullRefresh = 1;
|
||||
SetWindowText(hWnd, dev->displayName);
|
||||
LVCOLUMNW c;
|
||||
c.mask = LVCF_TEXT | LVCF_WIDTH;
|
||||
c.cx = 151;
|
||||
c.pszText = L"Control";
|
||||
ListView_InsertColumn(hWndList, 0, &c);
|
||||
c.cx = 90;
|
||||
c.pszText = L"Value";
|
||||
ListView_InsertColumn(hWndList, 1, &c);
|
||||
ListView_DeleteAllItems(hWndList);
|
||||
LVITEM item;
|
||||
item.mask = LVIF_TEXT;
|
||||
item.iSubItem = 0;
|
||||
for (i = 0; i < dev->numVirtualControls; i++) {
|
||||
item.pszText = dev->GetVirtualControlName(dev->virtualControls + i);
|
||||
item.iItem = i;
|
||||
ListView_InsertItem(hWndList, &item);
|
||||
}
|
||||
SetTimer(hWnd, 1, 200, 0);
|
||||
}
|
||||
//break;
|
||||
case WM_TIMER: {
|
||||
hWndButtonProc.SetWndHandle(hWndList);
|
||||
InitInfo info = {0, 1, hWnd, &hWndButtonProc};
|
||||
dm->Update(&info);
|
||||
LVITEMW item;
|
||||
item.mask = LVIF_TEXT;
|
||||
item.iSubItem = 1;
|
||||
//ShowWindow(hWndList, 0);
|
||||
//LockWindowUpdate(hWndList);
|
||||
if (!dev->active) {
|
||||
item.pszText = L"N/A";
|
||||
for (i = 0; i < dev->numVirtualControls; i++) {
|
||||
item.iItem = i;
|
||||
ListView_SetItem(hWndList, &item);
|
||||
}
|
||||
fullRefresh = 1;
|
||||
} else {
|
||||
for (i = 0; i < dev->numVirtualControls; i++) {
|
||||
if (fullRefresh || dev->virtualControlState[i] != dev->oldVirtualControlState[i]) {
|
||||
|
||||
VirtualControl *c = dev->virtualControls + i;
|
||||
wchar_t temp[50];
|
||||
int val = dev->virtualControlState[i];
|
||||
if (c->uid & (UID_POV)) {
|
||||
wsprintfW(temp, L"%i", val);
|
||||
} else {
|
||||
wchar_t *sign = L"";
|
||||
if (val < 0) {
|
||||
sign = L"-";
|
||||
val = -val;
|
||||
}
|
||||
if ((c->uid & UID_AXIS) && val) {
|
||||
val = val;
|
||||
}
|
||||
val = (int)floor(0.5 + val * 1000.0 / (double)FULLY_DOWN);
|
||||
wsprintfW(temp, L"%s%i.%03i", sign, val / 1000, val % 1000);
|
||||
}
|
||||
item.pszText = temp;
|
||||
item.iItem = i;
|
||||
ListView_SetItem(hWndList, &item);
|
||||
}
|
||||
}
|
||||
dm->PostRead();
|
||||
fullRefresh = 0;
|
||||
}
|
||||
//LockWindowUpdate(0);
|
||||
//ShowWindow(hWndList, 1);
|
||||
//UpdateWindow(hWnd);
|
||||
} break;
|
||||
case WM_NOTIFY: {
|
||||
NMLVKEYDOWN *n = (NMLVKEYDOWN *)lParam;
|
||||
// Don't always get the notification when testing DirectInput non-keyboard devices.
|
||||
// Don't get it (Or want it) when testing keyboards.
|
||||
if (n->hdr.idFrom != IDC_DIAG_LIST || n->hdr.code != LVN_KEYDOWN || n->wVKey != VK_ESCAPE)
|
||||
break;
|
||||
}
|
||||
case WM_ACTIVATE:
|
||||
if (uMsg == WM_ACTIVATE && wParam != WA_INACTIVE)
|
||||
break;
|
||||
break;
|
||||
case WM_CLOSE:
|
||||
KillTimer(hWnd, 1);
|
||||
dm->ReleaseInput();
|
||||
// Prevents reaching this branch again.
|
||||
dev = 0;
|
||||
EndDialog(hWnd, 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Diagnose(int id, HWND hWnd)
|
||||
{
|
||||
// init = 0;
|
||||
dev = dm->devices[id];
|
||||
for (int i = 0; i < dm->numDevices; i++) {
|
||||
if (i != id)
|
||||
dm->DisableDevice(i);
|
||||
// Shouldn't be needed.
|
||||
else
|
||||
dm->EnableDevice(i);
|
||||
}
|
||||
DialogBox(hInst, MAKEINTRESOURCE(IDD_DIAG), hWnd, DiagDialog);
|
||||
ClearKeyQueue();
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/* LilyPad - Pad plugin for PS2 Emulator
|
||||
* Copyright (C) 2002-2014 PCSX2 Dev Team/ChickenLiver
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Found- ation, either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* PCSX2 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 for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with PCSX2. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef DIAGNOSTICS_H
|
||||
#define DIAGNOSTICS_H
|
||||
|
||||
void Diagnose(int id, HWND hWnd);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,671 @@
|
|||
/* LilyPad - Pad plugin for PS2 Emulator
|
||||
* Copyright (C) 2002-2014 PCSX2 Dev Team/ChickenLiver
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Found- ation, either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* PCSX2 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 for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with PCSX2. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Global.h"
|
||||
#define DIRECTINPUT_VERSION 0x0800
|
||||
#include <dinput.h>
|
||||
#include "InputManager.h"
|
||||
#include "Config.h"
|
||||
|
||||
#include "VKey.h"
|
||||
#include "DirectInput.h"
|
||||
#include "DeviceEnumerator.h"
|
||||
#include "PS2Etypes.h"
|
||||
|
||||
// All for getting GUIDs of XInput devices....
|
||||
#include <wbemidl.h>
|
||||
#include <oleauto.h>
|
||||
// MS's code imports wmsstd.h, thus requiring the entire windows
|
||||
// media SDK also be installed for a simple macro. This is
|
||||
// simpler and less silly.
|
||||
#ifndef SAFE_RELEASE
|
||||
#define SAFE_RELEASE(p) \
|
||||
{ \
|
||||
if (p) { \
|
||||
(p)->Release(); \
|
||||
(p) = NULL; \
|
||||
} \
|
||||
}
|
||||
#endif
|
||||
|
||||
// Aka htons, without the winsock dependency.
|
||||
inline static u16 flipShort(u16 s)
|
||||
{
|
||||
return (s >> 8) | (s << 8);
|
||||
}
|
||||
|
||||
// Aka htonl, without the winsock dependency.
|
||||
inline static u32 flipLong(u32 l)
|
||||
{
|
||||
return (((u32)flipShort((u16)l)) << 16) | flipShort((u16)(l >> 16));
|
||||
}
|
||||
|
||||
static void GUIDtoString(wchar_t *data, const GUID *pg)
|
||||
{
|
||||
wsprintfW(data, L"%08X-%04X-%04X-%04X-%04X%08X",
|
||||
pg->Data1, (u32)pg->Data2, (u32)pg->Data3,
|
||||
flipShort(((u16 *)pg->Data4)[0]),
|
||||
flipShort(((u16 *)pg->Data4)[1]),
|
||||
flipLong(((u32 *)pg->Data4)[1]));
|
||||
}
|
||||
|
||||
struct DirectInput8Data
|
||||
{
|
||||
IDirectInput8 *lpDI8;
|
||||
int refCount;
|
||||
int deviceCount;
|
||||
};
|
||||
|
||||
DirectInput8Data di8d = {0, 0, 0};
|
||||
|
||||
IDirectInput8 *GetDirectInput()
|
||||
{
|
||||
if (!di8d.lpDI8) {
|
||||
if (FAILED(DirectInput8Create(hInst, 0x800, IID_IDirectInput8, (void **)&di8d.lpDI8, 0)))
|
||||
return 0;
|
||||
}
|
||||
di8d.refCount++;
|
||||
return di8d.lpDI8;
|
||||
}
|
||||
void ReleaseDirectInput()
|
||||
{
|
||||
if (di8d.refCount) {
|
||||
di8d.refCount--;
|
||||
if (!di8d.refCount) {
|
||||
di8d.lpDI8->Release();
|
||||
di8d.lpDI8 = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int StringToGUID(GUID *pg, wchar_t *dataw)
|
||||
{
|
||||
char data[100];
|
||||
if (wcslen(dataw) > 50)
|
||||
return 0;
|
||||
int w = 0;
|
||||
while (dataw[w]) {
|
||||
data[w] = (char)dataw[w];
|
||||
w++;
|
||||
}
|
||||
data[w] = 0;
|
||||
u32 temp[5];
|
||||
sscanf(data, "%08X-%04X-%04X-%04X-%04X%08X",
|
||||
&pg->Data1, temp, temp + 1,
|
||||
temp + 2, temp + 3, temp + 4);
|
||||
pg->Data2 = (u16)temp[0];
|
||||
pg->Data3 = (u16)temp[1];
|
||||
((u16 *)pg->Data4)[0] = flipShort((u16)temp[2]);
|
||||
((u16 *)pg->Data4)[1] = flipShort((u16)temp[3]);
|
||||
((u32 *)pg->Data4)[1] = flipLong(temp[4]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
struct DI8Effect
|
||||
{
|
||||
IDirectInputEffect *die;
|
||||
int scale;
|
||||
};
|
||||
|
||||
BOOL CALLBACK EnumDeviceObjectsCallback(LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef);
|
||||
BOOL CALLBACK EnumEffectsCallback(LPCDIEFFECTINFOW pdei, LPVOID pvRef);
|
||||
class DirectInputDevice : public Device
|
||||
{
|
||||
public:
|
||||
DI8Effect *diEffects;
|
||||
|
||||
IDirectInputDevice8 *did;
|
||||
GUID guidInstance;
|
||||
DirectInputDevice(DeviceType type, IDirectInputDevice8 *did, wchar_t *displayName, wchar_t *instanceID, wchar_t *productID, GUID guid)
|
||||
: Device(DI, type, displayName, instanceID, productID)
|
||||
{
|
||||
diEffects = 0;
|
||||
guidInstance = guid;
|
||||
this->did = 0;
|
||||
did->EnumEffects(EnumEffectsCallback, this, DIEFT_ALL);
|
||||
did->EnumObjects(EnumDeviceObjectsCallback, this, DIDFT_ALL);
|
||||
did->Release();
|
||||
}
|
||||
|
||||
void SetEffect(ForceFeedbackBinding *binding, unsigned char force)
|
||||
{
|
||||
int index = 0;
|
||||
if (!diEffects) {
|
||||
return;
|
||||
}
|
||||
for (int port = 0; port < 2; port++) {
|
||||
for (int slot = 0; slot < 4; slot++) {
|
||||
int padtype = config.padConfigs[port][slot].type;
|
||||
unsigned int diff = binding - pads[port][slot][padtype].ffBindings;
|
||||
if (diff < (unsigned int)pads[port][slot][padtype].numFFBindings) {
|
||||
index += diff;
|
||||
port = 2;
|
||||
break;
|
||||
}
|
||||
index += pads[port][slot][padtype].numFFBindings;
|
||||
}
|
||||
}
|
||||
IDirectInputEffect *die = diEffects[index].die;
|
||||
if (die) {
|
||||
DIEFFECT dieffect;
|
||||
memset(&dieffect, 0, sizeof(dieffect));
|
||||
union
|
||||
{
|
||||
DIPERIODIC periodic;
|
||||
DIRAMPFORCE ramp;
|
||||
DICONSTANTFORCE constant;
|
||||
};
|
||||
|
||||
dieffect.dwSize = sizeof(dieffect);
|
||||
dieffect.lpvTypeSpecificParams = &periodic;
|
||||
int magnitude = abs((int)((force * 10000 * (__int64)diEffects[index].scale) / BASE_SENSITIVITY / 255));
|
||||
if (magnitude > 10000)
|
||||
magnitude = 10000;
|
||||
int type = ffEffectTypes[binding->effectIndex].type;
|
||||
if (type == EFFECT_CONSTANT) {
|
||||
dieffect.cbTypeSpecificParams = sizeof(DICONSTANTFORCE);
|
||||
constant.lMagnitude = magnitude;
|
||||
} else if (type == EFFECT_PERIODIC) {
|
||||
dieffect.cbTypeSpecificParams = sizeof(DIPERIODIC);
|
||||
periodic.dwMagnitude = 0;
|
||||
periodic.lOffset = magnitude;
|
||||
periodic.dwPhase = 0;
|
||||
periodic.dwPeriod = 2000000;
|
||||
} else if (type == EFFECT_RAMP) {
|
||||
dieffect.cbTypeSpecificParams = sizeof(DIRAMPFORCE);
|
||||
ramp.lEnd = ramp.lStart = magnitude;
|
||||
}
|
||||
dieffect.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTIDS;
|
||||
dieffect.dwDuration = 2000000;
|
||||
die->SetParameters(&dieffect, DIEP_TYPESPECIFICPARAMS | DIEP_START);
|
||||
}
|
||||
}
|
||||
|
||||
int Activate(InitInfo *initInfo)
|
||||
{
|
||||
int i;
|
||||
IDirectInput8 *di8 = GetDirectInput();
|
||||
Deactivate();
|
||||
if (!di8)
|
||||
return 0;
|
||||
if (DI_OK != di8->CreateDevice(guidInstance, &did, 0)) {
|
||||
ReleaseDirectInput();
|
||||
did = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
{
|
||||
DIOBJECTDATAFORMAT *formats = (DIOBJECTDATAFORMAT *)calloc(numPhysicalControls, sizeof(DIOBJECTDATAFORMAT));
|
||||
for (i = 0; i < numPhysicalControls; i++) {
|
||||
formats[i].dwType = physicalControls[i].type | DIDFT_MAKEINSTANCE(physicalControls[i].id);
|
||||
formats[i].dwOfs = 4 * i;
|
||||
}
|
||||
DIDATAFORMAT format;
|
||||
format.dwSize = sizeof(format);
|
||||
format.dwDataSize = 4 * numPhysicalControls;
|
||||
format.dwObjSize = sizeof(DIOBJECTDATAFORMAT);
|
||||
format.dwFlags = 0;
|
||||
format.dwNumObjs = numPhysicalControls;
|
||||
format.rgodf = formats;
|
||||
int res = did->SetDataFormat(&format);
|
||||
for (i = 0; i < numPhysicalControls; i++) {
|
||||
if (physicalControls[i].type == ABSAXIS) {
|
||||
DIPROPRANGE prop;
|
||||
prop.diph.dwHeaderSize = sizeof(DIPROPHEADER);
|
||||
prop.diph.dwSize = sizeof(DIPROPRANGE);
|
||||
prop.diph.dwObj = formats[i].dwType;
|
||||
prop.diph.dwHow = DIPH_BYID;
|
||||
prop.lMin = -FULLY_DOWN;
|
||||
prop.lMax = FULLY_DOWN;
|
||||
did->SetProperty(DIPROP_RANGE, &prop.diph);
|
||||
|
||||
// May do something like this again, if there's any need.
|
||||
/*
|
||||
if (FAILED(DI->did->SetProperty(DIPROP_RANGE, &prop.diph))) {
|
||||
if (FAILED(DI->did->GetProperty(DIPROP_RANGE, &prop.diph))) {
|
||||
// ????
|
||||
DI->objects[i].min = prop.lMin;
|
||||
DI->objects[i].max = prop.lMax;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
DI->objects[i].min = prop.lMin;
|
||||
DI->objects[i].max = prop.lMax;
|
||||
//*/
|
||||
}
|
||||
}
|
||||
free(formats);
|
||||
}
|
||||
// Note: Have to use hWndTop to properly hide cursor for mouse device.
|
||||
if (type == OTHER) {
|
||||
did->SetCooperativeLevel(initInfo->hWndTop, DISCL_BACKGROUND | DISCL_EXCLUSIVE);
|
||||
} else if (type == KEYBOARD) {
|
||||
did->SetCooperativeLevel(initInfo->hWndTop, DISCL_FOREGROUND);
|
||||
} else {
|
||||
did->SetCooperativeLevel(initInfo->hWndTop, DISCL_FOREGROUND | DISCL_EXCLUSIVE);
|
||||
}
|
||||
if (did->Acquire() != DI_OK) {
|
||||
did->Release();
|
||||
did = 0;
|
||||
ReleaseDirectInput();
|
||||
return 0;
|
||||
}
|
||||
AllocState();
|
||||
int count = GetFFBindingCount();
|
||||
diEffects = (DI8Effect *)calloc(count, sizeof(DI8Effect));
|
||||
i = 0;
|
||||
for (int port = 0; port < 2; port++) {
|
||||
for (int slot = 0; slot < 4; slot++) {
|
||||
int padtype = config.padConfigs[port][slot].type;
|
||||
int subIndex = i;
|
||||
for (int j = 0; j < pads[port][slot][padtype].numFFBindings; j++) {
|
||||
ForceFeedbackBinding *b = 0;
|
||||
b = &pads[port][slot][padtype].ffBindings[i - subIndex];
|
||||
ForceFeedbackEffectType *eff = ffEffectTypes + b->effectIndex;
|
||||
GUID guid;
|
||||
if (!StringToGUID(&guid, eff->effectID))
|
||||
continue;
|
||||
|
||||
DIEFFECT dieffect;
|
||||
memset(&dieffect, 0, sizeof(dieffect));
|
||||
dieffect.dwSize = sizeof(dieffect);
|
||||
dieffect.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTIDS;
|
||||
dieffect.dwDuration = 1000000;
|
||||
dieffect.dwGain = 10000;
|
||||
dieffect.dwTriggerButton = DIEB_NOTRIGGER;
|
||||
union
|
||||
{
|
||||
DIPERIODIC pediodic;
|
||||
DIRAMPFORCE ramp;
|
||||
DICONSTANTFORCE constant;
|
||||
} stuff = {0, 0, 0, 0};
|
||||
|
||||
if (eff->type == EFFECT_CONSTANT) {
|
||||
dieffect.cbTypeSpecificParams = sizeof(DICONSTANTFORCE);
|
||||
} else if (eff->type == EFFECT_PERIODIC) {
|
||||
dieffect.cbTypeSpecificParams = sizeof(DIPERIODIC);
|
||||
} else if (eff->type == EFFECT_RAMP) {
|
||||
dieffect.cbTypeSpecificParams = sizeof(DIRAMPFORCE);
|
||||
}
|
||||
dieffect.lpvTypeSpecificParams = &stuff;
|
||||
|
||||
int maxForce = 0;
|
||||
int numAxes = 0;
|
||||
int *axes = (int *)malloc(sizeof(int) * 3 * numFFAxes);
|
||||
DWORD *axisIDs = (DWORD *)(axes + numFFAxes);
|
||||
LONG *dirList = (LONG *)(axisIDs + numFFAxes);
|
||||
dieffect.rgdwAxes = axisIDs;
|
||||
dieffect.rglDirection = dirList;
|
||||
for (int k = 0; k < numFFAxes; k++) {
|
||||
if (b->axes[k].force) {
|
||||
int force = abs(b->axes[k].force);
|
||||
if (force > maxForce) {
|
||||
maxForce = force;
|
||||
}
|
||||
axes[numAxes] = k;
|
||||
axisIDs[numAxes] = ffAxes[k].id;
|
||||
dirList[numAxes] = b->axes[k].force;
|
||||
numAxes++;
|
||||
}
|
||||
}
|
||||
if (!numAxes) {
|
||||
free(axes);
|
||||
continue;
|
||||
}
|
||||
dieffect.cAxes = numAxes;
|
||||
diEffects[i].scale = maxForce;
|
||||
if (!SUCCEEDED(did->CreateEffect(guid, &dieffect, &diEffects[i].die, 0))) {
|
||||
diEffects[i].die = 0;
|
||||
diEffects[i].scale = 0;
|
||||
}
|
||||
|
||||
free(axes);
|
||||
axes = 0;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
active = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Update()
|
||||
{
|
||||
if (!active)
|
||||
return 0;
|
||||
if (numPhysicalControls) {
|
||||
HRESULT res = did->Poll();
|
||||
// ??
|
||||
if ((res != DI_OK && res != DI_NOEFFECT) ||
|
||||
DI_OK != did->GetDeviceState(4 * numPhysicalControls, physicalControlState)) {
|
||||
Deactivate();
|
||||
return 0;
|
||||
}
|
||||
for (int i = 0; i < numPhysicalControls; i++) {
|
||||
if (physicalControls[i].type & RELAXIS) {
|
||||
physicalControlState[i] *= (FULLY_DOWN / 3);
|
||||
} else if (physicalControls[i].type & BUTTON) {
|
||||
physicalControlState[i] = (physicalControlState[i] & 0x80) * FULLY_DOWN / 128;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int GetFFBindingCount()
|
||||
{
|
||||
int count = 0;
|
||||
for (int port = 0; port < 2; port++) {
|
||||
for (int slot = 0; slot < 4; slot++) {
|
||||
int padtype = config.padConfigs[port][slot].type;
|
||||
count += pads[port][slot][padtype].numFFBindings;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
void Deactivate()
|
||||
{
|
||||
FreeState();
|
||||
if (diEffects) {
|
||||
int count = GetFFBindingCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (diEffects[i].die) {
|
||||
diEffects[i].die->Stop();
|
||||
diEffects[i].die->Release();
|
||||
}
|
||||
}
|
||||
free(diEffects);
|
||||
diEffects = 0;
|
||||
}
|
||||
if (active) {
|
||||
did->Unacquire();
|
||||
did->Release();
|
||||
ReleaseDirectInput();
|
||||
did = 0;
|
||||
active = 0;
|
||||
}
|
||||
}
|
||||
|
||||
~DirectInputDevice()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
BOOL CALLBACK EnumEffectsCallback(LPCDIEFFECTINFOW pdei, LPVOID pvRef)
|
||||
{
|
||||
DirectInputDevice *did = (DirectInputDevice *)pvRef;
|
||||
EffectType type;
|
||||
int diType = DIEFT_GETTYPE(pdei->dwEffType);
|
||||
if (diType == DIEFT_CONSTANTFORCE) {
|
||||
type = EFFECT_CONSTANT;
|
||||
} else if (diType == DIEFT_RAMPFORCE) {
|
||||
type = EFFECT_RAMP;
|
||||
} else if (diType == DIEFT_PERIODIC) {
|
||||
type = EFFECT_PERIODIC;
|
||||
} else {
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
wchar_t guidString[50];
|
||||
GUIDtoString(guidString, &pdei->guid);
|
||||
did->AddFFEffectType(pdei->tszName, guidString, type);
|
||||
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
BOOL CALLBACK EnumDeviceObjectsCallback(LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef)
|
||||
{
|
||||
DirectInputDevice *did = (DirectInputDevice *)pvRef;
|
||||
if (lpddoi->dwType & DIDFT_FFACTUATOR) {
|
||||
did->AddFFAxis(lpddoi->tszName, lpddoi->dwType);
|
||||
}
|
||||
|
||||
ControlType type;
|
||||
|
||||
if (lpddoi->dwType & DIDFT_POV)
|
||||
type = POV;
|
||||
else if (lpddoi->dwType & DIDFT_ABSAXIS)
|
||||
type = ABSAXIS;
|
||||
else if (lpddoi->dwType & DIDFT_RELAXIS)
|
||||
type = RELAXIS;
|
||||
else if (lpddoi->dwType & DIDFT_PSHBUTTON)
|
||||
type = PSHBTN;
|
||||
else if (lpddoi->dwType & DIDFT_TGLBUTTON)
|
||||
type = TGLBTN;
|
||||
else
|
||||
return DIENUM_CONTINUE;
|
||||
// If too many objects, ignore extra buttons.
|
||||
if ((did->numPhysicalControls > 255 && DIDFT_GETINSTANCE(lpddoi->dwType) > 255) && (type & (DIDFT_PSHBUTTON | DIDFT_TGLBUTTON))) {
|
||||
int i;
|
||||
for (i = did->numPhysicalControls - 1; i > did->numPhysicalControls - 4; i--) {
|
||||
if (!lpddoi->tszName[0])
|
||||
break;
|
||||
const wchar_t *s1 = lpddoi->tszName;
|
||||
const wchar_t *s2 = did->physicalControls[i].name;
|
||||
while (*s1 && *s1 == *s2) {
|
||||
s1++;
|
||||
s2++;
|
||||
}
|
||||
// If perfect match with one of last 4 names, break.
|
||||
if (!*s1 && !*s2)
|
||||
break;
|
||||
|
||||
while (s1 != lpddoi->tszName && (s1[-1] >= '0' && s1[-1] <= '9'))
|
||||
s1--;
|
||||
int check = 0;
|
||||
while (*s1 >= '0' && *s1 <= '9') {
|
||||
check = check * 10 + *s1 - '0';
|
||||
s1++;
|
||||
}
|
||||
while (*s2 >= '0' && *s2 <= '9') {
|
||||
s2++;
|
||||
}
|
||||
// If perfect match other than final number > 30, then break.
|
||||
// takes care of "button xx" case without causing issues with F keys.
|
||||
if (!*s1 && !*s2 && check > 30)
|
||||
break;
|
||||
}
|
||||
if (i != did->numPhysicalControls - 4) {
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
}
|
||||
|
||||
int vkey = 0;
|
||||
if (lpddoi->tszName[0] && did->type == KEYBOARD) {
|
||||
for (u32 i = 0; i < 256; i++) {
|
||||
wchar_t *t = GetVKStringW((u8)i);
|
||||
if (!wcsicmp(lpddoi->tszName, t)) {
|
||||
vkey = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
did->AddPhysicalControl(type, DIDFT_GETINSTANCE(lpddoi->dwType), vkey, lpddoi->tszName);
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
// Evil code from MS's site. If only they'd just made a way to get
|
||||
// an XInput device's GUID directly in the first place...
|
||||
BOOL IsXInputDevice(const GUID *pGuidProductFromDirectInput)
|
||||
{
|
||||
IWbemLocator *pIWbemLocator = NULL;
|
||||
IEnumWbemClassObject *pEnumDevices = NULL;
|
||||
IWbemClassObject *pDevices[20] = {0};
|
||||
IWbemServices *pIWbemServices = NULL;
|
||||
BSTR bstrNamespace = NULL;
|
||||
BSTR bstrDeviceID = NULL;
|
||||
BSTR bstrClassName = NULL;
|
||||
DWORD uReturned = 0;
|
||||
bool bIsXinputDevice = false;
|
||||
UINT iDevice = 0;
|
||||
VARIANT var;
|
||||
HRESULT hr;
|
||||
|
||||
// CoInit if needed
|
||||
hr = CoInitialize(NULL);
|
||||
bool bCleanupCOM = SUCCEEDED(hr);
|
||||
|
||||
// Create WMI
|
||||
hr = CoCreateInstance(__uuidof(WbemLocator),
|
||||
NULL,
|
||||
CLSCTX_INPROC_SERVER,
|
||||
__uuidof(IWbemLocator),
|
||||
(LPVOID *)&pIWbemLocator);
|
||||
if (FAILED(hr) || pIWbemLocator == NULL)
|
||||
goto LCleanup;
|
||||
|
||||
bstrNamespace = SysAllocString(L"\\\\.\\root\\cimv2");
|
||||
if (bstrNamespace == NULL)
|
||||
goto LCleanup;
|
||||
bstrClassName = SysAllocString(L"Win32_PNPEntity");
|
||||
if (bstrClassName == NULL)
|
||||
goto LCleanup;
|
||||
bstrDeviceID = SysAllocString(L"DeviceID");
|
||||
if (bstrDeviceID == NULL)
|
||||
goto LCleanup;
|
||||
|
||||
// Connect to WMI
|
||||
hr = pIWbemLocator->ConnectServer(bstrNamespace, NULL, NULL, 0L,
|
||||
0L, NULL, NULL, &pIWbemServices);
|
||||
if (FAILED(hr) || pIWbemServices == NULL)
|
||||
goto LCleanup;
|
||||
|
||||
// Switch security level to IMPERSONATE.
|
||||
CoSetProxyBlanket(pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL,
|
||||
RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
|
||||
|
||||
hr = pIWbemServices->CreateInstanceEnum(bstrClassName, 0, NULL, &pEnumDevices);
|
||||
if (FAILED(hr) || pEnumDevices == NULL)
|
||||
goto LCleanup;
|
||||
|
||||
// Loop over all devices
|
||||
for (;;) {
|
||||
// Get 20 at a time
|
||||
hr = pEnumDevices->Next(10000, 20, pDevices, &uReturned);
|
||||
if (FAILED(hr))
|
||||
goto LCleanup;
|
||||
if (uReturned == 0)
|
||||
break;
|
||||
|
||||
for (iDevice = 0; iDevice < uReturned; iDevice++) {
|
||||
// For each device, get its device ID
|
||||
hr = pDevices[iDevice]->Get(bstrDeviceID, 0L, &var, NULL, NULL);
|
||||
if (SUCCEEDED(hr) && var.vt == VT_BSTR && var.bstrVal != NULL) {
|
||||
// Check if the device ID contains "IG_". If it does, then it's an XInput device
|
||||
// This information can not be found from DirectInput
|
||||
if (wcsstr(var.bstrVal, L"IG_")) {
|
||||
// If it does, then get the VID/PID from var.bstrVal
|
||||
DWORD dwPid = 0, dwVid = 0;
|
||||
WCHAR *strVid = wcsstr(var.bstrVal, L"VID_");
|
||||
if (strVid) {
|
||||
dwVid = wcstoul(strVid + 4, 0, 16);
|
||||
}
|
||||
WCHAR *strPid = wcsstr(var.bstrVal, L"PID_");
|
||||
if (strPid) {
|
||||
dwPid = wcstoul(strPid + 4, 0, 16);
|
||||
}
|
||||
|
||||
// Compare the VID/PID to the DInput device
|
||||
DWORD dwVidPid = MAKELONG(dwVid, dwPid);
|
||||
if (dwVidPid == pGuidProductFromDirectInput->Data1) {
|
||||
bIsXinputDevice = true;
|
||||
goto LCleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
SAFE_RELEASE(pDevices[iDevice]);
|
||||
}
|
||||
}
|
||||
|
||||
LCleanup:
|
||||
if (bstrNamespace)
|
||||
SysFreeString(bstrNamespace);
|
||||
if (bstrDeviceID)
|
||||
SysFreeString(bstrDeviceID);
|
||||
if (bstrClassName)
|
||||
SysFreeString(bstrClassName);
|
||||
for (iDevice = 0; iDevice < 20; iDevice++)
|
||||
SAFE_RELEASE(pDevices[iDevice]);
|
||||
SAFE_RELEASE(pEnumDevices);
|
||||
SAFE_RELEASE(pIWbemLocator);
|
||||
SAFE_RELEASE(pIWbemServices);
|
||||
|
||||
if (bCleanupCOM)
|
||||
CoUninitialize();
|
||||
|
||||
return bIsXinputDevice;
|
||||
}
|
||||
|
||||
|
||||
struct DeviceEnumInfo
|
||||
{
|
||||
IDirectInput8 *di8;
|
||||
int ignoreXInput;
|
||||
};
|
||||
|
||||
BOOL CALLBACK EnumCallback(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef)
|
||||
{
|
||||
IDirectInput8 *di8 = ((DeviceEnumInfo *)pvRef)->di8;
|
||||
const wchar_t *name;
|
||||
wchar_t temp[40];
|
||||
//if (((DeviceEnumInfo*)pvRef)->ignoreXInput && lpddi->
|
||||
if (lpddi->tszInstanceName[0]) {
|
||||
name = lpddi->tszInstanceName;
|
||||
} else if (lpddi->tszProductName[0]) {
|
||||
name = lpddi->tszProductName;
|
||||
} else {
|
||||
wsprintfW(temp, L"Device %i", di8d.deviceCount);
|
||||
name = temp;
|
||||
}
|
||||
di8d.deviceCount++;
|
||||
wchar_t *fullName = (wchar_t *)malloc((wcslen(name) + 4) * sizeof(wchar_t));
|
||||
wsprintf(fullName, L"DX %s", name);
|
||||
wchar_t instanceID[100];
|
||||
wchar_t productID[100];
|
||||
GUIDtoString(instanceID, &lpddi->guidInstance);
|
||||
GUIDtoString(productID, &lpddi->guidProduct);
|
||||
DeviceType type = OTHER;
|
||||
if ((lpddi->dwDevType & 0xFF) == DI8DEVTYPE_KEYBOARD) {
|
||||
type = KEYBOARD;
|
||||
} else if ((lpddi->dwDevType & 0xFF) == DI8DEVTYPE_MOUSE) {
|
||||
type = MOUSE;
|
||||
}
|
||||
IDirectInputDevice8 *did;
|
||||
if (DI_OK == di8->CreateDevice(lpddi->guidInstance, &did, 0)) {
|
||||
DirectInputDevice *dev = new DirectInputDevice(type, did, fullName, instanceID, productID, lpddi->guidInstance);
|
||||
if (dev->numPhysicalControls || dev->numFFAxes) {
|
||||
dm->AddDevice(dev);
|
||||
} else {
|
||||
delete dev;
|
||||
}
|
||||
}
|
||||
free(fullName);
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
void EnumDirectInputDevices(int ignoreXInput)
|
||||
{
|
||||
DeviceEnumInfo enumInfo;
|
||||
enumInfo.di8 = GetDirectInput();
|
||||
if (!enumInfo.di8)
|
||||
return;
|
||||
enumInfo.ignoreXInput = ignoreXInput;
|
||||
di8d.deviceCount = 0;
|
||||
enumInfo.di8->EnumDevices(DI8DEVCLASS_ALL, EnumCallback, &enumInfo, DIEDFL_ATTACHEDONLY);
|
||||
ReleaseDirectInput();
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/* LilyPad - Pad plugin for PS2 Emulator
|
||||
* Copyright (C) 2002-2014 PCSX2 Dev Team/ChickenLiver
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Found- ation, either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* PCSX2 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 for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with PCSX2. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
void EnumDirectInputDevices(int ignoreXInput);
|
|
@ -0,0 +1,498 @@
|
|||
/* LilyPad - Pad plugin for PS2 Emulator
|
||||
* Copyright (C) 2002-2014 PCSX2 Dev Team/ChickenLiver
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Found- ation, either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* PCSX2 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 for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with PCSX2. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Global.h"
|
||||
#include "InputManager.h"
|
||||
#include "Config.h"
|
||||
|
||||
#include "usb.h"
|
||||
#include "HidDevice.h"
|
||||
|
||||
|
||||
#define VID 0x054c
|
||||
#define PID 0x0268
|
||||
|
||||
// Unresponsive period required before calling DS3Check().
|
||||
#define DEVICE_CHECK_DELAY 2000
|
||||
// Unresponsive period required before calling DS3Enum(). Note that enum is always called on first check.
|
||||
#define DEVICE_ENUM_DELAY 10000
|
||||
|
||||
// Delay between when DS3Check() and DS3Enum() actually do stuff.
|
||||
#define DOUBLE_CHECK_DELAY 1000
|
||||
#define DOUBLE_ENUM_DELAY 20000
|
||||
|
||||
// Send at least one message every 3 seconds - basically just makes sure the right light(s) are on.
|
||||
// Not really necessary.
|
||||
#define UPDATE_INTERVAL 3000
|
||||
|
||||
unsigned int lastDS3Check = 0;
|
||||
unsigned int lastDS3Enum = 0;
|
||||
|
||||
typedef void(__cdecl *_usb_init)(void);
|
||||
typedef int(__cdecl *_usb_close)(usb_dev_handle *dev);
|
||||
typedef int(__cdecl *_usb_get_string_simple)(usb_dev_handle *dev, int index, char *buf, size_t buflen);
|
||||
typedef usb_dev_handle *(__cdecl *_usb_open)(struct usb_device *dev);
|
||||
typedef int(__cdecl *_usb_find_busses)(void);
|
||||
typedef int(__cdecl *_usb_find_devices)(void);
|
||||
typedef struct usb_bus *(__cdecl *_usb_get_busses)(void);
|
||||
typedef usb_dev_handle *(__cdecl *_usb_open)(struct usb_device *dev);
|
||||
typedef int(__cdecl *_usb_control_msg)(usb_dev_handle *dev, int requesttype, int request, int value, int index, char *bytes, int size, int timeout);
|
||||
|
||||
_usb_init pusb_init;
|
||||
_usb_close pusb_close;
|
||||
_usb_get_string_simple pusb_get_string_simple;
|
||||
_usb_open pusb_open;
|
||||
_usb_find_busses pusb_find_busses;
|
||||
_usb_find_devices pusb_find_devices;
|
||||
_usb_get_busses pusb_get_busses;
|
||||
_usb_control_msg pusb_control_msg;
|
||||
|
||||
HMODULE hModLibusb = 0;
|
||||
|
||||
void UninitLibUsb()
|
||||
{
|
||||
if (hModLibusb) {
|
||||
FreeLibrary(hModLibusb);
|
||||
hModLibusb = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void TryInitDS3(usb_device *dev)
|
||||
{
|
||||
while (dev) {
|
||||
if (dev->descriptor.idVendor == VID && dev->descriptor.idProduct == PID) {
|
||||
usb_dev_handle *handle = pusb_open(dev);
|
||||
if (handle) {
|
||||
char junk[20];
|
||||
// This looks like HidD_GetFeature with a feature report id of 0xF2 to me and a length of 17.
|
||||
// That doesn't work, however, and 17 is shorter than the report length.
|
||||
pusb_control_msg(handle, 0xa1, 1, 0x03f2, dev->config->interface->altsetting->bInterfaceNumber, junk, 17, 1000);
|
||||
pusb_close(handle);
|
||||
}
|
||||
}
|
||||
if (dev->num_children) {
|
||||
for (int i = 0; i < dev->num_children; i++) {
|
||||
TryInitDS3(dev->children[i]);
|
||||
}
|
||||
}
|
||||
dev = dev->next;
|
||||
}
|
||||
}
|
||||
|
||||
void DS3Enum(unsigned int time)
|
||||
{
|
||||
if (time - lastDS3Enum < DOUBLE_ENUM_DELAY) {
|
||||
return;
|
||||
}
|
||||
lastDS3Enum = time;
|
||||
pusb_find_busses();
|
||||
pusb_find_devices();
|
||||
}
|
||||
|
||||
void DS3Check(unsigned int time)
|
||||
{
|
||||
if (time - lastDS3Check < DOUBLE_CHECK_DELAY) {
|
||||
return;
|
||||
}
|
||||
if (!lastDS3Check) {
|
||||
DS3Enum(time);
|
||||
}
|
||||
lastDS3Check = time;
|
||||
|
||||
usb_bus *bus = pusb_get_busses();
|
||||
while (bus) {
|
||||
TryInitDS3(bus->devices);
|
||||
bus = bus->next;
|
||||
}
|
||||
}
|
||||
|
||||
int InitLibUsb()
|
||||
{
|
||||
if (hModLibusb) {
|
||||
return 1;
|
||||
}
|
||||
hModLibusb = LoadLibraryA("C:\\windows\\system32\\libusb0.dll");
|
||||
if (hModLibusb) {
|
||||
if ((pusb_init = (_usb_init)GetProcAddress(hModLibusb, "usb_init")) &&
|
||||
(pusb_close = (_usb_close)GetProcAddress(hModLibusb, "usb_close")) &&
|
||||
(pusb_get_string_simple = (_usb_get_string_simple)GetProcAddress(hModLibusb, "usb_get_string_simple")) &&
|
||||
(pusb_open = (_usb_open)GetProcAddress(hModLibusb, "usb_open")) &&
|
||||
(pusb_find_busses = (_usb_find_busses)GetProcAddress(hModLibusb, "usb_find_busses")) &&
|
||||
(pusb_find_devices = (_usb_find_devices)GetProcAddress(hModLibusb, "usb_find_devices")) &&
|
||||
(pusb_get_busses = (_usb_get_busses)GetProcAddress(hModLibusb, "usb_get_busses")) &&
|
||||
(pusb_control_msg = (_usb_control_msg)GetProcAddress(hModLibusb, "usb_control_msg"))) {
|
||||
pusb_init();
|
||||
return 1;
|
||||
}
|
||||
UninitLibUsb();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DualShock3Possible()
|
||||
{
|
||||
return InitLibUsb();
|
||||
}
|
||||
|
||||
#include <pshpack1.h>
|
||||
|
||||
struct MotorState
|
||||
{
|
||||
unsigned char duration;
|
||||
unsigned char force;
|
||||
};
|
||||
|
||||
struct LightState
|
||||
{
|
||||
// 0xFF makes it stay on.
|
||||
unsigned char duration;
|
||||
// Have to make one or the other non-zero to turn on light.
|
||||
unsigned char dunno[2];
|
||||
// 0 is fully lit.
|
||||
unsigned char dimness;
|
||||
// Have to make non-zero to turn on light.
|
||||
unsigned char on;
|
||||
};
|
||||
|
||||
// Data sent to DS3 to set state.
|
||||
struct DS3Command
|
||||
{
|
||||
unsigned char id;
|
||||
unsigned char unsure;
|
||||
// Small is first, then big.
|
||||
MotorState motors[2];
|
||||
unsigned char noClue[4];
|
||||
// 2 is pad 1 light, 4 is pad 2, 8 is pad 3, 16 is pad 4. No clue about the others.
|
||||
unsigned char lightFlags;
|
||||
// Lights are in reverse order. pad 1 is last.
|
||||
LightState lights[4];
|
||||
unsigned char dunno[18];
|
||||
};
|
||||
|
||||
#include <poppack.h>
|
||||
|
||||
int CharToAxis(unsigned char c)
|
||||
{
|
||||
int v = (int)c + ((unsigned int)c >> 7);
|
||||
return ((c - 128) * FULLY_DOWN) >> 7;
|
||||
}
|
||||
|
||||
int CharToButton(unsigned char c)
|
||||
{
|
||||
int v = (int)c + ((unsigned int)c >> 7);
|
||||
return (v * FULLY_DOWN) >> 8;
|
||||
}
|
||||
|
||||
class DualShock3Device : public Device
|
||||
{
|
||||
// Cached last vibration values by pad and motor.
|
||||
// Need this, as only one value is changed at a time.
|
||||
int ps2Vibration[2][4][2];
|
||||
int vibration[2];
|
||||
|
||||
public:
|
||||
int index;
|
||||
HANDLE hFile;
|
||||
DS3Command sendState;
|
||||
unsigned char getState[49];
|
||||
OVERLAPPED readop;
|
||||
OVERLAPPED writeop;
|
||||
int writeCount;
|
||||
int lastWrite;
|
||||
|
||||
unsigned int dataLastReceived;
|
||||
|
||||
int writeQueued;
|
||||
int writing;
|
||||
|
||||
int StartRead()
|
||||
{
|
||||
int res = ReadFile(hFile, &getState, sizeof(getState), 0, &readop);
|
||||
return (res || GetLastError() == ERROR_IO_PENDING);
|
||||
}
|
||||
|
||||
void QueueWrite()
|
||||
{
|
||||
// max of 2 queued writes allowed, one for either motor.
|
||||
if (writeQueued < 2) {
|
||||
writeQueued++;
|
||||
StartWrite();
|
||||
}
|
||||
}
|
||||
|
||||
int StartWrite()
|
||||
{
|
||||
if (!writing && writeQueued) {
|
||||
lastWrite = GetTickCount();
|
||||
writing++;
|
||||
writeQueued--;
|
||||
sendState.motors[0].duration = 0x50;
|
||||
sendState.motors[1].duration = 0x50;
|
||||
|
||||
int bigForce = vibration[0] * 256 / FULLY_DOWN;
|
||||
if (bigForce > 255)
|
||||
bigForce = 255;
|
||||
sendState.motors[1].force = (unsigned char)bigForce;
|
||||
sendState.motors[0].force = (unsigned char)(vibration[1] >= FULLY_DOWN / 2);
|
||||
// Can't seem to have them both non-zero at once.
|
||||
if (sendState.motors[writeCount & 1].force) {
|
||||
sendState.motors[(writeCount & 1) ^ 1].force = 0;
|
||||
sendState.motors[(writeCount & 1) ^ 1].duration = 0;
|
||||
}
|
||||
|
||||
writeCount++;
|
||||
int res = WriteFile(hFile, &sendState, sizeof(sendState), 0, &writeop);
|
||||
return (res || GetLastError() == ERROR_IO_PENDING);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
DualShock3Device(int index, wchar_t *name, wchar_t *path)
|
||||
: Device(DS3, OTHER, name, path, L"DualShock 3")
|
||||
{
|
||||
writeCount = 0;
|
||||
writing = 0;
|
||||
writeQueued = 0;
|
||||
memset(&readop, 0, sizeof(readop));
|
||||
memset(&writeop, 0, sizeof(writeop));
|
||||
memset(&sendState, 0, sizeof(sendState));
|
||||
sendState.id = 1;
|
||||
int temp = (index & 4);
|
||||
sendState.lightFlags = (1 << (temp + 1));
|
||||
sendState.lights[3 - temp].duration = 0xFF;
|
||||
sendState.lights[3 - temp].dunno[0] = 1;
|
||||
sendState.lights[3 - temp].on = 1;
|
||||
memset(ps2Vibration, 0, sizeof(ps2Vibration));
|
||||
vibration[0] = vibration[1] = 0;
|
||||
this->index = index;
|
||||
int i;
|
||||
for (i = 0; i < 16; i++) {
|
||||
if (i != 14 && i != 15 && i != 8 && i != 9) {
|
||||
AddPhysicalControl(PRESSURE_BTN, i, 0);
|
||||
} else {
|
||||
AddPhysicalControl(PSHBTN, i, 0);
|
||||
}
|
||||
}
|
||||
for (; i < 23; i++) {
|
||||
AddPhysicalControl(ABSAXIS, i, 0);
|
||||
}
|
||||
AddFFAxis(L"Big Motor", 0);
|
||||
AddFFAxis(L"Small Motor", 1);
|
||||
AddFFEffectType(L"Constant Effect", L"Constant", EFFECT_CONSTANT);
|
||||
hFile = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
wchar_t *GetPhysicalControlName(PhysicalControl *c)
|
||||
{
|
||||
const static wchar_t *names[] = {
|
||||
L"Square",
|
||||
L"Cross",
|
||||
L"Circle",
|
||||
L"Triangle",
|
||||
L"R1",
|
||||
L"L1",
|
||||
L"R2",
|
||||
L"L2",
|
||||
L"R3",
|
||||
L"L3",
|
||||
L"Left",
|
||||
L"Down",
|
||||
L"Right",
|
||||
L"Up",
|
||||
L"Start",
|
||||
L"Select",
|
||||
L"L-Stick X",
|
||||
L"L-Stick Y",
|
||||
L"R-Stick X",
|
||||
L"R-Stick Y",
|
||||
L"Left/Right Tilt",
|
||||
L"Forward/Back Tilt",
|
||||
L"???",
|
||||
};
|
||||
unsigned int i = (unsigned int)(c - physicalControls);
|
||||
if (i < sizeof(names) / sizeof(names[0])) {
|
||||
return (wchar_t *)names[i];
|
||||
}
|
||||
return Device::GetPhysicalControlName(c);
|
||||
}
|
||||
|
||||
int Activate(InitInfo *initInfo)
|
||||
{
|
||||
if (active)
|
||||
Deactivate();
|
||||
// Give grace period before get mad.
|
||||
lastWrite = dataLastReceived = GetTickCount();
|
||||
readop.hEvent = CreateEvent(0, 0, 0, 0);
|
||||
writeop.hEvent = CreateEvent(0, 0, 0, 0);
|
||||
hFile = CreateFileW(instanceID, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
|
||||
if (!readop.hEvent || !writeop.hEvent || hFile == INVALID_HANDLE_VALUE ||
|
||||
!StartRead()) {
|
||||
Deactivate();
|
||||
return 0;
|
||||
}
|
||||
active = 1;
|
||||
AllocState();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Update()
|
||||
{
|
||||
if (!active)
|
||||
return 0;
|
||||
HANDLE h[2] = {
|
||||
readop.hEvent,
|
||||
writeop.hEvent};
|
||||
unsigned int time = GetTickCount();
|
||||
if (time - lastWrite > UPDATE_INTERVAL) {
|
||||
QueueWrite();
|
||||
}
|
||||
while (1) {
|
||||
DWORD res = WaitForMultipleObjects(2, h, 0, 0);
|
||||
if (res == WAIT_OBJECT_0) {
|
||||
dataLastReceived = time;
|
||||
if (!StartRead()) {
|
||||
Deactivate();
|
||||
return 0;
|
||||
}
|
||||
|
||||
physicalControlState[0] = CharToButton(getState[25]);
|
||||
physicalControlState[1] = CharToButton(getState[24]);
|
||||
physicalControlState[2] = CharToButton(getState[23]);
|
||||
physicalControlState[3] = CharToButton(getState[22]);
|
||||
physicalControlState[4] = CharToButton(getState[21]);
|
||||
physicalControlState[5] = CharToButton(getState[20]);
|
||||
physicalControlState[6] = CharToButton(getState[19]);
|
||||
physicalControlState[7] = CharToButton(getState[18]);
|
||||
physicalControlState[10] = CharToButton(getState[17]);
|
||||
physicalControlState[11] = CharToButton(getState[16]);
|
||||
physicalControlState[12] = CharToButton(getState[15]);
|
||||
physicalControlState[13] = CharToButton(getState[14]);
|
||||
physicalControlState[8] = ((getState[2] & 4) / 4) * FULLY_DOWN;
|
||||
physicalControlState[9] = ((getState[2] & 2) / 2) * FULLY_DOWN;
|
||||
physicalControlState[15] = ((getState[2] & 1) / 1) * FULLY_DOWN;
|
||||
physicalControlState[14] = ((getState[2] & 8) / 8) * FULLY_DOWN;
|
||||
physicalControlState[16] = CharToAxis(getState[6]);
|
||||
physicalControlState[17] = CharToAxis(getState[7]);
|
||||
physicalControlState[18] = CharToAxis(getState[8]);
|
||||
physicalControlState[19] = CharToAxis(getState[9]);
|
||||
physicalControlState[20] = CharToAxis(getState[42] + 128);
|
||||
physicalControlState[21] = CharToAxis(getState[44] + 128);
|
||||
physicalControlState[22] = CharToAxis(getState[46] + 128);
|
||||
continue;
|
||||
} else if (res == WAIT_OBJECT_0 + 1) {
|
||||
writing = 0;
|
||||
if (!writeQueued && (vibration[0] | vibration[1])) {
|
||||
QueueWrite();
|
||||
}
|
||||
if (!StartWrite()) {
|
||||
Deactivate();
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if (time - dataLastReceived >= DEVICE_CHECK_DELAY) {
|
||||
if (time - dataLastReceived >= DEVICE_ENUM_DELAY) {
|
||||
DS3Enum(time);
|
||||
}
|
||||
DS3Check(time);
|
||||
QueueWrite();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void SetEffects(unsigned char port, unsigned int slot, unsigned char motor, unsigned char force)
|
||||
{
|
||||
ps2Vibration[port][slot][motor] = force;
|
||||
vibration[0] = vibration[1] = 0;
|
||||
for (int p = 0; p < 2; p++) {
|
||||
for (int s = 0; s < 4; s++) {
|
||||
int padtype = config.padConfigs[p][s].type;
|
||||
for (int i = 0; i < pads[p][s][padtype].numFFBindings; i++) {
|
||||
// Technically should also be a *65535/BASE_SENSITIVITY, but that's close enough to 1 for me.
|
||||
ForceFeedbackBinding *ffb = &pads[p][s][padtype].ffBindings[i];
|
||||
vibration[0] += (int)((ffb->axes[0].force * (__int64)ps2Vibration[p][s][ffb->motor]) / 255);
|
||||
vibration[1] += (int)((ffb->axes[1].force * (__int64)ps2Vibration[p][s][ffb->motor]) / 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Make sure at least 2 writes are queued, to update both motors.
|
||||
QueueWrite();
|
||||
QueueWrite();
|
||||
}
|
||||
|
||||
void SetEffect(ForceFeedbackBinding *binding, unsigned char force)
|
||||
{
|
||||
PadBindings pBackup = pads[0][0][0];
|
||||
pads[0][0][0].ffBindings = binding;
|
||||
pads[0][0][0].numFFBindings = 1;
|
||||
SetEffects(0, 0, binding->motor, 255);
|
||||
pads[0][0][0] = pBackup;
|
||||
}
|
||||
|
||||
void Deactivate()
|
||||
{
|
||||
if (hFile != INVALID_HANDLE_VALUE) {
|
||||
CancelIo(hFile);
|
||||
CloseHandle(hFile);
|
||||
hFile = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if (readop.hEvent) {
|
||||
CloseHandle(readop.hEvent);
|
||||
}
|
||||
if (writeop.hEvent) {
|
||||
CloseHandle(writeop.hEvent);
|
||||
}
|
||||
writing = 0;
|
||||
writeQueued = 0;
|
||||
memset(ps2Vibration, 0, sizeof(ps2Vibration));
|
||||
vibration[0] = vibration[1] = 0;
|
||||
|
||||
FreeState();
|
||||
active = 0;
|
||||
}
|
||||
|
||||
~DualShock3Device()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
void EnumDualShock3s()
|
||||
{
|
||||
if (!InitLibUsb())
|
||||
return;
|
||||
|
||||
HidDeviceInfo *foundDevs = 0;
|
||||
|
||||
int numDevs = FindHids(&foundDevs, VID, PID);
|
||||
if (!numDevs)
|
||||
return;
|
||||
int index = 0;
|
||||
for (int i = 0; i < numDevs; i++) {
|
||||
if (foundDevs[i].caps.FeatureReportByteLength == 49 &&
|
||||
foundDevs[i].caps.InputReportByteLength == 49 &&
|
||||
foundDevs[i].caps.OutputReportByteLength == 49) {
|
||||
wchar_t temp[100];
|
||||
wsprintfW(temp, L"DualShock 3 #%i", index + 1);
|
||||
dm->AddDevice(new DualShock3Device(index, temp, foundDevs[i].path));
|
||||
index++;
|
||||
}
|
||||
free(foundDevs[i].path);
|
||||
}
|
||||
free(foundDevs);
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/* LilyPad - Pad plugin for PS2 Emulator
|
||||
* Copyright (C) 2002-2014 PCSX2 Dev Team/ChickenLiver
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Found- ation, either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* PCSX2 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 for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with PCSX2. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
int DualShock3Possible();
|
||||
void EnumDualShock3s();
|
||||
|
||||
// May move elsewhere in the future.
|
||||
int InitLibUsb();
|
||||
void UninitLibUsb();
|
|
@ -0,0 +1,18 @@
|
|||
/* LilyPad - Pad plugin for PS2 Emulator
|
||||
* Copyright (C) 2002-2014 PCSX2 Dev Team/ChickenLiver
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Found- ation, either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* PCSX2 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 for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with PCSX2. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Global.h"
|
|
@ -0,0 +1,195 @@
|
|||
/* LilyPad - Pad plugin for PS2 Emulator
|
||||
* Copyright (C) 2002-2014 PCSX2 Dev Team/ChickenLiver
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Found- ation, either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* PCSX2 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 for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with PCSX2. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __linux__
|
||||
// Seriously why there is no standard
|
||||
#include "stdint.h"
|
||||
typedef uint32_t DWORD;
|
||||
typedef uint16_t USHORT;
|
||||
#ifndef __INTEL_COMPILER
|
||||
typedef int64_t __int64;
|
||||
#endif
|
||||
|
||||
#define MAX_PATH (256) // random value
|
||||
|
||||
#include <X11/keysym.h>
|
||||
|
||||
#define VK_SHIFT XK_Shift_L
|
||||
#define VK_LSHIFT XK_Shift_L
|
||||
#define VK_RSHIFT XK_Shift_R
|
||||
#define VK_LMENU XK_Menu
|
||||
#define VK_RMENU XK_Menu
|
||||
#define VK_MENU XK_Menu
|
||||
#define VK_CONTROL XK_Control_L
|
||||
#define VK_TAB XK_Tab
|
||||
#define VK_ESCAPE XK_Escape
|
||||
#define VK_F4 XK_F4
|
||||
|
||||
#include <cwchar>
|
||||
#include <cstdarg>
|
||||
|
||||
template <typename Array>
|
||||
void wsprintfW(Array &buf, const wchar_t *format, ...)
|
||||
{
|
||||
va_list a;
|
||||
va_start(a, format);
|
||||
|
||||
vswprintf(buf, sizeof(buf) / sizeof(buf[0]), format, a);
|
||||
|
||||
va_end(a);
|
||||
}
|
||||
|
||||
template <typename Array>
|
||||
void wsprintf(Array &buf, const wchar_t *format, ...)
|
||||
{
|
||||
va_list a;
|
||||
va_start(a, format);
|
||||
|
||||
vswprintf(buf, sizeof(buf) / sizeof(buf[0]), format, a);
|
||||
|
||||
va_end(a);
|
||||
}
|
||||
|
||||
static inline int wcsicmp(const wchar_t *w1, const wchar_t *w2)
|
||||
{
|
||||
// I didn't find a way to put ignore case ...
|
||||
return wcscmp(w1, w2);
|
||||
}
|
||||
|
||||
#include <sys/time.h>
|
||||
static inline unsigned int timeGetTime()
|
||||
{
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
uint64_t ms = (now.tv_usec / 1000) + ((uint64_t)now.tv_sec * 1000);
|
||||
return (ms & 0xFFFFFFFF); // MS code is u32 ...
|
||||
}
|
||||
|
||||
#include "Utilities/Dependencies.h"
|
||||
#include "Utilities/StringHelpers.h"
|
||||
#include "Utilities/Path.h"
|
||||
|
||||
#include <X11/Xutil.h>
|
||||
|
||||
extern Display *GSdsp;
|
||||
extern Window GSwin;
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef _CRT_SECURE_NO_DEPRECATE
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define EXPORT_C_(type) extern "C" type CALLBACK
|
||||
#else
|
||||
#define EXPORT_C_(type) extern "C" __attribute__((stdcall, externally_visible, visibility("default"))) type CALLBACK
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define _WIN32_WINNT 0x0600
|
||||
#define NOMINMAX
|
||||
#include <algorithm>
|
||||
#include <windows.h>
|
||||
|
||||
#ifdef PCSX2_DEBUG
|
||||
#define _CRTDBG_MAPALLOC
|
||||
#define _CRTDBG_MAP_ALLOC
|
||||
#include <stdlib.h>
|
||||
#include <crtdbg.h>
|
||||
#else
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <mutex>
|
||||
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <commctrl.h>
|
||||
// Only needed for DBT_DEVNODES_CHANGED
|
||||
#include <Dbt.h>
|
||||
#endif
|
||||
|
||||
#include "PS2Edefs.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
extern HINSTANCE hInst;
|
||||
#endif
|
||||
// Needed for config screen
|
||||
void GetNameAndVersionString(wchar_t *out);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char controllerType;
|
||||
unsigned short buttonStatus;
|
||||
unsigned char rightJoyX, rightJoyY, leftJoyX, leftJoyY;
|
||||
unsigned char moveX, moveY;
|
||||
unsigned char reserved[91];
|
||||
} PadDataS;
|
||||
|
||||
EXPORT_C_(void)
|
||||
PADupdate(int pad);
|
||||
EXPORT_C_(u32)
|
||||
PS2EgetLibType(void);
|
||||
EXPORT_C_(u32)
|
||||
PS2EgetLibVersion2(u32 type);
|
||||
EXPORT_C_(char *)
|
||||
PS2EgetLibName(void);
|
||||
EXPORT_C_(void)
|
||||
PADshutdown();
|
||||
EXPORT_C_(s32)
|
||||
PADinit(u32 flags);
|
||||
EXPORT_C_(s32)
|
||||
PADopen(void *pDsp);
|
||||
EXPORT_C_(void)
|
||||
PADclose();
|
||||
EXPORT_C_(u8)
|
||||
PADstartPoll(int pad);
|
||||
EXPORT_C_(u8)
|
||||
PADpoll(u8 value);
|
||||
EXPORT_C_(u32)
|
||||
PADquery();
|
||||
EXPORT_C_(void)
|
||||
PADabout();
|
||||
EXPORT_C_(s32)
|
||||
PADtest();
|
||||
EXPORT_C_(keyEvent *)
|
||||
PADkeyEvent();
|
||||
EXPORT_C_(u32)
|
||||
PADreadPort1(PadDataS *pads);
|
||||
EXPORT_C_(u32)
|
||||
PADreadPort2(PadDataS *pads);
|
||||
EXPORT_C_(void)
|
||||
PADconfigure();
|
||||
EXPORT_C_(s32)
|
||||
PADfreeze(int mode, freezeData *data);
|
||||
EXPORT_C_(s32)
|
||||
PADsetSlot(u8 port, u8 slot);
|
||||
EXPORT_C_(s32)
|
||||
PADqueryMtap(u8 port);
|
||||
EXPORT_C_(void)
|
||||
PADsetSettingsDir(const char *dir);
|
|
@ -0,0 +1,80 @@
|
|||
/* LilyPad - Pad plugin for PS2 Emulator
|
||||
* Copyright (C) 2002-2014 PCSX2 Dev Team/ChickenLiver
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Found- ation, either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* PCSX2 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 for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with PCSX2. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Global.h"
|
||||
#include "HidDevice.h"
|
||||
#include <setupapi.h>
|
||||
#include <hidsdi.h>
|
||||
|
||||
int FindHids(HidDeviceInfo **foundDevs, int vid, int pid)
|
||||
{
|
||||
GUID GUID_DEVINTERFACE_HID;
|
||||
int numFoundDevs = 0;
|
||||
*foundDevs = 0;
|
||||
HidD_GetHidGuid(&GUID_DEVINTERFACE_HID);
|
||||
HDEVINFO hdev = SetupDiGetClassDevs(&GUID_DEVINTERFACE_HID, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
|
||||
if (hdev != INVALID_HANDLE_VALUE) {
|
||||
SP_DEVICE_INTERFACE_DATA devInterfaceData;
|
||||
devInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
|
||||
for (int i = 0; SetupDiEnumDeviceInterfaces(hdev, 0, &GUID_DEVINTERFACE_HID, i, &devInterfaceData); i++) {
|
||||
|
||||
DWORD size = 0;
|
||||
SetupDiGetDeviceInterfaceDetail(hdev, &devInterfaceData, 0, 0, &size, 0);
|
||||
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER || !size)
|
||||
continue;
|
||||
SP_DEVICE_INTERFACE_DETAIL_DATA *devInterfaceDetails = (SP_DEVICE_INTERFACE_DETAIL_DATA *)malloc(size);
|
||||
if (!devInterfaceDetails)
|
||||
continue;
|
||||
|
||||
devInterfaceDetails->cbSize = sizeof(*devInterfaceDetails);
|
||||
SP_DEVINFO_DATA devInfoData;
|
||||
devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
|
||||
|
||||
if (!SetupDiGetDeviceInterfaceDetail(hdev, &devInterfaceData, devInterfaceDetails, size, &size, &devInfoData))
|
||||
continue;
|
||||
|
||||
HANDLE hfile = CreateFile(devInterfaceDetails->DevicePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
|
||||
if (hfile != INVALID_HANDLE_VALUE) {
|
||||
HIDD_ATTRIBUTES attributes;
|
||||
attributes.Size = sizeof(attributes);
|
||||
if (HidD_GetAttributes(hfile, &attributes)) {
|
||||
if (attributes.VendorID == vid && attributes.ProductID == pid) {
|
||||
PHIDP_PREPARSED_DATA pData;
|
||||
HIDP_CAPS caps;
|
||||
if (HidD_GetPreparsedData(hfile, &pData)) {
|
||||
if (HidP_GetCaps(pData, &caps) == HIDP_STATUS_SUCCESS) {
|
||||
if (numFoundDevs % 32 == 0) {
|
||||
*foundDevs = (HidDeviceInfo *)realloc(*foundDevs, sizeof(HidDeviceInfo) * (32 + numFoundDevs));
|
||||
}
|
||||
HidDeviceInfo *dev = &foundDevs[0][numFoundDevs++];
|
||||
dev->caps = caps;
|
||||
dev->vid = attributes.VendorID;
|
||||
dev->pid = attributes.ProductID;
|
||||
dev->path = wcsdup(devInterfaceDetails->DevicePath);
|
||||
}
|
||||
HidD_FreePreparsedData(pData);
|
||||
}
|
||||
}
|
||||
}
|
||||
CloseHandle(hfile);
|
||||
}
|
||||
free(devInterfaceDetails);
|
||||
}
|
||||
SetupDiDestroyDeviceInfoList(hdev);
|
||||
}
|
||||
return numFoundDevs;
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/* LilyPad - Pad plugin for PS2 Emulator
|
||||
* Copyright (C) 2002-2014 PCSX2 Dev Team/ChickenLiver
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Found- ation, either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* PCSX2 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 for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with PCSX2. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef HID_DEVICE_H
|
||||
#define HID_DEVICE_H
|
||||
|
||||
#include <hidsdi.h>
|
||||
|
||||
struct HidDeviceInfo
|
||||
{
|
||||
HIDP_CAPS caps;
|
||||
wchar_t *path;
|
||||
unsigned short vid;
|
||||
unsigned short pid;
|
||||
};
|
||||
|
||||
int FindHids(HidDeviceInfo **foundDevs, int vid, int pid);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,662 @@
|
|||
/* LilyPad - Pad plugin for PS2 Emulator
|
||||
* Copyright (C) 2002-2014 PCSX2 Dev Team/ChickenLiver
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Found- ation, either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* PCSX2 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 for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with PCSX2. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Global.h"
|
||||
#include "InputManager.h"
|
||||
#include "KeyboardQueue.h"
|
||||
#include "Config.h"
|
||||
|
||||
InputDeviceManager *dm = 0;
|
||||
|
||||
InputDeviceManager::InputDeviceManager()
|
||||
{
|
||||
memset(this, 0, sizeof(*this));
|
||||
}
|
||||
|
||||
void InputDeviceManager::ClearDevices()
|
||||
{
|
||||
for (int i = 0; i < numDevices; i++) {
|
||||
delete devices[i];
|
||||
}
|
||||
free(devices);
|
||||
devices = 0;
|
||||
numDevices = 0;
|
||||
}
|
||||
|
||||
InputDeviceManager::~InputDeviceManager()
|
||||
{
|
||||
ClearDevices();
|
||||
}
|
||||
|
||||
Device::Device(DeviceAPI api, DeviceType d, const wchar_t *displayName, const wchar_t *instanceID, const wchar_t *productID)
|
||||
{
|
||||
memset(pads, 0, sizeof(pads));
|
||||
this->api = api;
|
||||
type = d;
|
||||
this->displayName = wcsdup(displayName);
|
||||
if (instanceID)
|
||||
this->instanceID = wcsdup(instanceID);
|
||||
else
|
||||
this->instanceID = wcsdup(displayName);
|
||||
this->productID = 0;
|
||||
if (productID)
|
||||
this->productID = wcsdup(productID);
|
||||
active = 0;
|
||||
attached = 1;
|
||||
enabled = 0;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
hWndProc = 0;
|
||||
#endif
|
||||
|
||||
virtualControls = 0;
|
||||
numVirtualControls = 0;
|
||||
virtualControlState = 0;
|
||||
oldVirtualControlState = 0;
|
||||
|
||||
physicalControls = 0;
|
||||
numPhysicalControls = 0;
|
||||
physicalControlState = 0;
|
||||
|
||||
ffEffectTypes = 0;
|
||||
numFFEffectTypes = 0;
|
||||
ffAxes = 0;
|
||||
numFFAxes = 0;
|
||||
}
|
||||
|
||||
void Device::FreeState()
|
||||
{
|
||||
if (virtualControlState)
|
||||
free(virtualControlState);
|
||||
virtualControlState = 0;
|
||||
oldVirtualControlState = 0;
|
||||
physicalControlState = 0;
|
||||
}
|
||||
|
||||
Device::~Device()
|
||||
{
|
||||
Deactivate();
|
||||
// Generally called by deactivate, but just in case...
|
||||
FreeState();
|
||||
int i;
|
||||
for (int port = 0; port < 2; port++) {
|
||||
for (int slot = 0; slot < 4; slot++) {
|
||||
for (int padtype = 0; padtype < numPadTypes; padtype++) {
|
||||
free(pads[port][slot][padtype].bindings);
|
||||
for (i = 0; i < pads[port][slot][padtype].numFFBindings; i++) {
|
||||
free(pads[port][slot][padtype].ffBindings[i].axes);
|
||||
}
|
||||
free(pads[port][slot][padtype].ffBindings);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(virtualControls);
|
||||
|
||||
for (i = numPhysicalControls - 1; i >= 0; i--) {
|
||||
if (physicalControls[i].name)
|
||||
free(physicalControls[i].name);
|
||||
}
|
||||
free(physicalControls);
|
||||
|
||||
free(displayName);
|
||||
free(instanceID);
|
||||
free(productID);
|
||||
if (ffAxes) {
|
||||
for (i = 0; i < numFFAxes; i++) {
|
||||
free(ffAxes[i].displayName);
|
||||
}
|
||||
free(ffAxes);
|
||||
}
|
||||
if (ffEffectTypes) {
|
||||
for (i = 0; i < numFFEffectTypes; i++) {
|
||||
free(ffEffectTypes[i].displayName);
|
||||
free(ffEffectTypes[i].effectID);
|
||||
}
|
||||
free(ffEffectTypes);
|
||||
}
|
||||
}
|
||||
|
||||
void Device::AddFFEffectType(const wchar_t *displayName, const wchar_t *effectID, EffectType type)
|
||||
{
|
||||
ffEffectTypes = (ForceFeedbackEffectType *)realloc(ffEffectTypes, sizeof(ForceFeedbackEffectType) * (numFFEffectTypes + 1));
|
||||
ffEffectTypes[numFFEffectTypes].displayName = wcsdup(displayName);
|
||||
ffEffectTypes[numFFEffectTypes].effectID = wcsdup(effectID);
|
||||
ffEffectTypes[numFFEffectTypes].type = type;
|
||||
numFFEffectTypes++;
|
||||
}
|
||||
|
||||
void Device::AddFFAxis(const wchar_t *displayName, int id)
|
||||
{
|
||||
ffAxes = (ForceFeedbackAxis *)realloc(ffAxes, sizeof(ForceFeedbackAxis) * (numFFAxes + 1));
|
||||
ffAxes[numFFAxes].id = id;
|
||||
ffAxes[numFFAxes].displayName = wcsdup(displayName);
|
||||
numFFAxes++;
|
||||
int bindingsExist = 0;
|
||||
for (int port = 0; port < 2; port++) {
|
||||
for (int slot = 0; slot < 4; slot++) {
|
||||
for (int padtype = 0; padtype < numPadTypes; padtype++) {
|
||||
for (int i = 0; i < pads[port][slot][padtype].numFFBindings; i++) {
|
||||
ForceFeedbackBinding *b = pads[port][slot][padtype].ffBindings + i;
|
||||
b->axes = (AxisEffectInfo *)realloc(b->axes, sizeof(AxisEffectInfo) * (numFFAxes));
|
||||
memset(b->axes + (numFFAxes - 1), 0, sizeof(AxisEffectInfo));
|
||||
bindingsExist = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Generally the case when not loading a binding file.
|
||||
if (!bindingsExist) {
|
||||
int i = numFFAxes - 1;
|
||||
ForceFeedbackAxis temp = ffAxes[i];
|
||||
while (i && temp.id < ffAxes[i - 1].id) {
|
||||
ffAxes[i] = ffAxes[i - 1];
|
||||
i--;
|
||||
}
|
||||
ffAxes[i] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
void Device::AllocState()
|
||||
{
|
||||
FreeState();
|
||||
virtualControlState = (int *)calloc(numVirtualControls + numVirtualControls + numPhysicalControls, sizeof(int));
|
||||
oldVirtualControlState = virtualControlState + numVirtualControls;
|
||||
physicalControlState = oldVirtualControlState + numVirtualControls;
|
||||
}
|
||||
|
||||
void Device::FlipState()
|
||||
{
|
||||
memcpy(oldVirtualControlState, virtualControlState, sizeof(int) * numVirtualControls);
|
||||
}
|
||||
|
||||
void Device::PostRead()
|
||||
{
|
||||
FlipState();
|
||||
}
|
||||
|
||||
void Device::CalcVirtualState()
|
||||
{
|
||||
for (int i = 0; i < numPhysicalControls; i++) {
|
||||
PhysicalControl *c = physicalControls + i;
|
||||
int index = c->baseVirtualControlIndex;
|
||||
int val = physicalControlState[i];
|
||||
if (c->type & BUTTON) {
|
||||
virtualControlState[index] = val;
|
||||
// DirectInput keyboard events only.
|
||||
if (this->api == DI && this->type == KEYBOARD) {
|
||||
if (!(virtualControlState[index] >> 15) != !(oldVirtualControlState[index] >> 15) && c->vkey) {
|
||||
// Check for alt-F4 to avoid toggling skip mode incorrectly.
|
||||
if (c->vkey == VK_F4) {
|
||||
int i;
|
||||
for (i = 0; i < numPhysicalControls; i++) {
|
||||
if (virtualControlState[physicalControls[i].baseVirtualControlIndex] &&
|
||||
(physicalControls[i].vkey == VK_MENU ||
|
||||
physicalControls[i].vkey == VK_RMENU ||
|
||||
physicalControls[i].vkey == VK_LMENU)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i < numPhysicalControls)
|
||||
continue;
|
||||
}
|
||||
int event = KEYPRESS;
|
||||
if (!(virtualControlState[index] >> 15))
|
||||
event = KEYRELEASE;
|
||||
QueueKeyEvent(c->vkey, event);
|
||||
}
|
||||
}
|
||||
} else if (c->type & ABSAXIS) {
|
||||
virtualControlState[index] = (val + FULLY_DOWN) / 2;
|
||||
// Positive. Overkill.
|
||||
virtualControlState[index + 1] = (val & ~(val >> 31));
|
||||
// Negative
|
||||
virtualControlState[index + 2] = (-val & (val >> 31));
|
||||
} else if (c->type & RELAXIS) {
|
||||
int delta = val - oldVirtualControlState[index];
|
||||
virtualControlState[index] = val;
|
||||
// Positive
|
||||
virtualControlState[index + 1] = (delta & ~(delta >> 31));
|
||||
// Negative
|
||||
virtualControlState[index + 2] = (-delta & (delta >> 31));
|
||||
} else if (c->type & POV) {
|
||||
virtualControlState[index] = val;
|
||||
int iSouth = 0;
|
||||
int iEast = 0;
|
||||
if ((unsigned int)val <= 37000) {
|
||||
double angle = val * (3.141592653589793 / 18000.0);
|
||||
double East = sin(angle);
|
||||
double South = -cos(angle);
|
||||
// Normalize so greatest direction is 1.
|
||||
double mul = FULLY_DOWN / std::max(fabs(South), fabs(East));
|
||||
|
||||
iEast = (int)floor(East * mul + 0.5);
|
||||
iSouth = (int)floor(South * mul + 0.5);
|
||||
}
|
||||
// N
|
||||
virtualControlState[index + 1] = (-iSouth & (iSouth >> 31));
|
||||
// S
|
||||
virtualControlState[index + 3] = (iSouth & ~(iSouth >> 31));
|
||||
// E
|
||||
virtualControlState[index + 2] = (iEast & ~(iEast >> 31));
|
||||
// W
|
||||
virtualControlState[index + 4] = (-iEast & (iEast >> 31));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VirtualControl *Device::GetVirtualControl(unsigned int uid)
|
||||
{
|
||||
for (int i = 0; i < numVirtualControls; i++) {
|
||||
if (virtualControls[i].uid == uid)
|
||||
return virtualControls + i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
VirtualControl *Device::AddVirtualControl(unsigned int uid, int physicalControlIndex)
|
||||
{
|
||||
// Not really necessary, as always call AllocState when activated, but doesn't hurt.
|
||||
FreeState();
|
||||
|
||||
if (numVirtualControls % 16 == 0) {
|
||||
virtualControls = (VirtualControl *)realloc(virtualControls, sizeof(VirtualControl) * (numVirtualControls + 16));
|
||||
}
|
||||
VirtualControl *c = virtualControls + numVirtualControls;
|
||||
|
||||
c->uid = uid;
|
||||
c->physicalControlIndex = physicalControlIndex;
|
||||
|
||||
numVirtualControls++;
|
||||
return c;
|
||||
}
|
||||
|
||||
PhysicalControl *Device::AddPhysicalControl(ControlType type, unsigned short id, unsigned short vkey, const wchar_t *name)
|
||||
{
|
||||
// Not really necessary, as always call AllocState when activated, but doesn't hurt.
|
||||
FreeState();
|
||||
|
||||
if (numPhysicalControls % 16 == 0) {
|
||||
physicalControls = (PhysicalControl *)realloc(physicalControls, sizeof(PhysicalControl) * (numPhysicalControls + 16));
|
||||
}
|
||||
PhysicalControl *control = physicalControls + numPhysicalControls;
|
||||
|
||||
memset(control, 0, sizeof(PhysicalControl));
|
||||
control->type = type;
|
||||
control->id = id;
|
||||
if (name)
|
||||
control->name = wcsdup(name);
|
||||
control->baseVirtualControlIndex = numVirtualControls;
|
||||
unsigned int uid = id | (type << 16);
|
||||
if (type & BUTTON) {
|
||||
AddVirtualControl(uid, numPhysicalControls);
|
||||
control->vkey = vkey;
|
||||
} else if (type & AXIS) {
|
||||
AddVirtualControl(uid | UID_AXIS, numPhysicalControls);
|
||||
AddVirtualControl(uid | UID_AXIS_POS, numPhysicalControls);
|
||||
AddVirtualControl(uid | UID_AXIS_NEG, numPhysicalControls);
|
||||
} else if (type & POV) {
|
||||
AddVirtualControl(uid | UID_POV, numPhysicalControls);
|
||||
AddVirtualControl(uid | UID_POV_N, numPhysicalControls);
|
||||
AddVirtualControl(uid | UID_POV_E, numPhysicalControls);
|
||||
AddVirtualControl(uid | UID_POV_S, numPhysicalControls);
|
||||
AddVirtualControl(uid | UID_POV_W, numPhysicalControls);
|
||||
}
|
||||
numPhysicalControls++;
|
||||
return control;
|
||||
}
|
||||
|
||||
void Device::SetEffects(unsigned char port, unsigned int slot, unsigned char motor, unsigned char force)
|
||||
{
|
||||
int padtype = config.padConfigs[port][slot].type;
|
||||
for (int i = 0; i < pads[port][slot][padtype].numFFBindings; i++) {
|
||||
ForceFeedbackBinding *binding = pads[port][slot][padtype].ffBindings + i;
|
||||
if (binding->motor == motor) {
|
||||
SetEffect(binding, force);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wchar_t *GetDefaultControlName(unsigned short id, int type)
|
||||
{
|
||||
static wchar_t name[20];
|
||||
if (type & BUTTON) {
|
||||
wsprintfW(name, L"Button %i", id);
|
||||
} else if (type & AXIS) {
|
||||
wsprintfW(name, L"Axis %i", id);
|
||||
} else if (type & POV) {
|
||||
wsprintfW(name, L"POV %i", id);
|
||||
} else {
|
||||
wcscpy(name, L"Unknown");
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
wchar_t *Device::GetVirtualControlName(VirtualControl *control)
|
||||
{
|
||||
static wchar_t temp[100];
|
||||
wchar_t *baseName = 0;
|
||||
if (control->physicalControlIndex >= 0) {
|
||||
baseName = physicalControls[control->physicalControlIndex].name;
|
||||
if (!baseName)
|
||||
baseName = GetPhysicalControlName(&physicalControls[control->physicalControlIndex]);
|
||||
}
|
||||
unsigned int uid = control->uid;
|
||||
if (!baseName) {
|
||||
baseName = GetDefaultControlName(uid & 0xFFFF, (uid >> 16) & 0x1F);
|
||||
}
|
||||
uid &= 0xFF000000;
|
||||
int len = (int)wcslen(baseName);
|
||||
if (len > 99)
|
||||
len = 99;
|
||||
memcpy(temp, baseName, len * sizeof(wchar_t));
|
||||
temp[len] = 0;
|
||||
if (uid) {
|
||||
if (len > 95)
|
||||
len = 95;
|
||||
wchar_t *out = temp + len;
|
||||
if (uid == UID_AXIS_POS) {
|
||||
wcscpy(out, L" +");
|
||||
} else if (uid == UID_AXIS_NEG) {
|
||||
wcscpy(out, L" -");
|
||||
} else if (uid == UID_POV_N) {
|
||||
wcscpy(out, L" N");
|
||||
} else if (uid == UID_POV_E) {
|
||||
wcscpy(out, L" E");
|
||||
} else if (uid == UID_POV_S) {
|
||||
wcscpy(out, L" S");
|
||||
} else if (uid == UID_POV_W) {
|
||||
wcscpy(out, L" W");
|
||||
}
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
wchar_t *Device::GetPhysicalControlName(PhysicalControl *control)
|
||||
{
|
||||
if (control->name)
|
||||
return control->name;
|
||||
return GetDefaultControlName(control->id, control->type);
|
||||
}
|
||||
|
||||
void InputDeviceManager::AddDevice(Device *d)
|
||||
{
|
||||
devices = (Device **)realloc(devices, sizeof(Device *) * (numDevices + 1));
|
||||
devices[numDevices++] = d;
|
||||
}
|
||||
|
||||
void InputDeviceManager::Update(InitInfo *info)
|
||||
{
|
||||
for (int i = 0; i < numDevices; i++) {
|
||||
if (devices[i]->enabled) {
|
||||
if (!devices[i]->active) {
|
||||
if (!devices[i]->Activate(info) || !devices[i]->Update())
|
||||
continue;
|
||||
devices[i]->CalcVirtualState();
|
||||
devices[i]->PostRead();
|
||||
}
|
||||
if (devices[i]->Update())
|
||||
devices[i]->CalcVirtualState();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InputDeviceManager::PostRead()
|
||||
{
|
||||
for (int i = 0; i < numDevices; i++) {
|
||||
if (devices[i]->active)
|
||||
devices[i]->PostRead();
|
||||
}
|
||||
}
|
||||
|
||||
Device *InputDeviceManager::GetActiveDevice(InitInfo *info, unsigned int *uid, int *index, int *value)
|
||||
{
|
||||
int i, j;
|
||||
Update(info);
|
||||
int bestDiff = FULLY_DOWN / 2;
|
||||
Device *bestDevice = 0;
|
||||
for (i = 0; i < numDevices; i++) {
|
||||
if (devices[i]->active) {
|
||||
for (j = 0; j < devices[i]->numVirtualControls; j++) {
|
||||
if (devices[i]->virtualControlState[j] == devices[i]->oldVirtualControlState[j])
|
||||
continue;
|
||||
if (devices[i]->virtualControls[j].uid & UID_POV)
|
||||
continue;
|
||||
// Fix for releasing button used to click on bind button
|
||||
if (!((devices[i]->virtualControls[j].uid >> 16) & (POV | RELAXIS | ABSAXIS))) {
|
||||
if (abs(devices[i]->oldVirtualControlState[j]) > abs(devices[i]->virtualControlState[j])) {
|
||||
devices[i]->oldVirtualControlState[j] = 0;
|
||||
}
|
||||
}
|
||||
int diff = abs(devices[i]->virtualControlState[j] - devices[i]->oldVirtualControlState[j]);
|
||||
// Make it require a bit more work to bind relative axes.
|
||||
if (((devices[i]->virtualControls[j].uid >> 16) & 0xFF) == RELAXIS) {
|
||||
diff = diff / 4 + 1;
|
||||
}
|
||||
// Less pressure needed to bind DS3/SCP buttons.
|
||||
if ((devices[i]->api == DS3 || devices[i]->api == XINPUT) && (((devices[i]->virtualControls[j].uid >> 16) & 0xFF) & BUTTON)) {
|
||||
diff *= 4;
|
||||
}
|
||||
if (diff > bestDiff) {
|
||||
if (devices[i]->virtualControls[j].uid & UID_AXIS) {
|
||||
if ((((devices[i]->virtualControls[j].uid >> 16) & 0xFF) != ABSAXIS))
|
||||
continue;
|
||||
// Very picky when binding entire axes. Prefer binding half-axes.
|
||||
if (!((devices[i]->oldVirtualControlState[j] < FULLY_DOWN / 32 && devices[i]->virtualControlState[j] > FULLY_DOWN / 8) ||
|
||||
(devices[i]->oldVirtualControlState[j] > 31 * FULLY_DOWN / 32 && devices[i]->virtualControlState[j] < 7 * FULLY_DOWN / 8))) {
|
||||
continue;
|
||||
}
|
||||
} else if ((((devices[i]->virtualControls[j].uid >> 16) & 0xFF) == ABSAXIS)) {
|
||||
if (devices[i]->oldVirtualControlState[j] > 15 * FULLY_DOWN / 16)
|
||||
continue;
|
||||
}
|
||||
bestDiff = diff;
|
||||
*uid = devices[i]->virtualControls[j].uid;
|
||||
*index = j;
|
||||
bestDevice = devices[i];
|
||||
if (value) {
|
||||
if ((devices[i]->virtualControls[j].uid >> 16) & RELAXIS) {
|
||||
*value = devices[i]->virtualControlState[j] - devices[i]->oldVirtualControlState[j];
|
||||
} else {
|
||||
*value = devices[i]->virtualControlState[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Don't call when binding.
|
||||
// PostRead();
|
||||
return bestDevice;
|
||||
}
|
||||
|
||||
void InputDeviceManager::ReleaseInput()
|
||||
{
|
||||
for (int i = 0; i < numDevices; i++) {
|
||||
if (devices[i]->active)
|
||||
devices[i]->Deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
void InputDeviceManager::EnableDevices(DeviceType type, DeviceAPI api)
|
||||
{
|
||||
for (int i = 0; i < numDevices; i++) {
|
||||
if (devices[i]->api == api && devices[i]->type == type) {
|
||||
EnableDevice(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InputDeviceManager::DisableAllDevices()
|
||||
{
|
||||
for (int i = 0; i < numDevices; i++) {
|
||||
DisableDevice(i);
|
||||
}
|
||||
}
|
||||
|
||||
void InputDeviceManager::DisableDevice(int index)
|
||||
{
|
||||
devices[index]->enabled = 0;
|
||||
if (devices[index]->active) {
|
||||
devices[index]->Deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
ForceFeedbackEffectType *Device::GetForcefeedbackEffect(wchar_t *id)
|
||||
{
|
||||
for (int i = 0; i < numFFEffectTypes; i++) {
|
||||
if (!wcsicmp(id, ffEffectTypes[i].effectID)) {
|
||||
return &ffEffectTypes[i];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ForceFeedbackAxis *Device::GetForceFeedbackAxis(int id)
|
||||
{
|
||||
for (int i = 0; i < numFFAxes; i++) {
|
||||
if (ffAxes[i].id == id)
|
||||
return &ffAxes[i];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void InputDeviceManager::CopyBindings(int numOldDevices, Device **oldDevices)
|
||||
{
|
||||
int *oldMatches = (int *)malloc(sizeof(int) * numOldDevices);
|
||||
int *matches = (int *)malloc(sizeof(int) * numDevices);
|
||||
int i, j, port, slot;
|
||||
Device *old, *dev;
|
||||
for (i = 0; i < numDevices; i++) {
|
||||
matches[i] = -1;
|
||||
}
|
||||
for (i = 0; i < numOldDevices; i++) {
|
||||
oldMatches[i] = -2;
|
||||
old = oldDevices[i];
|
||||
for (port = 0; port < 2; port++) {
|
||||
for (slot = 0; slot < 4; slot++) {
|
||||
for (int padtype = 0; padtype < numPadTypes; padtype++) {
|
||||
if (old->pads[port][slot][padtype].numBindings + old->pads[port][slot][padtype].numFFBindings) {
|
||||
// Means that there are bindings.
|
||||
oldMatches[i] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Loops through ids looking for match, from most specific to most general.
|
||||
for (int id = 0; id < 3; id++) {
|
||||
for (i = 0; i < numOldDevices; i++) {
|
||||
if (oldMatches[i] >= 0)
|
||||
continue;
|
||||
for (j = 0; j < numDevices; j++) {
|
||||
if (matches[j] >= 0) {
|
||||
continue;
|
||||
}
|
||||
wchar_t *id1 = devices[j]->IDs[id];
|
||||
wchar_t *id2 = oldDevices[i]->IDs[id];
|
||||
if (!id1 || !id2) {
|
||||
continue;
|
||||
}
|
||||
if (!wcsicmp(id1, id2)) {
|
||||
matches[j] = i;
|
||||
oldMatches[i] = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < numOldDevices; i++) {
|
||||
if (oldMatches[i] == -2)
|
||||
continue;
|
||||
old = oldDevices[i];
|
||||
if (oldMatches[i] < 0) {
|
||||
dev = new Device(old->api, old->type, old->displayName, old->instanceID, old->productID);
|
||||
dev->attached = 0;
|
||||
AddDevice(dev);
|
||||
for (j = 0; j < old->numVirtualControls; j++) {
|
||||
VirtualControl *c = old->virtualControls + j;
|
||||
dev->AddVirtualControl(c->uid, -1);
|
||||
}
|
||||
for (j = 0; j < old->numFFEffectTypes; j++) {
|
||||
ForceFeedbackEffectType *effect = old->ffEffectTypes + j;
|
||||
dev->AddFFEffectType(effect->displayName, effect->effectID, effect->type);
|
||||
}
|
||||
for (j = 0; j < old->numFFAxes; j++) {
|
||||
ForceFeedbackAxis *axis = old->ffAxes + j;
|
||||
dev->AddFFAxis(axis->displayName, axis->id);
|
||||
}
|
||||
// Just steal the old bindings directly when there's no matching device.
|
||||
// Indices will be the same.
|
||||
memcpy(dev->pads, old->pads, sizeof(old->pads));
|
||||
memset(old->pads, 0, sizeof(old->pads));
|
||||
} else {
|
||||
dev = devices[oldMatches[i]];
|
||||
for (port = 0; port < 2; port++) {
|
||||
for (slot = 0; slot < 4; slot++) {
|
||||
for (int padtype = 0; padtype < numPadTypes; padtype++) {
|
||||
if (old->pads[port][slot][padtype].numBindings) {
|
||||
dev->pads[port][slot][padtype].bindings = (Binding *)malloc(old->pads[port][slot][padtype].numBindings * sizeof(Binding));
|
||||
for (int j = 0; j < old->pads[port][slot][padtype].numBindings; j++) {
|
||||
Binding *bo = old->pads[port][slot][padtype].bindings + j;
|
||||
Binding *bn = dev->pads[port][slot][padtype].bindings + dev->pads[port][slot][padtype].numBindings;
|
||||
VirtualControl *cn = dev->GetVirtualControl(old->virtualControls[bo->controlIndex].uid);
|
||||
if (cn) {
|
||||
*bn = *bo;
|
||||
bn->controlIndex = cn - dev->virtualControls;
|
||||
dev->pads[port][slot][padtype].numBindings++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (old->pads[port][slot][padtype].numFFBindings) {
|
||||
dev->pads[port][slot][padtype].ffBindings = (ForceFeedbackBinding *)malloc(old->pads[port][slot][padtype].numFFBindings * sizeof(ForceFeedbackBinding));
|
||||
for (int j = 0; j < old->pads[port][slot][padtype].numFFBindings; j++) {
|
||||
ForceFeedbackBinding *bo = old->pads[port][slot][padtype].ffBindings + j;
|
||||
ForceFeedbackBinding *bn = dev->pads[port][slot][padtype].ffBindings + dev->pads[port][slot][padtype].numFFBindings;
|
||||
ForceFeedbackEffectType *en = dev->GetForcefeedbackEffect(old->ffEffectTypes[bo->effectIndex].effectID);
|
||||
if (en) {
|
||||
*bn = *bo;
|
||||
bn->effectIndex = en - dev->ffEffectTypes;
|
||||
bn->axes = (AxisEffectInfo *)calloc(dev->numFFAxes, sizeof(AxisEffectInfo));
|
||||
for (int k = 0; k < old->numFFAxes; k++) {
|
||||
ForceFeedbackAxis *newAxis = dev->GetForceFeedbackAxis(old->ffAxes[k].id);
|
||||
if (newAxis) {
|
||||
bn->axes[newAxis - dev->ffAxes] = bo->axes[k];
|
||||
}
|
||||
}
|
||||
dev->pads[port][slot][padtype].numFFBindings++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
free(oldMatches);
|
||||
free(matches);
|
||||
}
|
||||
|
||||
void InputDeviceManager::SetEffect(unsigned char port, unsigned int slot, unsigned char motor, unsigned char force)
|
||||
{
|
||||
for (int i = 0; i < numDevices; i++) {
|
||||
Device *dev = devices[i];
|
||||
if (dev->enabled && dev->numFFEffectTypes) {
|
||||
dev->SetEffects(port, slot, motor, force);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,404 @@
|
|||
/* LilyPad - Pad plugin for PS2 Emulator
|
||||
* Copyright (C) 2002-2017 PCSX2 Dev Team/ChickenLiver
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Found- ation, either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* PCSX2 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 for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with PCSX2. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef INPUT_MANAGER_H
|
||||
#define INPUT_MANAGER_H
|
||||
|
||||
// Both of these are hard coded in a lot of places, so don't modify them.
|
||||
// Base sensitivity means that a sensitivity of that corresponds to a factor of 1.
|
||||
// Fully down means that value corresponds to a button being fully down (255).
|
||||
// a value of 128 or more corresponds to that button being pressed, for binary
|
||||
// values.
|
||||
#define BASE_SENSITIVITY (1 << 16)
|
||||
#define BASE_ANALOG_SENSITIVITY (87183)
|
||||
#define FULLY_DOWN (1 << 16)
|
||||
|
||||
#define DEFAULT_DEADZONE (BASE_SENSITIVITY * 201 / 1000)
|
||||
|
||||
/* Idea is for this file and the associated cpp file to be Windows independent.
|
||||
* Still more effort than it's worth to port to Linux, however.
|
||||
*/
|
||||
|
||||
enum PadType {
|
||||
DisabledPad,
|
||||
Dualshock2Pad,
|
||||
GuitarPad,
|
||||
PopnPad,
|
||||
MousePad,
|
||||
neGconPad,
|
||||
numPadTypes // total number of PadTypes. Add new PadType above this line.
|
||||
};
|
||||
|
||||
// Mostly match DirectInput8 values. Note that these are for physical controls.
|
||||
// One physical axis maps to 3 virtual ones, and one physical POV control maps to
|
||||
// 4 virtual ones.
|
||||
enum ControlType {
|
||||
NO_CONTROL = 0,
|
||||
// Axes are ints. Relative axes are for mice, mice wheels, etc,
|
||||
// and are always reported relative to their last value.
|
||||
// Absolute axes range from -65536 to 65536 and are absolute positions,
|
||||
// like for joysticks and pressure sensitive buttons.
|
||||
RELAXIS = 1,
|
||||
ABSAXIS = 2,
|
||||
|
||||
// Buttons range from 0 to 65536.
|
||||
PSHBTN = 4,
|
||||
TGLBTN = 8,
|
||||
|
||||
// POV controls are ints, values range from -1 to 36000.
|
||||
// -1 means not pressed, otherwise it's an angle.
|
||||
// For easy DirectInput compatibility, anything outside.
|
||||
// that range is treated as -1 (Though 36000-37000 is treated
|
||||
// like 0 to 1000, just in case).
|
||||
POV = 16,
|
||||
|
||||
// Pressure sensitive buttons. Only a different type because
|
||||
// they have configurable dead zones, unlike push or toggle buttons.
|
||||
PRESSURE_BTN = 32,
|
||||
};
|
||||
|
||||
// Masks to determine button type. Don't need one for POV.
|
||||
#define BUTTON (PSHBTN | TGLBTN | PRESSURE_BTN)
|
||||
#define BINARY_BUTTON (PSHBTN | TGLBTN)
|
||||
#define AXIS 3
|
||||
|
||||
struct Binding
|
||||
{
|
||||
int controlIndex;
|
||||
int command;
|
||||
int sensitivity;
|
||||
int deadZone;
|
||||
int skipDeadZone;
|
||||
unsigned char rapidFire;
|
||||
};
|
||||
|
||||
#define UID_AXIS (1U << 31)
|
||||
#define UID_POV (1 << 30)
|
||||
|
||||
#define UID_AXIS_POS (1U << 24)
|
||||
#define UID_AXIS_NEG (2U << 24)
|
||||
#define UID_POV_N (3 << 24)
|
||||
#define UID_POV_E (4 << 24)
|
||||
#define UID_POV_S (5 << 24)
|
||||
#define UID_POV_W (6 << 24)
|
||||
|
||||
// One of these exists for each bindable object.
|
||||
// Bindable objects consist of buttons, axis, pov controls,
|
||||
// and individual axis/pov directions. Not that pov controls
|
||||
// cannot actually be bound, but when trying to bind as an axis,
|
||||
// all directions are assigned individually.
|
||||
struct VirtualControl
|
||||
{
|
||||
// Unique id for control, given device. Based on source control's id,
|
||||
// source control type, axis/pov flags if it's a pov/axis (Rather than
|
||||
// a button or a pov/axis control's individual button), and an index,
|
||||
// if the control is split.
|
||||
unsigned int uid;
|
||||
// virtual key code. 0 if none.
|
||||
int physicalControlIndex;
|
||||
};
|
||||
|
||||
// Need one for each button, axis, and pov control.
|
||||
// API-specific code creates the PhysicalControls and
|
||||
// updates their state, standard function then populates
|
||||
// the VirtualControls and queues the keyboard messages, if
|
||||
// needed.
|
||||
struct PhysicalControl
|
||||
{
|
||||
// index of the first virtual control corresponding to this.
|
||||
// Buttons have 1 virtual control, axes 3, and povs 5, all
|
||||
// in a row.
|
||||
int baseVirtualControlIndex;
|
||||
ControlType type;
|
||||
// id. Must be unique for control type.
|
||||
// short so can be combined with other values to get
|
||||
// uid for virtual controls.
|
||||
unsigned short id;
|
||||
unsigned short vkey;
|
||||
wchar_t *name;
|
||||
};
|
||||
|
||||
enum DeviceAPI {
|
||||
NO_API = 0,
|
||||
DI = 1,
|
||||
WM = 2,
|
||||
RAW = 3,
|
||||
XINPUT = 4,
|
||||
DS3 = 5,
|
||||
// Not currently used.
|
||||
LLHOOK = 6,
|
||||
// Not a real API, obviously. Only used with keyboards,
|
||||
// to ignore individual buttons. Wrapper itself takes care
|
||||
// of ignoring bound keys. Otherwise, works normally.
|
||||
IGNORE_KEYBOARD = 7,
|
||||
// XXX
|
||||
LNX_KEYBOARD = 16,
|
||||
LNX_JOY = 17,
|
||||
};
|
||||
|
||||
enum DeviceType {
|
||||
NO_DEVICE = 0,
|
||||
KEYBOARD = 1,
|
||||
MOUSE = 2,
|
||||
OTHER = 3
|
||||
};
|
||||
|
||||
enum EffectType {
|
||||
EFFECT_CONSTANT,
|
||||
EFFECT_PERIODIC,
|
||||
EFFECT_RAMP
|
||||
};
|
||||
|
||||
// force range sfrom -BASE_SENSITIVITY to BASE_SENSITIVITY.
|
||||
// Order matches ForceFeedbackAxis order. force of 0 means to
|
||||
// ignore that axis completely. Force of 1 or -1 means to initialize
|
||||
// the axis with minimum force (Possibly 0 force), if applicable.
|
||||
struct AxisEffectInfo
|
||||
{
|
||||
int force;
|
||||
};
|
||||
|
||||
struct ForceFeedbackBinding
|
||||
{
|
||||
AxisEffectInfo *axes;
|
||||
int effectIndex;
|
||||
unsigned char motor;
|
||||
};
|
||||
|
||||
// Bindings listed by effect, so I don't have to bother with
|
||||
// indexing effects.
|
||||
struct ForceFeedbackEffectType
|
||||
{
|
||||
wchar_t *displayName;
|
||||
// Because I'm lazy, can only have ASCII characters and no spaces.
|
||||
wchar_t *effectID;
|
||||
// constant, ramp, or periodic
|
||||
EffectType type;
|
||||
};
|
||||
|
||||
|
||||
struct ForceFeedbackAxis
|
||||
{
|
||||
wchar_t *displayName;
|
||||
int id;
|
||||
};
|
||||
|
||||
// Used both for active devices and for sets of settings for devices.
|
||||
// Way things work:
|
||||
// LoadSettings() will delete all device info, then load settings to get
|
||||
// one set of generic devices. Then I enumerate all devices. Then I merge
|
||||
// them, moving settings from the generic devices to the enumerated ones.
|
||||
|
||||
struct PadBindings
|
||||
{
|
||||
Binding *bindings;
|
||||
int numBindings;
|
||||
ForceFeedbackBinding *ffBindings;
|
||||
int numFFBindings;
|
||||
};
|
||||
|
||||
class WndProcEater;
|
||||
|
||||
struct InitInfo
|
||||
{
|
||||
// 1 when binding key to ignore.
|
||||
int bindingIgnore;
|
||||
// 1 when binding.
|
||||
int binding;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
HWND hWndTop;
|
||||
|
||||
// For config screen, need to eat button's message handling.
|
||||
//HWND hWndButton;
|
||||
|
||||
WndProcEater *hWndProc;
|
||||
#else
|
||||
// Linux equivalent to HWND
|
||||
Display *GSdsp;
|
||||
Window GSwin;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
// Mostly self-contained, but bindings are modified by config.cpp, to make
|
||||
// updating the ListView simpler.
|
||||
class Device
|
||||
{
|
||||
public:
|
||||
DeviceAPI api;
|
||||
DeviceType type;
|
||||
char active;
|
||||
char attached;
|
||||
// Based on input modes.
|
||||
char enabled;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// Not all devices need to subclass the windproc, but most do so might as well
|
||||
// put it here... --air
|
||||
WndProcEater *hWndProc;
|
||||
#endif
|
||||
|
||||
union
|
||||
{
|
||||
// Allows for one loop to compare all 3 in order.
|
||||
wchar_t *IDs[3];
|
||||
struct
|
||||
{
|
||||
// Same as DisplayName, when not given. Absolutely must be unique.
|
||||
// Used for loading/saving controls. If matches, all other strings
|
||||
// are ignored, so must be unique.
|
||||
wchar_t *instanceID;
|
||||
// Not required. Used when a device's instance id changes, doesn't have to
|
||||
// be unique. For devices that can only have one instance, not needed.
|
||||
wchar_t *productID;
|
||||
|
||||
wchar_t *displayName;
|
||||
};
|
||||
};
|
||||
|
||||
PadBindings pads[2][4][numPadTypes];
|
||||
|
||||
// Virtual controls. All basically act like pressure sensitivity buttons, with
|
||||
// values between 0 and 2^16. 2^16 is fully down, 0 is up. Larger values
|
||||
// are allowed, but *only* for absolute axes (Which don't support the flip checkbox).
|
||||
// Each control on a device must have a unique id, used for binding.
|
||||
VirtualControl *virtualControls;
|
||||
int numVirtualControls;
|
||||
|
||||
int *virtualControlState;
|
||||
int *oldVirtualControlState;
|
||||
|
||||
PhysicalControl *physicalControls;
|
||||
int numPhysicalControls;
|
||||
int *physicalControlState;
|
||||
|
||||
ForceFeedbackEffectType *ffEffectTypes;
|
||||
int numFFEffectTypes;
|
||||
ForceFeedbackAxis *ffAxes;
|
||||
int numFFAxes;
|
||||
void AddFFAxis(const wchar_t *displayName, int id);
|
||||
void AddFFEffectType(const wchar_t *displayName, const wchar_t *effectID, EffectType type);
|
||||
|
||||
Device(DeviceAPI, DeviceType, const wchar_t *displayName, const wchar_t *instanceID = 0, const wchar_t *deviceID = 0);
|
||||
virtual ~Device();
|
||||
|
||||
// Allocates memory for old and new state, sets everything to 0.
|
||||
// all old states are in one array, buttons, axes, and then POVs.
|
||||
// start of each section is int aligned. This makes it DirectInput
|
||||
// compatible.
|
||||
void AllocState();
|
||||
|
||||
// Doesn't actually flip. Copies current state to old state.
|
||||
void FlipState();
|
||||
|
||||
// Frees state variables.
|
||||
void FreeState();
|
||||
|
||||
ForceFeedbackEffectType *GetForcefeedbackEffect(wchar_t *id);
|
||||
ForceFeedbackAxis *GetForceFeedbackAxis(int id);
|
||||
|
||||
VirtualControl *GetVirtualControl(unsigned int uid);
|
||||
|
||||
PhysicalControl *AddPhysicalControl(ControlType type, unsigned short id, unsigned short vkey, const wchar_t *name = 0);
|
||||
VirtualControl *AddVirtualControl(unsigned int uid, int physicalControlIndex);
|
||||
|
||||
virtual wchar_t *GetVirtualControlName(VirtualControl *c);
|
||||
virtual wchar_t *GetPhysicalControlName(PhysicalControl *c);
|
||||
|
||||
void CalcVirtualState();
|
||||
|
||||
virtual int Activate(InitInfo *args)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline virtual void Deactivate()
|
||||
{
|
||||
FreeState();
|
||||
active = 0;
|
||||
}
|
||||
|
||||
// Default update proc. All that's needed for post-based APIs.
|
||||
inline virtual int Update()
|
||||
{
|
||||
return active;
|
||||
}
|
||||
|
||||
// force is from -FULLY_DOWN to FULLY_DOWN.
|
||||
// Either function can be overridden. Second one by default calls the first
|
||||
// for every bound effect that's affected.
|
||||
|
||||
// Note: Only used externally for binding, so if override the other one, can assume
|
||||
// all other forces are currently 0.
|
||||
inline virtual void SetEffect(ForceFeedbackBinding *binding, unsigned char force) {}
|
||||
virtual void SetEffects(unsigned char port, unsigned int slot, unsigned char motor, unsigned char force);
|
||||
|
||||
// Called after reading. Basically calls FlipState().
|
||||
// Some device types (Those that don't incrementally update)
|
||||
// could call FlipState elsewhere, but this makes it simpler to ignore
|
||||
// while binding.
|
||||
virtual void PostRead();
|
||||
};
|
||||
|
||||
class InputDeviceManager
|
||||
{
|
||||
public:
|
||||
Device **devices;
|
||||
int numDevices;
|
||||
|
||||
void ClearDevices();
|
||||
|
||||
// When refreshing devices, back up old devices, then
|
||||
// populate this with new devices, then call copy bindings.
|
||||
// All old bindings are copied to matching devices.
|
||||
|
||||
// When old devices are missing, I do a slightly more careful search
|
||||
// using productIDs and then (in desperation) displayName.
|
||||
// Finally create new dummy devices if no matches found.
|
||||
void CopyBindings(int numDevices, Device **devices);
|
||||
|
||||
|
||||
InputDeviceManager();
|
||||
~InputDeviceManager();
|
||||
|
||||
void AddDevice(Device *d);
|
||||
Device *GetActiveDevice(InitInfo *info, unsigned int *uid, int *index, int *value);
|
||||
void Update(InitInfo *initInfo);
|
||||
|
||||
// Called after reading state, after Update().
|
||||
void PostRead();
|
||||
|
||||
void SetEffect(unsigned char port, unsigned int slot, unsigned char motor, unsigned char force);
|
||||
|
||||
// Update does this as needed.
|
||||
// void GetInput(void *v);
|
||||
void ReleaseInput();
|
||||
|
||||
void DisableDevice(int index);
|
||||
inline void EnableDevice(int i)
|
||||
{
|
||||
devices[i]->enabled = 1;
|
||||
}
|
||||
|
||||
void EnableDevices(DeviceType type, DeviceAPI api);
|
||||
void DisableAllDevices();
|
||||
};
|
||||
|
||||
extern InputDeviceManager *dm;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,101 @@
|
|||
/* LilyPad - Pad plugin for PS2 Emulator
|
||||
* Copyright (C) 2002-2014 PCSX2 Dev Team/ChickenLiver
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Found- ation, either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* PCSX2 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 for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with PCSX2. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Global.h"
|
||||
// This is undoubtedly completely unnecessary.
|
||||
#include "KeyboardQueue.h"
|
||||
|
||||
// What MS calls a single process Mutex. Faster, supposedly.
|
||||
// More importantly, can be abbreviated, amusingly, as cSection.
|
||||
#ifdef _MSC_VER
|
||||
static CRITICAL_SECTION cSection;
|
||||
static u8 csInitialized = 0;
|
||||
#else
|
||||
static std::mutex cSection;
|
||||
#endif
|
||||
|
||||
#define EVENT_QUEUE_LEN 16
|
||||
// Actually points one beyond the last queued event.
|
||||
static u8 lastQueuedEvent = 0;
|
||||
static u8 nextQueuedEvent = 0;
|
||||
static keyEvent queuedEvents[EVENT_QUEUE_LEN];
|
||||
|
||||
void QueueKeyEvent(int key, int event)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
if (!csInitialized) {
|
||||
csInitialized = 1;
|
||||
InitializeCriticalSection(&cSection);
|
||||
}
|
||||
EnterCriticalSection(&cSection);
|
||||
#else
|
||||
std::lock_guard<std::mutex> lock(cSection);
|
||||
#endif
|
||||
|
||||
// Don't queue events if escape is on top of queue. This is just for safety
|
||||
// purposes when a game is killing the emulator for whatever reason.
|
||||
if (nextQueuedEvent == lastQueuedEvent ||
|
||||
queuedEvents[nextQueuedEvent].key != VK_ESCAPE ||
|
||||
queuedEvents[nextQueuedEvent].evt != KEYPRESS) {
|
||||
// Clear queue on escape down, bringing escape to front. May do something
|
||||
// with shift/ctrl/alt and F-keys, later.
|
||||
if (event == KEYPRESS && key == VK_ESCAPE) {
|
||||
nextQueuedEvent = lastQueuedEvent;
|
||||
}
|
||||
|
||||
queuedEvents[lastQueuedEvent].key = key;
|
||||
queuedEvents[lastQueuedEvent].evt = event;
|
||||
|
||||
lastQueuedEvent = (lastQueuedEvent + 1) % EVENT_QUEUE_LEN;
|
||||
// If queue wrapped around, remove last element.
|
||||
if (nextQueuedEvent == lastQueuedEvent) {
|
||||
nextQueuedEvent = (nextQueuedEvent + 1) % EVENT_QUEUE_LEN;
|
||||
}
|
||||
}
|
||||
#ifdef _MSC_VER
|
||||
LeaveCriticalSection(&cSection);
|
||||
#endif
|
||||
}
|
||||
|
||||
int GetQueuedKeyEvent(keyEvent *event)
|
||||
{
|
||||
if (lastQueuedEvent == nextQueuedEvent)
|
||||
return 0;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
EnterCriticalSection(&cSection);
|
||||
#else
|
||||
std::lock_guard<std::mutex> lock(cSection);
|
||||
#endif
|
||||
*event = queuedEvents[nextQueuedEvent];
|
||||
nextQueuedEvent = (nextQueuedEvent + 1) % EVENT_QUEUE_LEN;
|
||||
#ifdef _MSC_VER
|
||||
LeaveCriticalSection(&cSection);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ClearKeyQueue()
|
||||
{
|
||||
lastQueuedEvent = nextQueuedEvent;
|
||||
#ifdef _MSC_VER
|
||||
if (csInitialized) {
|
||||
DeleteCriticalSection(&cSection);
|
||||
csInitialized = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/* LilyPad - Pad plugin for PS2 Emulator
|
||||
* Copyright (C) 2002-2014 PCSX2 Dev Team/ChickenLiver
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Found- ation, either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* PCSX2 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 for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with PCSX2. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
// This entire thing isn't really needed,
|
||||
// but takes little enough effort to be safe...
|
||||
|
||||
void QueueKeyEvent(int key, int event);
|
||||
int GetQueuedKeyEvent(keyEvent *event);
|
||||
|
||||
// Cleans up as well as clears queue.
|
||||
void ClearKeyQueue();
|
||||
|
||||
#ifdef __linux__
|
||||
void R_QueueKeyEvent(const keyEvent &event);
|
||||
int R_GetQueuedKeyEvent(keyEvent *event);
|
||||
void R_ClearKeyQueue();
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,604 @@
|
|||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include <winres.h>
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (United States) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
#pragma code_page(1252)
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include <winres.h>\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Dialog
|
||||
//
|
||||
|
||||
IDD_CONFIG DIALOGEX 0, 0, 424, 283
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION
|
||||
FONT 8, "MS Shell Dlg", 0, 0, 0x1
|
||||
BEGIN
|
||||
CONTROL "",IDC_BINDINGS_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | WS_BORDER | WS_VSCROLL | WS_TABSTOP,7,7,183,237,WS_EX_CLIENTEDGE
|
||||
// Input Bindings:
|
||||
PUSHBUTTON "Select",ID_SELECT,328,34,34,15
|
||||
PUSHBUTTON "Start",ID_START,366,34,34,15
|
||||
PUSHBUTTON "Analog",ID_ANALOG,328,51,34,15
|
||||
PUSHBUTTON "Mouse",ID_MOUSE,366,51,34,15
|
||||
GROUPBOX "Shoulder buttons",IDC_SHOULDER,196,24,108,46
|
||||
PUSHBUTTON "L1",ID_L1,210,34,34,15
|
||||
PUSHBUTTON "R1",ID_R1,254,34,34,15
|
||||
PUSHBUTTON "L2",ID_L2,210,51,34,15
|
||||
PUSHBUTTON "R2",ID_R2,254,51,34,15
|
||||
GROUPBOX "D-Pad",IDC_DPAD,196,70,108,70
|
||||
PUSHBUTTON "Up",ID_DPAD_UP,233,81,34,15
|
||||
PUSHBUTTON "Left",ID_DPAD_LEFT,214,100,34,15
|
||||
PUSHBUTTON "Right",ID_DPAD_RIGHT,252,100,34,15
|
||||
PUSHBUTTON "Down",ID_DPAD_DOWN,233,118,34,15
|
||||
GROUPBOX "Face buttons",IDC_FACE,310,70,108,70
|
||||
PUSHBUTTON "Triangle",ID_TRIANGLE,347,81,34,15
|
||||
PUSHBUTTON "Square",ID_SQUARE,328,100,34,15
|
||||
PUSHBUTTON "Circle",ID_CIRCLE,366,100,34,15
|
||||
PUSHBUTTON "Cross",ID_CROSS,347,119,34,15
|
||||
GROUPBOX "Left Analog Stick",IDC_LSTICK,196,141,108,70
|
||||
PUSHBUTTON "Up",ID_LSTICK_UP,234,152,30,15
|
||||
PUSHBUTTON "Left",ID_LSTICK_LEFT,202,171,30,15
|
||||
PUSHBUTTON "L3",ID_L3,234,171,30,15
|
||||
PUSHBUTTON "Right",ID_LSTICK_RIGHT,266,171,30,15
|
||||
PUSHBUTTON "Down",ID_LSTICK_DOWN,234,191,30,15
|
||||
GROUPBOX "Right Analog Stick",IDC_RSTICK,310,141,108,70
|
||||
PUSHBUTTON "Up",ID_RSTICK_UP,348,152,30,15
|
||||
PUSHBUTTON "Left",ID_RSTICK_LEFT,316,171,30,15
|
||||
PUSHBUTTON "R3",ID_R3,348,171,30,15
|
||||
PUSHBUTTON "Right",ID_RSTICK_RIGHT,380,171,30,15
|
||||
PUSHBUTTON "Down",ID_RSTICK_DOWN,348,191,30,15
|
||||
// Force Feedback bindings:
|
||||
GROUPBOX "Add Force Feedback Effect",ID_FORCEFEEDBACK_BOX,196,215,221,30
|
||||
COMBOBOX IDC_FORCEFEEDBACK,202,225,96,118,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
PUSHBUTTON "Big Motor",ID_BIG_MOTOR,304,224,50,14
|
||||
PUSHBUTTON "Small Motor",ID_SMALL_MOTOR,360,224,50,14
|
||||
// Input options:
|
||||
PUSHBUTTON "Quick Setup",ID_QUICK_SETUP,358,7,59,15
|
||||
CTEXT "",IDC_QUICK_SETUP_TEXT,196,7,156,15,WS_BORDER
|
||||
CONTROL "Configure on bind",IDC_CONFIGURE_ON_BIND,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,347,266,70,15
|
||||
PUSHBUTTON "Show Special Inputs",ID_SPECIAL_INPUTS,196,249,90,15
|
||||
COMBOBOX IDC_DEVICE_SELECT,304,250,113,70,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
// Special bindings:
|
||||
PUSHBUTTON "Lock Input",ID_LOCK_ALL_INPUT,7,249,58,15
|
||||
PUSHBUTTON "Lock Direction",ID_LOCK_DIRECTION,69,249,58,15
|
||||
PUSHBUTTON "Lock Buttons",ID_LOCK_BUTTONS,131,249,58,15
|
||||
PUSHBUTTON "Turbo",ID_TURBO_KEY,7,265,58,15
|
||||
PUSHBUTTON "Exclude Input",ID_EXCLUDE,131,265,58,15
|
||||
// Force Feedback & Input configurations:
|
||||
PUSHBUTTON "Back to Controls",ID_CONTROLS,196,260,59,15
|
||||
PUSHBUTTON "Reset Configuration",ID_RESET_CONFIG,259,260,72,15
|
||||
// Force Feedback configuration:
|
||||
GROUPBOX "",ID_FF,195,9,222,248
|
||||
COMBOBOX IDC_FF_EFFECT,203,23,206,106,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
CONTROL "",IDC_FF_AXIS1,"msctls_trackbar32",WS_TABSTOP,199,43,214,17
|
||||
CONTROL "Axis 1",IDC_FF_AXIS1_ENABLED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,205,63,91,10
|
||||
CONTROL "Flip",IDC_FF_AXIS1_FLIP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,302,63,35,10
|
||||
EDITTEXT IDC_FF_AXIS1_SCALE,375,63,33,12,ES_RIGHT | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_RTLREADING
|
||||
CONTROL "",IDC_FF_AXIS2,"msctls_trackbar32",WS_TABSTOP,199,79,214,17
|
||||
CONTROL "Axis 2",IDC_FF_AXIS2_ENABLED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,205,99,91,10
|
||||
CONTROL "Flip",IDC_FF_AXIS2_FLIP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,302,99,35,10
|
||||
EDITTEXT IDC_FF_AXIS2_SCALE,375,99,33,12,ES_RIGHT | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_RTLREADING
|
||||
CONTROL "",IDC_FF_AXIS3,"msctls_trackbar32",WS_TABSTOP,199,115,214,17
|
||||
CONTROL "Axis 3",IDC_FF_AXIS3_ENABLED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,205,135,91,10
|
||||
CONTROL "Flip",IDC_FF_AXIS3_FLIP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,302,135,35,10
|
||||
EDITTEXT IDC_FF_AXIS3_SCALE,375,135,33,12,ES_RIGHT | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_RTLREADING
|
||||
CONTROL "",IDC_FF_AXIS4,"msctls_trackbar32",WS_TABSTOP,199,151,214,17
|
||||
CONTROL "Axis 4",IDC_FF_AXIS4_ENABLED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,205,171,91,10
|
||||
CONTROL "Flip",IDC_FF_AXIS4_FLIP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,302,171,35,10
|
||||
EDITTEXT IDC_FF_AXIS4_SCALE,375,171,33,12,ES_RIGHT | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_RTLREADING
|
||||
CONTROL "",IDC_FF_AXIS5,"msctls_trackbar32",WS_TABSTOP,199,187,214,17
|
||||
CONTROL "Axis 5",IDC_FF_AXIS5_ENABLED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,205,207,91,10
|
||||
CONTROL "Flip",IDC_FF_AXIS5_FLIP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,302,207,35,10
|
||||
EDITTEXT IDC_FF_AXIS5_SCALE,375,207,33,12,ES_RIGHT | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_RTLREADING
|
||||
CONTROL "",IDC_FF_AXIS6,"msctls_trackbar32",WS_TABSTOP,199,223,214,17
|
||||
CONTROL "Axis 6",IDC_FF_AXIS6_ENABLED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,205,243,91,10
|
||||
CONTROL "Flip",IDC_FF_AXIS6_FLIP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,302,243,35,10
|
||||
EDITTEXT IDC_FF_AXIS6_SCALE,375,243,33,12,ES_RIGHT | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_RTLREADING
|
||||
PUSHBUTTON "Test",ID_TEST,335,260,59,15
|
||||
// Input configuration:
|
||||
GROUPBOX "Configure Binding",ID_SENSITIVITY,195,9,222,110
|
||||
EDITTEXT IDC_AXIS_DEVICE,202,22,72,12,ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP
|
||||
COMBOBOX IDC_AXIS_DIRECTION,276,20,70,47,CBS_DROPDOWNLIST | WS_TABSTOP
|
||||
EDITTEXT IDC_AXIS_CONTROL,349,22,65,12,ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP
|
||||
CONTROL "Flip",IDC_FLIP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,202,37,27,10
|
||||
CONTROL "Rapid Fire",IDC_RAPID_FIRE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,232,37,44,10
|
||||
LTEXT "Sensitivity",IDC_LABEL_SENSITIVITY,202,51,42,8
|
||||
CONTROL "",IDC_SLIDER_SENSITIVITY,"msctls_trackbar32",WS_TABSTOP,240,51,131,17
|
||||
EDITTEXT IDC_AXIS_SENSITIVITY,372,53,33,12,ES_RIGHT | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_RTLREADING
|
||||
LTEXT "Dead Zone",IDC_LABEL_DEADZONE,202,71,42,8
|
||||
CONTROL "",IDC_SLIDER_DEADZONE,"msctls_trackbar32",WS_TABSTOP,240,71,131,17
|
||||
EDITTEXT IDC_AXIS_DEADZONE,372,73,33,12,ES_RIGHT | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_RTLREADING
|
||||
LTEXT "Skip Dead Zone",IDC_LABEL_SKIP_DEADZONE,202,92,42,16
|
||||
CONTROL "",IDC_SLIDER_SKIP_DEADZONE,"msctls_trackbar32",WS_TABSTOP,240,92,131,17
|
||||
EDITTEXT IDC_AXIS_SKIP_DEADZONE,372,94,33,12,ES_RIGHT | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_RTLREADING
|
||||
LTEXT "Off",IDC_SKIP_DEADZONE_OFF,390,94,20,12
|
||||
END
|
||||
|
||||
IDD_CONFIG_POPN DIALOGEX 0, 0, 424, 283
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION
|
||||
FONT 8, "MS Shell Dlg", 0, 0, 0x1
|
||||
BEGIN
|
||||
CONTROL "",IDC_BINDINGS_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | WS_BORDER | WS_VSCROLL | WS_TABSTOP,7,7,183,237,WS_EX_CLIENTEDGE
|
||||
// Input Bindings:
|
||||
PUSHBUTTON "Select", ID_SELECT,262,25,43,15
|
||||
PUSHBUTTON "Start", ID_START,306,25,43,15
|
||||
PUSHBUTTON "White L",ID_TRIANGLE,196,69,43,15
|
||||
PUSHBUTTON "Yellow L",ID_CIRCLE,218,51,43,15
|
||||
PUSHBUTTON "Green L",ID_R1,240,69,43,15
|
||||
PUSHBUTTON "Blue L",ID_CROSS,262,51,43,15
|
||||
PUSHBUTTON "Red",ID_L1,284,69,43,15
|
||||
PUSHBUTTON "Blue R",ID_SQUARE,306,51,43,15
|
||||
PUSHBUTTON "Green R",ID_R2,328,69,43,15
|
||||
PUSHBUTTON "Yellow R",ID_DPAD_UP,350,51,43,15
|
||||
PUSHBUTTON "White R",ID_L2,372,69,43,15
|
||||
// Force Feedback bindings:
|
||||
GROUPBOX "Add Force Feedback Effect",ID_FORCEFEEDBACK_BOX,196,215,221,30
|
||||
COMBOBOX IDC_FORCEFEEDBACK,202,225,96,118,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
PUSHBUTTON "Big Motor",ID_BIG_MOTOR,304,224,50,14
|
||||
PUSHBUTTON "Small Motor",ID_SMALL_MOTOR,360,224,50,14
|
||||
// Input options:
|
||||
PUSHBUTTON "Quick Setup",ID_QUICK_SETUP,358,7,59,15
|
||||
CTEXT "",IDC_QUICK_SETUP_TEXT,196,7,156,15,WS_BORDER
|
||||
CONTROL "Configure on bind",IDC_CONFIGURE_ON_BIND,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,347,266,70,15
|
||||
PUSHBUTTON "Show Special Inputs",ID_SPECIAL_INPUTS,196,249,90,15
|
||||
COMBOBOX IDC_DEVICE_SELECT,304,250,113,70,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
// Special bindings:
|
||||
PUSHBUTTON "Lock Input",ID_LOCK_ALL_INPUT,7,249,58,15
|
||||
PUSHBUTTON "Lock Direction",ID_LOCK_DIRECTION,69,249,58,15
|
||||
PUSHBUTTON "Lock Buttons",ID_LOCK_BUTTONS,131,249,58,15
|
||||
PUSHBUTTON "Turbo",ID_TURBO_KEY,7,265,58,15
|
||||
PUSHBUTTON "Exclude Input",ID_EXCLUDE,131,265,58,15
|
||||
// Force Feedback & Input configurations:
|
||||
PUSHBUTTON "Back to Controls",ID_CONTROLS,196,260,59,15
|
||||
PUSHBUTTON "Reset Configuration",ID_RESET_CONFIG,259,260,72,15
|
||||
// Force Feedback configuration:
|
||||
GROUPBOX "",ID_FF,195,9,222,248
|
||||
COMBOBOX IDC_FF_EFFECT,203,23,206,106,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
CONTROL "",IDC_FF_AXIS1,"msctls_trackbar32",WS_TABSTOP,199,43,214,17
|
||||
CONTROL "Axis 1",IDC_FF_AXIS1_ENABLED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,205,63,91,10
|
||||
CONTROL "Flip",IDC_FF_AXIS1_FLIP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,302,63,35,10
|
||||
EDITTEXT IDC_FF_AXIS1_SCALE,375,63,33,12,ES_RIGHT | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_RTLREADING
|
||||
CONTROL "",IDC_FF_AXIS2,"msctls_trackbar32",WS_TABSTOP,199,79,214,17
|
||||
CONTROL "Axis 2",IDC_FF_AXIS2_ENABLED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,205,99,91,10
|
||||
CONTROL "Flip",IDC_FF_AXIS2_FLIP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,302,99,35,10
|
||||
EDITTEXT IDC_FF_AXIS2_SCALE,375,99,33,12,ES_RIGHT | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_RTLREADING
|
||||
CONTROL "",IDC_FF_AXIS3,"msctls_trackbar32",WS_TABSTOP,199,115,214,17
|
||||
CONTROL "Axis 3",IDC_FF_AXIS3_ENABLED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,205,135,91,10
|
||||
CONTROL "Flip",IDC_FF_AXIS3_FLIP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,302,135,35,10
|
||||
EDITTEXT IDC_FF_AXIS3_SCALE,375,135,33,12,ES_RIGHT | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_RTLREADING
|
||||
CONTROL "",IDC_FF_AXIS4,"msctls_trackbar32",WS_TABSTOP,199,151,214,17
|
||||
CONTROL "Axis 4",IDC_FF_AXIS4_ENABLED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,205,171,91,10
|
||||
CONTROL "Flip",IDC_FF_AXIS4_FLIP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,302,171,35,10
|
||||
EDITTEXT IDC_FF_AXIS4_SCALE,375,171,33,12,ES_RIGHT | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_RTLREADING
|
||||
CONTROL "",IDC_FF_AXIS5,"msctls_trackbar32",WS_TABSTOP,199,187,214,17
|
||||
CONTROL "Axis 5",IDC_FF_AXIS5_ENABLED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,205,207,91,10
|
||||
CONTROL "Flip",IDC_FF_AXIS5_FLIP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,302,207,35,10
|
||||
EDITTEXT IDC_FF_AXIS5_SCALE,375,207,33,12,ES_RIGHT | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_RTLREADING
|
||||
CONTROL "",IDC_FF_AXIS6,"msctls_trackbar32",WS_TABSTOP,199,223,214,17
|
||||
CONTROL "Axis 6",IDC_FF_AXIS6_ENABLED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,205,243,91,10
|
||||
CONTROL "Flip",IDC_FF_AXIS6_FLIP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,302,243,35,10
|
||||
EDITTEXT IDC_FF_AXIS6_SCALE,375,243,33,12,ES_RIGHT | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_RTLREADING
|
||||
PUSHBUTTON "Test",ID_TEST,335,260,59,15
|
||||
// Input configuration:
|
||||
GROUPBOX "Configure Binding",ID_SENSITIVITY,195,9,222,110
|
||||
EDITTEXT IDC_AXIS_DEVICE,202,22,72,12,ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP
|
||||
COMBOBOX IDC_AXIS_DIRECTION,276,20,70,47,CBS_DROPDOWNLIST | WS_TABSTOP
|
||||
EDITTEXT IDC_AXIS_CONTROL,349,22,65,12,ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP
|
||||
CONTROL "Flip",IDC_FLIP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,202,37,27,10
|
||||
CONTROL "Rapid Fire",IDC_RAPID_FIRE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,232,37,44,10
|
||||
LTEXT "Sensitivity",IDC_LABEL_SENSITIVITY,202,51,42,8
|
||||
CONTROL "",IDC_SLIDER_SENSITIVITY,"msctls_trackbar32",WS_TABSTOP,240,51,131,17
|
||||
EDITTEXT IDC_AXIS_SENSITIVITY,372,53,33,12,ES_RIGHT | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_RTLREADING
|
||||
LTEXT "Dead Zone",IDC_LABEL_DEADZONE,202,71,42,8
|
||||
CONTROL "",IDC_SLIDER_DEADZONE,"msctls_trackbar32",WS_TABSTOP,240,71,131,17
|
||||
EDITTEXT IDC_AXIS_DEADZONE,372,73,33,12,ES_RIGHT | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_RTLREADING
|
||||
LTEXT "Skip Dead Zone",IDC_LABEL_SKIP_DEADZONE,202,92,42,16
|
||||
CONTROL "",IDC_SLIDER_SKIP_DEADZONE,"msctls_trackbar32",WS_TABSTOP,240,92,131,17
|
||||
EDITTEXT IDC_AXIS_SKIP_DEADZONE,372,94,33,12,ES_RIGHT | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_RTLREADING
|
||||
LTEXT "Off",IDC_SKIP_DEADZONE_OFF,390,94,20,12
|
||||
END
|
||||
|
||||
IDD_CONFIG_GUITAR DIALOGEX 0, 0, 424, 283
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION
|
||||
FONT 8, "MS Shell Dlg", 0, 0, 0x1
|
||||
BEGIN
|
||||
CONTROL "",IDC_BINDINGS_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | WS_BORDER | WS_VSCROLL | WS_TABSTOP,7,7,183,237,WS_EX_CLIENTEDGE
|
||||
// Input Bindings:
|
||||
PUSHBUTTON "Fret 1",ID_R2,283,30,45,15
|
||||
PUSHBUTTON "Fret 2",ID_CIRCLE,283,53,45,15
|
||||
PUSHBUTTON "Fret 3",ID_TRIANGLE,283,76,45,15
|
||||
PUSHBUTTON "Fret 4",ID_CROSS,283,99,45,15
|
||||
PUSHBUTTON "Fret 5",ID_SQUARE,283,122,45,15
|
||||
PUSHBUTTON "Start",ID_START,256,145,45,15
|
||||
PUSHBUTTON "Select/Tilt",ID_SELECT,307,145,45,15
|
||||
PUSHBUTTON "Whammy Bar Up",ID_LSTICK_UP,219,168,69,15
|
||||
PUSHBUTTON "Whammy Bar Down",ID_LSTICK_DOWN,219,191,69,15
|
||||
PUSHBUTTON "Strum Bar Up",ID_DPAD_UP,336,168,58,15
|
||||
PUSHBUTTON "Strum Bar Down",ID_DPAD_DOWN,336,191,58,15
|
||||
// Force Feedback bindings:
|
||||
GROUPBOX "Add Force Feedback Effect",ID_FORCEFEEDBACK_BOX,196,215,221,30
|
||||
COMBOBOX IDC_FORCEFEEDBACK,202,225,96,118,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
PUSHBUTTON "Big Motor",ID_BIG_MOTOR,304,224,50,14
|
||||
PUSHBUTTON "Small Motor",ID_SMALL_MOTOR,360,224,50,14
|
||||
// Input options:
|
||||
PUSHBUTTON "Quick Setup",ID_QUICK_SETUP,358,7,59,15
|
||||
CTEXT "",IDC_QUICK_SETUP_TEXT,196,7,156,15,WS_BORDER
|
||||
CONTROL "Configure on bind",IDC_CONFIGURE_ON_BIND,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,347,266,70,15
|
||||
PUSHBUTTON "Show Special Inputs",ID_SPECIAL_INPUTS,196,249,90,15
|
||||
COMBOBOX IDC_DEVICE_SELECT,304,250,113,70,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
// Special bindings:
|
||||
PUSHBUTTON "Lock Input",ID_LOCK_ALL_INPUT,7,249,58,15
|
||||
PUSHBUTTON "Lock Direction",ID_LOCK_DIRECTION,69,249,58,15
|
||||
PUSHBUTTON "Lock Buttons",ID_LOCK_BUTTONS,131,249,58,15
|
||||
PUSHBUTTON "Turbo",ID_TURBO_KEY,7,265,58,15
|
||||
PUSHBUTTON "Exclude Input",ID_EXCLUDE,131,265,58,15
|
||||
// Force Feedback & Input configurations:
|
||||
PUSHBUTTON "Back to Controls",ID_CONTROLS,196,260,59,15
|
||||
PUSHBUTTON "Reset Configuration",ID_RESET_CONFIG,259,260,72,15
|
||||
// Force Feedback configuration:
|
||||
GROUPBOX "",ID_FF,195,9,222,248
|
||||
COMBOBOX IDC_FF_EFFECT,203,23,206,106,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
CONTROL "",IDC_FF_AXIS1,"msctls_trackbar32",WS_TABSTOP,199,43,214,17
|
||||
CONTROL "Axis 1",IDC_FF_AXIS1_ENABLED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,205,63,91,10
|
||||
CONTROL "Flip",IDC_FF_AXIS1_FLIP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,302,63,35,10
|
||||
EDITTEXT IDC_FF_AXIS1_SCALE,375,63,33,12,ES_RIGHT | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_RTLREADING
|
||||
CONTROL "",IDC_FF_AXIS2,"msctls_trackbar32",WS_TABSTOP,199,79,214,17
|
||||
CONTROL "Axis 2",IDC_FF_AXIS2_ENABLED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,205,99,91,10
|
||||
CONTROL "Flip",IDC_FF_AXIS2_FLIP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,302,99,35,10
|
||||
EDITTEXT IDC_FF_AXIS2_SCALE,375,99,33,12,ES_RIGHT | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_RTLREADING
|
||||
CONTROL "",IDC_FF_AXIS3,"msctls_trackbar32",WS_TABSTOP,199,115,214,17
|
||||
CONTROL "Axis 3",IDC_FF_AXIS3_ENABLED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,205,135,91,10
|
||||
CONTROL "Flip",IDC_FF_AXIS3_FLIP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,302,135,35,10
|
||||
EDITTEXT IDC_FF_AXIS3_SCALE,375,135,33,12,ES_RIGHT | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_RTLREADING
|
||||
CONTROL "",IDC_FF_AXIS4,"msctls_trackbar32",WS_TABSTOP,199,151,214,17
|
||||
CONTROL "Axis 4",IDC_FF_AXIS4_ENABLED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,205,171,91,10
|
||||
CONTROL "Flip",IDC_FF_AXIS4_FLIP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,302,171,35,10
|
||||
EDITTEXT IDC_FF_AXIS4_SCALE,375,171,33,12,ES_RIGHT | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_RTLREADING
|
||||
CONTROL "",IDC_FF_AXIS5,"msctls_trackbar32",WS_TABSTOP,199,187,214,17
|
||||
CONTROL "Axis 5",IDC_FF_AXIS5_ENABLED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,205,207,91,10
|
||||
CONTROL "Flip",IDC_FF_AXIS5_FLIP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,302,207,35,10
|
||||
EDITTEXT IDC_FF_AXIS5_SCALE,375,207,33,12,ES_RIGHT | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_RTLREADING
|
||||
CONTROL "",IDC_FF_AXIS6,"msctls_trackbar32",WS_TABSTOP,199,223,214,17
|
||||
CONTROL "Axis 6",IDC_FF_AXIS6_ENABLED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,205,243,91,10
|
||||
CONTROL "Flip",IDC_FF_AXIS6_FLIP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,302,243,35,10
|
||||
EDITTEXT IDC_FF_AXIS6_SCALE,375,243,33,12,ES_RIGHT | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_RTLREADING
|
||||
PUSHBUTTON "Test",ID_TEST,335,260,59,15
|
||||
// Input configuration:
|
||||
GROUPBOX "Configure Binding",ID_SENSITIVITY,195,9,222,110
|
||||
EDITTEXT IDC_AXIS_DEVICE,202,22,72,12,ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP
|
||||
COMBOBOX IDC_AXIS_DIRECTION,276,20,70,47,CBS_DROPDOWNLIST | WS_TABSTOP
|
||||
EDITTEXT IDC_AXIS_CONTROL,349,22,65,12,ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP
|
||||
CONTROL "Flip",IDC_FLIP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,202,37,27,10
|
||||
CONTROL "Rapid Fire",IDC_RAPID_FIRE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,232,37,44,10
|
||||
LTEXT "Sensitivity",IDC_LABEL_SENSITIVITY,202,51,42,8
|
||||
CONTROL "",IDC_SLIDER_SENSITIVITY,"msctls_trackbar32",WS_TABSTOP,240,51,131,17
|
||||
EDITTEXT IDC_AXIS_SENSITIVITY,372,53,33,12,ES_RIGHT | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_RTLREADING
|
||||
LTEXT "Dead Zone",IDC_LABEL_DEADZONE,202,71,42,8
|
||||
CONTROL "",IDC_SLIDER_DEADZONE,"msctls_trackbar32",WS_TABSTOP,240,71,131,17
|
||||
EDITTEXT IDC_AXIS_DEADZONE,372,73,33,12,ES_RIGHT | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_RTLREADING
|
||||
LTEXT "Skip Dead Zone",IDC_LABEL_SKIP_DEADZONE,202,92,42,16
|
||||
CONTROL "",IDC_SLIDER_SKIP_DEADZONE,"msctls_trackbar32",WS_TABSTOP,240,92,131,17
|
||||
EDITTEXT IDC_AXIS_SKIP_DEADZONE,372,94,33,12,ES_RIGHT | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_RTLREADING
|
||||
LTEXT "Off",IDC_SKIP_DEADZONE_OFF,390,94,20,12
|
||||
END
|
||||
|
||||
IDD_CONFIG_PS1_MOUSE DIALOGEX 0, 0, 424, 283
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION
|
||||
FONT 8, "MS Shell Dlg", 0, 0, 0x1
|
||||
BEGIN
|
||||
CONTROL "",IDC_BINDINGS_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | WS_BORDER | WS_VSCROLL | WS_TABSTOP,7,7,183,237,WS_EX_CLIENTEDGE
|
||||
// Input bindings:
|
||||
PUSHBUTTON "Mouse",ID_MOUSE,379,28,34,15
|
||||
GROUPBOX "Mouse buttons",IDC_FACE,242,46,124,34
|
||||
PUSHBUTTON "Left-click",ID_CIRCLE,256,57,45,15
|
||||
PUSHBUTTON "Right-click",ID_CROSS,307,57,45,15
|
||||
GROUPBOX "Mouse Axis",IDC_LSTICK,242,81,124,74
|
||||
PUSHBUTTON "X-axis Left",ID_LSTICK_LEFT,256,112,45,15
|
||||
PUSHBUTTON "X-axis Right",ID_LSTICK_RIGHT,307,112,45,15
|
||||
PUSHBUTTON "Y-axis Up",ID_LSTICK_UP,283,92,45,15
|
||||
PUSHBUTTON "Y-axis Down",ID_LSTICK_DOWN,283,132,45,15
|
||||
// Force Feedback bindings:
|
||||
GROUPBOX "Add Force Feedback Effect",ID_FORCEFEEDBACK_BOX,196,215,221,30
|
||||
COMBOBOX IDC_FORCEFEEDBACK,202,225,96,118,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
PUSHBUTTON "Big Motor",ID_BIG_MOTOR,304,224,50,14
|
||||
PUSHBUTTON "Small Motor",ID_SMALL_MOTOR,360,224,50,14
|
||||
// Input options:
|
||||
PUSHBUTTON "Quick Setup",ID_QUICK_SETUP,358,7,59,15
|
||||
CTEXT "",IDC_QUICK_SETUP_TEXT,196,7,156,15,WS_BORDER
|
||||
CONTROL "Configure on bind",IDC_CONFIGURE_ON_BIND,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,347,266,70,15
|
||||
PUSHBUTTON "Show Special Inputs",ID_SPECIAL_INPUTS,196,249,90,15
|
||||
COMBOBOX IDC_DEVICE_SELECT,304,250,113,70,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
// Special bindings:
|
||||
PUSHBUTTON "Lock Input",ID_LOCK_ALL_INPUT,7,249,58,15
|
||||
PUSHBUTTON "Lock Direction",ID_LOCK_DIRECTION,69,249,58,15
|
||||
PUSHBUTTON "Lock Buttons",ID_LOCK_BUTTONS,131,249,58,15
|
||||
PUSHBUTTON "Turbo",ID_TURBO_KEY,7,265,58,15
|
||||
PUSHBUTTON "Exclude Input",ID_EXCLUDE,131,265,58,15
|
||||
// Force Feedback & Input configurations:
|
||||
PUSHBUTTON "Back to Controls",ID_CONTROLS,196,260,59,15
|
||||
PUSHBUTTON "Reset Configuration",ID_RESET_CONFIG,259,260,72,15
|
||||
// Input configuration:
|
||||
GROUPBOX "Configure Binding",ID_SENSITIVITY,195,9,222,110
|
||||
EDITTEXT IDC_AXIS_DEVICE,202,22,72,12,ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP
|
||||
COMBOBOX IDC_AXIS_DIRECTION,276,20,70,47,CBS_DROPDOWNLIST | WS_TABSTOP
|
||||
EDITTEXT IDC_AXIS_CONTROL,349,22,65,12,ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP
|
||||
CONTROL "Flip",IDC_FLIP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,202,37,27,10
|
||||
CONTROL "Rapid Fire",IDC_RAPID_FIRE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,232,37,44,10
|
||||
LTEXT "Sensitivity",IDC_LABEL_SENSITIVITY,202,51,42,8
|
||||
CONTROL "",IDC_SLIDER_SENSITIVITY,"msctls_trackbar32",WS_TABSTOP,240,51,131,17
|
||||
EDITTEXT IDC_AXIS_SENSITIVITY,372,53,33,12,ES_RIGHT | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_RTLREADING
|
||||
LTEXT "Dead Zone",IDC_LABEL_DEADZONE,202,71,42,8
|
||||
CONTROL "",IDC_SLIDER_DEADZONE,"msctls_trackbar32",WS_TABSTOP,240,71,131,17
|
||||
EDITTEXT IDC_AXIS_DEADZONE,372,73,33,12,ES_RIGHT | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_RTLREADING
|
||||
LTEXT "Skip Dead Zone",IDC_LABEL_SKIP_DEADZONE,202,92,42,16
|
||||
CONTROL "",IDC_SLIDER_SKIP_DEADZONE,"msctls_trackbar32",WS_TABSTOP,240,92,131,17
|
||||
EDITTEXT IDC_AXIS_SKIP_DEADZONE,372,94,33,12,ES_RIGHT | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_RTLREADING
|
||||
LTEXT "Off",IDC_SKIP_DEADZONE_OFF,390,94,20,12
|
||||
END
|
||||
|
||||
IDD_CONFIG_NEGCON DIALOGEX 0, 0, 424, 283
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION
|
||||
FONT 8, "MS Shell Dlg", 0, 0, 0x1
|
||||
BEGIN
|
||||
CONTROL "",IDC_BINDINGS_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | WS_BORDER | WS_VSCROLL | WS_TABSTOP,7,7,183,237,WS_EX_CLIENTEDGE
|
||||
// Input bindings:
|
||||
GROUPBOX "Shoulder buttons",IDC_SHOULDER,220,30,173,34
|
||||
PUSHBUTTON "Analog L",ID_L1,233,41,34,15
|
||||
PUSHBUTTON "Digital R",ID_R1,346,41,34,15
|
||||
GROUPBOX "D-Pad",IDC_DPAD,196,65,108,70
|
||||
PUSHBUTTON "Up",ID_DPAD_UP,233,76,34,15
|
||||
PUSHBUTTON "Left",ID_DPAD_LEFT,214,95,34,15
|
||||
PUSHBUTTON "Right",ID_DPAD_RIGHT,252,95,34,15
|
||||
PUSHBUTTON "Down",ID_DPAD_DOWN,233,114,34,15
|
||||
GROUPBOX "Digital Face buttons",IDC_FACE,310,65,108,34
|
||||
PUSHBUTTON "B",ID_TRIANGLE,327,76,34,15
|
||||
PUSHBUTTON "A",ID_CIRCLE,367,76,34,15
|
||||
GROUPBOX "Analog Face buttons",IDC_FACE_ANALOG,310,101,108,34
|
||||
PUSHBUTTON "II",ID_SQUARE,327,112,34,15
|
||||
PUSHBUTTON "I",ID_CROSS,367,112,34,15
|
||||
GROUPBOX "Analog Rotating Section",IDC_LSTICK,247,136,124,34
|
||||
PUSHBUTTON "Left",ID_LSTICK_LEFT,261,147,30,15
|
||||
PUSHBUTTON "Right",ID_LSTICK_RIGHT,327,147,30,15
|
||||
PUSHBUTTON "Start",ID_START,207,139,34,15
|
||||
PUSHBUTTON "Mouse",ID_MOUSE,207,158,34,15
|
||||
// Force Feedback bindings:
|
||||
GROUPBOX "Add Force Feedback Effect",ID_FORCEFEEDBACK_BOX,196,215,221,30
|
||||
COMBOBOX IDC_FORCEFEEDBACK,202,225,96,118,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
PUSHBUTTON "Big Motor",ID_BIG_MOTOR,304,224,50,14
|
||||
PUSHBUTTON "Small Motor",ID_SMALL_MOTOR,360,224,50,14
|
||||
// Input options:
|
||||
PUSHBUTTON "Quick Setup",ID_QUICK_SETUP,358,7,59,15
|
||||
CTEXT "",IDC_QUICK_SETUP_TEXT,196,7,156,15,WS_BORDER
|
||||
CONTROL "Configure on bind",IDC_CONFIGURE_ON_BIND,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,347,266,70,15
|
||||
PUSHBUTTON "Show Special Inputs",ID_SPECIAL_INPUTS,196,249,90,15
|
||||
COMBOBOX IDC_DEVICE_SELECT,304,250,113,70,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
// Special bindings:
|
||||
PUSHBUTTON "Lock Input",ID_LOCK_ALL_INPUT,7,249,58,15
|
||||
PUSHBUTTON "Lock Direction",ID_LOCK_DIRECTION,69,249,58,15
|
||||
PUSHBUTTON "Lock Buttons",ID_LOCK_BUTTONS,131,249,58,15
|
||||
PUSHBUTTON "Turbo",ID_TURBO_KEY,7,265,58,15
|
||||
PUSHBUTTON "Exclude Input",ID_EXCLUDE,131,265,58,15
|
||||
// Force Feedback & Input configurations:
|
||||
PUSHBUTTON "Back to Controls",ID_CONTROLS,196,260,59,15
|
||||
PUSHBUTTON "Reset Configuration",ID_RESET_CONFIG,259,260,72,15
|
||||
// Input configuration:
|
||||
GROUPBOX "Configure Binding",ID_SENSITIVITY,195,9,222,110
|
||||
EDITTEXT IDC_AXIS_DEVICE,202,22,72,12,ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP
|
||||
COMBOBOX IDC_AXIS_DIRECTION,276,20,70,47,CBS_DROPDOWNLIST | WS_TABSTOP
|
||||
EDITTEXT IDC_AXIS_CONTROL,349,22,65,12,ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP
|
||||
CONTROL "Flip",IDC_FLIP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,202,37,27,10
|
||||
CONTROL "Rapid Fire",IDC_RAPID_FIRE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,232,37,44,10
|
||||
LTEXT "Sensitivity",IDC_LABEL_SENSITIVITY,202,51,42,8
|
||||
CONTROL "",IDC_SLIDER_SENSITIVITY,"msctls_trackbar32",WS_TABSTOP,240,51,131,17
|
||||
EDITTEXT IDC_AXIS_SENSITIVITY,372,53,33,12,ES_RIGHT | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_RTLREADING
|
||||
LTEXT "Dead Zone",IDC_LABEL_DEADZONE,202,71,42,8
|
||||
CONTROL "",IDC_SLIDER_DEADZONE,"msctls_trackbar32",WS_TABSTOP,240,71,131,17
|
||||
EDITTEXT IDC_AXIS_DEADZONE,372,73,33,12,ES_RIGHT | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_RTLREADING
|
||||
LTEXT "Skip Dead Zone",IDC_LABEL_SKIP_DEADZONE,202,92,42,16
|
||||
CONTROL "",IDC_SLIDER_SKIP_DEADZONE,"msctls_trackbar32",WS_TABSTOP,240,92,131,17
|
||||
EDITTEXT IDC_AXIS_SKIP_DEADZONE,372,94,33,12,ES_RIGHT | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_RTLREADING
|
||||
LTEXT "Off",IDC_SKIP_DEADZONE_OFF,390,94,20,12
|
||||
END
|
||||
|
||||
IDD_GENERAL DIALOGEX 0, 0, 424, 283
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION
|
||||
FONT 8, "MS Shell Dlg", 0, 0, 0x1
|
||||
BEGIN
|
||||
GROUPBOX "Input APIs",IDC_STATIC,7,6,410,133
|
||||
GROUPBOX "Keyboard API",IDC_STATIC,16,16,192,51
|
||||
CONTROL "Windows messaging (Recommended)",IDC_KB_WM,"Button",BS_AUTORADIOBUTTON | WS_GROUP,22,28,137,10
|
||||
CONTROL "Raw input",IDC_KB_RAW,"Button",BS_AUTORADIOBUTTON,22,40,112,10
|
||||
CONTROL "DirectInput",IDC_KB_DI,"Button",BS_AUTORADIOBUTTON,22,52,112,10
|
||||
GROUPBOX "Game Device APIs",IDC_STATIC,16,70,191,62
|
||||
CONTROL "DirectInput (Legacy)",IDC_G_DI,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,22,82,100,10
|
||||
CONTROL "XInput (Modern)",IDC_G_XI,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,22,94,100,10
|
||||
CONTROL "DualShock 3 native mode (Requires libusb)",IDC_G_DS3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,22,106,155,10
|
||||
CONTROL "Monitor when in background",IDC_BACKGROUND,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,22,118,107,10
|
||||
GROUPBOX "Mouse API",IDC_STATIC,216,16,192,85
|
||||
CONTROL "Windows messaging (Recommended)",IDC_M_WM,"Button",BS_AUTORADIOBUTTON | WS_GROUP,223,27,137,10
|
||||
CONTROL "Raw input",IDC_M_RAW,"Button",BS_AUTORADIOBUTTON,223,39,112,10
|
||||
CONTROL "DirectInput",IDC_M_DI,"Button",BS_AUTORADIOBUTTON,223,51,112,10
|
||||
CONTROL "Disable",IDC_M_DISABLE,"Button",BS_AUTORADIOBUTTON,223,63,39,10
|
||||
CONTROL "Start without mouse focus",IDC_MOUSE_UNFOCUS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,223,75,98,10
|
||||
CONTROL "Always hide cursor",IDC_FORCE_HIDE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,223,87,73,10
|
||||
GROUPBOX "Pads",IDC_STATIC,7,142,410,62
|
||||
CONTROL "Port 1 Multitap",IDC_MULTITAP1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,152,63,10
|
||||
CONTROL "Port 2 Multitap",IDC_MULTITAP2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,164,63,10
|
||||
CONTROL "Multiple bindings",IDC_MULTIPLE_BINDING, "Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,176,66,10
|
||||
CONTROL "",IDC_PAD_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_TABSTOP,81,151,183,48,WS_EX_CLIENTEDGE
|
||||
COMBOBOX IDC_PAD_TYPE,270,151,140,118,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
GROUPBOX "Device Diagnostics",IDC_STATIC,7,207,201,72
|
||||
CONTROL "",IDC_DIAG_LIST,"SysListView32",LVS_LIST | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | WS_BORDER | WS_VSCROLL | WS_TABSTOP,14,217,187,57,WS_EX_CLIENTEDGE
|
||||
GROUPBOX "Hacks and advanced features",IDC_STATIC,216,207,201,46
|
||||
CONTROL "Enable logging",IDC_DEBUG_FILE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,223,217,79,10
|
||||
CONTROL "Guitar Hero 2 Hack",IDC_GH2_HACK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,223,228,79,10
|
||||
PUSHBUTTON "Restore Defaults",ID_RESTORE_DEFAULTS,219,259,62,15
|
||||
PUSHBUTTON "Load Bindings",ID_LOAD,287,259,62,15
|
||||
PUSHBUTTON "Save Bindings",ID_SAVE,355,259,62,15
|
||||
END
|
||||
|
||||
IDD_ABOUT DIALOGEX 0, 0, 108, 66
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "About LilyPad"
|
||||
FONT 8, "MS Shell Dlg", 0, 0, 0x1
|
||||
BEGIN
|
||||
CTEXT "LilyPad plugin",IDC_VERSION,7,7,94,10
|
||||
ICON IDI_FROG,IDC_STATIC,42,20,21,20
|
||||
DEFPUSHBUTTON "OK",IDOK,28,45,50,14
|
||||
END
|
||||
|
||||
IDD_DIAG DIALOGEX 0, 0, 190, 178
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION " "
|
||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||
BEGIN
|
||||
CONTROL "",IDC_DIAG_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_NOSORTHEADER | WS_BORDER | WS_VSCROLL | WS_TABSTOP,7,7,176,164,WS_EX_CLIENTEDGE
|
||||
END
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DESIGNINFO
|
||||
//
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
GUIDELINES DESIGNINFO
|
||||
BEGIN
|
||||
IDD_CONFIG, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 7
|
||||
RIGHTMARGIN, 417
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 311
|
||||
END
|
||||
|
||||
IDD_CONFIG_POPN, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 7
|
||||
RIGHTMARGIN, 417
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 311
|
||||
END
|
||||
|
||||
IDD_CONFIG_GUITAR, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 7
|
||||
RIGHTMARGIN, 417
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 311
|
||||
END
|
||||
|
||||
IDD_CONFIG_PS1_MOUSE, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 7
|
||||
RIGHTMARGIN, 417
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 311
|
||||
END
|
||||
|
||||
IDD_CONFIG_NEGCON, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 7
|
||||
RIGHTMARGIN, 417
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 311
|
||||
END
|
||||
|
||||
IDD_GENERAL, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 7
|
||||
RIGHTMARGIN, 417
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 319
|
||||
END
|
||||
|
||||
IDD_ABOUT, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 7
|
||||
RIGHTMARGIN, 101
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 59
|
||||
END
|
||||
|
||||
IDD_DIAG, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 7
|
||||
RIGHTMARGIN, 183
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 171
|
||||
END
|
||||
END
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// RCDATA
|
||||
//
|
||||
|
||||
IDR_INI1 RCDATA "Default.ini"
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Icon
|
||||
//
|
||||
|
||||
// Icon with lowest ID value placed first to ensure application icon
|
||||
// remains consistent on all systems.
|
||||
IDI_FROG ICON "frog.ico"
|
||||
|
||||
#endif // English (United States) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
|
@ -0,0 +1,331 @@
|
|||
/* LilyPad - Pad plugin for PS2 Emulator
|
||||
* Copyright (C) 2002-2014 PCSX2 Dev Team/ChickenLiver
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Found- ation, either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* PCSX2 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 for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with PCSX2. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Global.h"
|
||||
#include "InputManager.h"
|
||||
#include "WindowsMessaging.h"
|
||||
#include "VKey.h"
|
||||
#include "DeviceEnumerator.h"
|
||||
#include "WndProcEater.h"
|
||||
#include "WindowsKeyboard.h"
|
||||
#include "WindowsMouse.h"
|
||||
|
||||
ExtraWndProcResult RawInputWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *output);
|
||||
|
||||
int GetRawKeyboards(HWND hWnd)
|
||||
{
|
||||
RAWINPUTDEVICE Rid;
|
||||
Rid.hwndTarget = hWnd;
|
||||
|
||||
Rid.dwFlags = 0;
|
||||
Rid.usUsagePage = 0x01;
|
||||
Rid.usUsage = 0x06;
|
||||
return RegisterRawInputDevices(&Rid, 1, sizeof(Rid));
|
||||
}
|
||||
|
||||
void ReleaseRawKeyboards()
|
||||
{
|
||||
RAWINPUTDEVICE Rid;
|
||||
Rid.hwndTarget = 0;
|
||||
|
||||
Rid.dwFlags = RIDEV_REMOVE;
|
||||
Rid.usUsagePage = 0x01;
|
||||
Rid.usUsage = 0x06;
|
||||
RegisterRawInputDevices(&Rid, 1, sizeof(Rid));
|
||||
}
|
||||
|
||||
int GetRawMice(HWND hWnd)
|
||||
{
|
||||
RAWINPUTDEVICE Rid;
|
||||
Rid.hwndTarget = hWnd;
|
||||
|
||||
Rid.dwFlags = RIDEV_NOLEGACY | RIDEV_CAPTUREMOUSE;
|
||||
Rid.usUsagePage = 0x01;
|
||||
Rid.usUsage = 0x02;
|
||||
return RegisterRawInputDevices(&Rid, 1, sizeof(Rid));
|
||||
}
|
||||
|
||||
void ReleaseRawMice()
|
||||
{
|
||||
RAWINPUTDEVICE Rid;
|
||||
Rid.hwndTarget = 0;
|
||||
|
||||
Rid.dwFlags = RIDEV_REMOVE;
|
||||
Rid.usUsagePage = 0x01;
|
||||
Rid.usUsage = 0x02;
|
||||
RegisterRawInputDevices(&Rid, 1, sizeof(Rid));
|
||||
}
|
||||
|
||||
// Count of active raw keyboard devices.
|
||||
// when it gets to 0, release them all.
|
||||
static int rawKeyboardActivatedCount = 0;
|
||||
// Same for mice.
|
||||
static int rawMouseActivatedCount = 0;
|
||||
|
||||
class RawInputKeyboard : public WindowsKeyboard
|
||||
{
|
||||
public:
|
||||
HANDLE hDevice;
|
||||
|
||||
RawInputKeyboard(HANDLE hDevice, wchar_t *name, wchar_t *instanceID = 0)
|
||||
: WindowsKeyboard(RAW, name, instanceID)
|
||||
{
|
||||
this->hDevice = hDevice;
|
||||
}
|
||||
|
||||
int Activate(InitInfo *initInfo)
|
||||
{
|
||||
Deactivate();
|
||||
|
||||
hWndProc = initInfo->hWndProc;
|
||||
|
||||
active = 1;
|
||||
if (!rawKeyboardActivatedCount++) {
|
||||
if (!rawMouseActivatedCount)
|
||||
hWndProc->Eat(RawInputWndProc, EATPROC_NO_UPDATE_WHILE_UPDATING_DEVICES);
|
||||
|
||||
if (!GetRawKeyboards(hWndProc->hWndEaten)) {
|
||||
Deactivate();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
InitState();
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Deactivate()
|
||||
{
|
||||
FreeState();
|
||||
if (active) {
|
||||
active = 0;
|
||||
rawKeyboardActivatedCount--;
|
||||
if (!rawKeyboardActivatedCount) {
|
||||
ReleaseRawKeyboards();
|
||||
if (!rawMouseActivatedCount)
|
||||
hWndProc->ReleaseExtraProc(RawInputWndProc);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class RawInputMouse : public WindowsMouse
|
||||
{
|
||||
public:
|
||||
HANDLE hDevice;
|
||||
|
||||
RawInputMouse(HANDLE hDevice, wchar_t *name, wchar_t *instanceID = 0, wchar_t *productID = 0)
|
||||
: WindowsMouse(RAW, 0, name, instanceID, productID)
|
||||
{
|
||||
this->hDevice = hDevice;
|
||||
}
|
||||
|
||||
int Activate(InitInfo *initInfo)
|
||||
{
|
||||
Deactivate();
|
||||
|
||||
hWndProc = initInfo->hWndProc;
|
||||
|
||||
active = 1;
|
||||
|
||||
// Have to be careful with order. At worst, one unmatched call to ReleaseRawMice on
|
||||
// EatWndProc fail. In all other cases, no unmatched initialization/cleanup
|
||||
// lines.
|
||||
if (!rawMouseActivatedCount++) {
|
||||
GetMouseCapture(hWndProc->hWndEaten);
|
||||
if (!rawKeyboardActivatedCount)
|
||||
hWndProc->Eat(RawInputWndProc, EATPROC_NO_UPDATE_WHILE_UPDATING_DEVICES);
|
||||
|
||||
if (!GetRawMice(hWndProc->hWndEaten)) {
|
||||
Deactivate();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
AllocState();
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Deactivate()
|
||||
{
|
||||
FreeState();
|
||||
if (active) {
|
||||
active = 0;
|
||||
rawMouseActivatedCount--;
|
||||
if (!rawMouseActivatedCount) {
|
||||
ReleaseRawMice();
|
||||
ReleaseMouseCapture();
|
||||
if (!rawKeyboardActivatedCount) {
|
||||
hWndProc->ReleaseExtraProc(RawInputWndProc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ExtraWndProcResult RawInputWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *output)
|
||||
{
|
||||
if (uMsg == WM_INPUT) {
|
||||
if (GET_RAWINPUT_CODE_WPARAM(wParam) == RIM_INPUT) {
|
||||
RAWINPUT in;
|
||||
unsigned int size = sizeof(RAWINPUT);
|
||||
if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, &in, &size, sizeof(RAWINPUTHEADER)) > 0) {
|
||||
for (int i = 0; i < dm->numDevices; i++) {
|
||||
Device *dev = dm->devices[i];
|
||||
if (dev->api != RAW || !dev->active)
|
||||
continue;
|
||||
if (in.header.dwType == RIM_TYPEKEYBOARD && dev->type == KEYBOARD) {
|
||||
RawInputKeyboard *rik = (RawInputKeyboard *)dev;
|
||||
if (rik->hDevice != in.header.hDevice)
|
||||
continue;
|
||||
|
||||
u32 uMsg = in.data.keyboard.Message;
|
||||
if (!(in.data.keyboard.VKey >> 8))
|
||||
rik->UpdateKey((u8)in.data.keyboard.VKey, (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN));
|
||||
} else if (in.header.dwType == RIM_TYPEMOUSE && dev->type == MOUSE) {
|
||||
RawInputMouse *rim = (RawInputMouse *)dev;
|
||||
if (rim->hDevice != in.header.hDevice)
|
||||
continue;
|
||||
if (in.data.mouse.usFlags) {
|
||||
// Never been set for me, and specs on what most of them
|
||||
// actually mean is sorely lacking. Also, specs erroneously
|
||||
// indicate MOUSE_MOVE_RELATIVE is a flag, when it's really
|
||||
// 0...
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned short buttons = in.data.mouse.usButtonFlags & 0x3FF;
|
||||
int button = 0;
|
||||
while (buttons) {
|
||||
if (buttons & 3) {
|
||||
// 2 is up, 1 is down. Up takes precedence over down.
|
||||
rim->UpdateButton(button, !(buttons & 2));
|
||||
}
|
||||
button++;
|
||||
buttons >>= 2;
|
||||
}
|
||||
if (in.data.mouse.usButtonFlags & RI_MOUSE_WHEEL) {
|
||||
rim->UpdateAxis(2, ((short)in.data.mouse.usButtonData) / WHEEL_DELTA);
|
||||
}
|
||||
if (in.data.mouse.lLastX || in.data.mouse.lLastY) {
|
||||
rim->UpdateAxis(0, in.data.mouse.lLastX);
|
||||
rim->UpdateAxis(1, in.data.mouse.lLastY);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (uMsg == WM_ACTIVATE) {
|
||||
for (int i = 0; i < dm->numDevices; i++) {
|
||||
Device *dev = dm->devices[i];
|
||||
if (dev->api != RAW || dev->physicalControlState == 0)
|
||||
continue;
|
||||
memset(dev->physicalControlState, 0, sizeof(int) * dev->numPhysicalControls);
|
||||
}
|
||||
} else if (uMsg == WM_SIZE && rawMouseActivatedCount) {
|
||||
// Doesn't really matter for raw mice, as I disable legacy stuff, but shouldn't hurt.
|
||||
WindowsMouse::WindowResized(hWnd);
|
||||
}
|
||||
|
||||
return CONTINUE_BLISSFULLY;
|
||||
}
|
||||
|
||||
void EnumRawInputDevices()
|
||||
{
|
||||
int count = 0;
|
||||
if (GetRawInputDeviceList(0, (unsigned int *)&count, sizeof(RAWINPUTDEVICELIST)) != (UINT)-1 && count > 0) {
|
||||
wchar_t *instanceID = (wchar_t *)malloc(41000 * sizeof(wchar_t));
|
||||
wchar_t *keyName = instanceID + 11000;
|
||||
wchar_t *displayName = keyName + 10000;
|
||||
wchar_t *productID = displayName + 10000;
|
||||
|
||||
RAWINPUTDEVICELIST *list = (RAWINPUTDEVICELIST *)malloc(sizeof(RAWINPUTDEVICELIST) * count);
|
||||
int keyboardCount = 1;
|
||||
int mouseCount = 1;
|
||||
count = GetRawInputDeviceList(list, (unsigned int *)&count, sizeof(RAWINPUTDEVICELIST));
|
||||
|
||||
// Not necessary, but reminder that count is -1 on failure.
|
||||
if (count > 0) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (list[i].dwType != RIM_TYPEKEYBOARD && list[i].dwType != RIM_TYPEMOUSE)
|
||||
continue;
|
||||
|
||||
UINT bufferLen = 10000;
|
||||
int nameLen = GetRawInputDeviceInfo(list[i].hDevice, RIDI_DEVICENAME, instanceID, &bufferLen);
|
||||
if (nameLen >= 4) {
|
||||
// nameLen includes terminating null.
|
||||
nameLen--;
|
||||
|
||||
// Strip out GUID parts of instanceID to make it a generic product id,
|
||||
// and reformat it to point to registry entry containing device description.
|
||||
wcscpy(productID, instanceID);
|
||||
wchar_t *temp = 0;
|
||||
for (int j = 0; j < 3; j++) {
|
||||
wchar_t *s = wcschr(productID, '#');
|
||||
if (!s)
|
||||
break;
|
||||
*s = '\\';
|
||||
if (j == 2) {
|
||||
*s = 0;
|
||||
}
|
||||
if (j == 1)
|
||||
temp = s;
|
||||
}
|
||||
|
||||
wsprintfW(keyName, L"SYSTEM\\CurrentControlSet\\Enum%s", productID + 3);
|
||||
if (temp)
|
||||
*temp = 0;
|
||||
int haveDescription = 0;
|
||||
HKEY hKey;
|
||||
if (ERROR_SUCCESS == RegOpenKeyExW(HKEY_LOCAL_MACHINE, keyName, 0, KEY_QUERY_VALUE, &hKey)) {
|
||||
DWORD type;
|
||||
DWORD len = 10000 * sizeof(wchar_t);
|
||||
if (ERROR_SUCCESS == RegQueryValueExW(hKey, L"DeviceDesc", 0, &type, (BYTE *)displayName, &len) &&
|
||||
len && type == REG_SZ) {
|
||||
wchar_t *temp2 = wcsrchr(displayName, ';');
|
||||
if (!temp2)
|
||||
temp2 = displayName;
|
||||
else
|
||||
temp2++;
|
||||
// Could do without this, but more effort than it's worth.
|
||||
wcscpy(keyName, temp2);
|
||||
haveDescription = 1;
|
||||
}
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
if (list[i].dwType == RIM_TYPEKEYBOARD) {
|
||||
if (!haveDescription)
|
||||
wsprintfW(displayName, L"Raw Keyboard %i", keyboardCount++);
|
||||
else
|
||||
wsprintfW(displayName, L"Raw KB: %s", keyName);
|
||||
dm->AddDevice(new RawInputKeyboard(list[i].hDevice, displayName, instanceID));
|
||||
} else if (list[i].dwType == RIM_TYPEMOUSE) {
|
||||
if (!haveDescription)
|
||||
wsprintfW(displayName, L"Raw Mouse %i", mouseCount++);
|
||||
else
|
||||
wsprintfW(displayName, L"Raw MS: %s", keyName);
|
||||
dm->AddDevice(new RawInputMouse(list[i].hDevice, displayName, instanceID, productID));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
free(list);
|
||||
free(instanceID);
|
||||
dm->AddDevice(new RawInputKeyboard(0, L"Simulated Keyboard"));
|
||||
dm->AddDevice(new RawInputMouse(0, L"Simulated Mouse"));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/* LilyPad - Pad plugin for PS2 Emulator
|
||||
* Copyright (C) 2002-2014 PCSX2 Dev Team/ChickenLiver
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Found- ation, either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* PCSX2 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 for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with PCSX2. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Can't enumerate raw devices, can only detect them when
|
||||
// receiving data from them, so just use the list from before.
|
||||
void EnumRawInputDevices();
|
|
@ -0,0 +1,129 @@
|
|||
/* LilyPad - Pad plugin for PS2 Emulator
|
||||
* Copyright (C) 2016-2017 PCSX2 Dev Team/ChickenLiver
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Found- ation, either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* PCSX2 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 for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with PCSX2. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Global.h"
|
||||
#include "resource.h"
|
||||
|
||||
LPWSTR dialog_message(int ID, bool *updateText)
|
||||
{
|
||||
if (updateText)
|
||||
*updateText = true;
|
||||
switch (ID) {
|
||||
// General tab
|
||||
case IDC_M_WM:
|
||||
case IDC_M_RAW:
|
||||
case IDC_M_DI:
|
||||
return L"Enables mouse inputs to be used as pad controls.\n\n"
|
||||
L"The mouse needs to be in focus to be used for playing. By default this is not the case as the \"Start without mouse focus\" checkbox is enabled. "
|
||||
L"Either disable this checkbox or enable/disable the mouse while playing by assigning a key to the \"Mouse\" button on the Pad tabs.\n\n"
|
||||
L"Note 1: By default PCSX2 uses a double-click by the left mouse button to toggle fullscreen mode, this makes the left mouse button unusable as an input."
|
||||
L"To disable this option in PCSX2 go to Config > Emulation Settings > GS Window tab, and disable the \"Double-click toggles fullscreen mode\" checkbox.\n\n"
|
||||
L"Note 2: This does not enable the mouse to function as an in-game mouse in PS2 games that support a USB mouse or lightgun."
|
||||
L"This requires a USB plugin, while LilyPad is a PAD plugin(PAD means it emulates devices that are to be plugged into the PlayStation controller port that connects the DualShock 2 controller).";
|
||||
case IDC_MOUSE_UNFOCUS:
|
||||
return L"Enabled: Mouse is unfocused and can be used for emulation and outside it.\n\n"
|
||||
L"Disabled: Mouse is focused and can be used for emulation.";
|
||||
case IDC_MULTIPLE_BINDING:
|
||||
return L"Allows binding multiple PS2 controls to one PC control, and binding conflicting controls on opposing ports and/or slots.\n\n"
|
||||
L"Also enables swapping different kinds of pad types(for example, between DS2 and Guitar) when right-clicking in the pad list.";
|
||||
case IDC_PAD_LIST:
|
||||
return L"Left-click on one of the available pads to enable the pad specific options on the right."
|
||||
L"These options include being able to select the pad type(DS2, Guitar, etc.) and enabling automatic analog mode for PS1 emulation.\n\n"
|
||||
L"Right-click to show a pop-up menu that allows for swapping all the settings and bindings, or just the bindings of individual pad types,"
|
||||
L"between the selected pad and one of other active pads, and clearing all the settings and bindings from the selected pad or just the bindings from a selected pad type.\n\n"
|
||||
L"Note: To allow swapping different kinds of pad types(like DS2 to Guitar), the \"Allow binding multiple PS2 Controls...\" option needs to be enabled as well.";
|
||||
case IDC_PAD_TYPE:
|
||||
return L"\"Unplugged\" disables the controller and removes the corresponding pad tab.\n\n"
|
||||
L"\"Dualshock 2\" emulates the default PS2 controller for use in both PS1 and PS2 games.\n\n"
|
||||
L"\"Guitar\" emulates a PS2 controller used in the Guitar Hero and Rock Band series of games.\n\n"
|
||||
L"\"Pop'n Music controller\" emulates a PS2 controller used exclusively in the Japanese Pop'n Music series of games.\n\n"
|
||||
L"\"PS1 Mouse\" emulates the PlayStation Mouse. This controller can only be used in a number of PS1 games like \"Command & Conquer: Red Alert\" and \"Myst\".\n\n"
|
||||
L"\"neGcon\" emulates a controller that can be used in a number of PS1 games and PS2 games like the \"Ridge Racer\" and \"Ace Combat\" series.";
|
||||
case IDC_DIAG_LIST:
|
||||
return L"Shows a list of currently available input devices.\n\n"
|
||||
L"Double-click a device in the list or right-click it and select \"Test Device\" to display a continuously updated list of the state of all inputs on the selected device.\n"
|
||||
L"Use this option to check if all the inputs on a controller function properly.\n\n"
|
||||
L"Right-click and select \"Refresh\" to update the list of devices in case a recently connected device has not shown up yet.";
|
||||
case IDC_G_DI:
|
||||
return L"(Legacy) Enable this if your gamepad doesn't support Xinput.\n\n"
|
||||
L"Disable for DualShock 4 (PS4 controllers) and probably others.";
|
||||
case IDC_G_XI:
|
||||
return L"For Xbox 360/ Xbox One controllers (or devices supporting Xinput).\n\n"
|
||||
L"If it doesn't support Xinput then running through Steam as a non-Steam game might be required for the controllers to work properly.\n\n"
|
||||
L"https://gamepad-tester.com/ to test your controller and check if it only says 'Xinput' on top.";
|
||||
case ID_RESTORE_DEFAULTS:
|
||||
return L"Restores the default contents of LilyPad.ini, undoing all settings changes and bindings that have been set up.";
|
||||
// Pad tabs
|
||||
case IDC_BINDINGS_LIST:
|
||||
return L"Shows a list of currently bound inputs of the selected Pad.\n\n"
|
||||
L"Left-click on one of the bindings in the list to configure it.\n\n"
|
||||
L"Right-click and select \"Delete Selected\" to remove the selected input from the list.\n\n"
|
||||
L"Right-click and select \"Clear All\" to remove all the inputs from the list.\n\n"
|
||||
L"Note: Use Shift/Ctrl + Left-click to select multiple bindings. Changing the displayed configuration will now copy it to all selected bindings.";
|
||||
case IDC_DEVICE_SELECT:
|
||||
return L"Select a single device to hide the bindings from other devices in the bindings list, and to only be able to add new bindings for the selected device.\n\n"
|
||||
L"This can also avoid input conflict issues when one controller is recognized as several devices through different APIs.";
|
||||
case IDC_CONFIGURE_ON_BIND:
|
||||
return L"Immediately go to the configuration setup when you create a new binding.";
|
||||
case ID_MOUSE:
|
||||
return L"Bind a key that releases or captures the mouse.\n\n"
|
||||
L"Pressing the assigned button when the mouse is in focus, it releases the mouse from use in-game and makes the cursor visible so it can move/resize the emulator window.\n\n"
|
||||
L"Alt-tabbing to another application also makes the cursor visible, but focusing the emulation window hides it again.\n\n"
|
||||
L"Pressing the button when the mouse is out of focus and visible, it captures the mouse so that it can be used as a controller again.\n\n"
|
||||
L"Note 1: Though the binding appears on the page of a specific pad, pressing the button affects all mice.\n\n"
|
||||
L"Note 2: By default PCSX2 uses a double-click by the left mouse button to toggle fullscreen mode, this makes the left mouse button unusable as an input."
|
||||
L"To disable this option in PCSX2 go to Config > Emulation Settings > GS Window tab, and disable the \"Double-click toggles fullscreen mode\" checkbox.";
|
||||
case ID_ANALOG:
|
||||
return L"Bind a keys that switches the pad from digital mode to analog mode and vice versa.\n\n"
|
||||
L"This option is useful when analog mode is enabled in a game that does not support it, as this causes the game to not recognise any input or to not even detect a controller.\n\n"
|
||||
L"This option can also be used to enable analog mode in games that support, but do not automatically enable analog mode.\n\n"
|
||||
L"Note: Analog mode enables the analog sticks to function on a DualShock controller, while in digital mode it behaves as an original PlayStation controller.\n\n";
|
||||
case ID_TURBO_KEY:
|
||||
return L"Sets a key to send a TAB press to the emulator, which toggles Turbo mode(200% speed) in PCSX2.";
|
||||
case ID_EXCLUDE:
|
||||
return L"Disables an input so it will be ignored when trying to bind another input.\n\n"
|
||||
L"This is helpful when binding controls for a device with an input that's difficult to center like an accelerator, or just always active like a faulty button or analog stick.";
|
||||
case ID_LOCK_ALL_INPUT:
|
||||
return L"Locks the current state of the pad. Any further input is handled normally, but the initial pad state is the locked state instead of a state with no buttons pressed. "
|
||||
L"Pressing it again releases the old pad state, if the old pad state had any keys pressed. Otherwise, it's released automatically.";
|
||||
case ID_LOCK_DIRECTION:
|
||||
return L"Locks the current state of the d-pad and analog sticks. Pressing this when all input is locked unlocks only the pad and sticks."
|
||||
L"Pressing it again will lock them again, keeping the buttons locked.";
|
||||
case ID_LOCK_BUTTONS:
|
||||
return L"Locks the current state of the buttons. Pressing this when all input is locked unlocks only the buttons. "
|
||||
L"Pressing it again will lock them again, keeping the d-pad and analog sticks locked.";
|
||||
case IDC_RAPID_FIRE:
|
||||
return L"Automatically presses/releases the input every other time the button is polled.";
|
||||
case IDC_FLIP:
|
||||
return L"Inverts a button or axis, making down up and up down.";
|
||||
case IDC_SLIDER_DEADZONE:
|
||||
return L"Decreases or increases the range of an input where no input is recognised.\n\n"
|
||||
L"Increasing the dead zone requires the input to be pressed harder or moved more before it is applied, decreasing it makes it recognise a softer press or a shorter movement.";
|
||||
case IDC_SLIDER_SKIP_DEADZONE:
|
||||
return L"Skips and avoids the dead zone to detect input earlier.\n\n"
|
||||
L"Note: This is useful when a controller input requires too much movement/pressure before there's a corresponding action in-game.";
|
||||
case IDC_SLIDER_SENSITIVITY:
|
||||
return L"Sets how hard an axis or button is pressed.\n\n"
|
||||
L"Note 1: What the default sensitivity value of \"1.00\" means depends on the device itself. The default is high enough that relative axes (which are primarily used by mice) are generally either considered fully up or down."
|
||||
L"For absolute axes (and force feedback devices), which are used by most game devices, a value of 1.0 should map the device's extreme values to the extreme values of a stick/pad.\n\n"
|
||||
L"Note 2: Setting the sensitivity of PC button bindings only really has an effect for PS2 analog sticks or when playing a game with full DS2 pressure sensitivity support.";
|
||||
default:
|
||||
if (updateText)
|
||||
*updateText = false;
|
||||
return L"";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/* LilyPad - Pad plugin for PS2 Emulator
|
||||
* Copyright (C) 2016 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Found- ation, either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* PCSX2 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 for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with PCSX2. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TOOLTIPS_H
|
||||
#define TOOLTIPS_H
|
||||
|
||||
#include "Global.h"
|
||||
|
||||
LPWSTR dialog_message(int ID, bool *updateText = false);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,108 @@
|
|||
/* LilyPad - Pad plugin for PS2 Emulator
|
||||
* Copyright (C) 2002-2014 PCSX2 Dev Team/ChickenLiver
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Found- ation, either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* PCSX2 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 for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with PCSX2. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Global.h"
|
||||
#include "VKey.h"
|
||||
|
||||
wchar_t *GetVKStringW(unsigned char vk)
|
||||
{
|
||||
int flag;
|
||||
static wchar_t t[20];
|
||||
switch (vk) {
|
||||
case 0x0C:
|
||||
return L"Clear";
|
||||
case 0x13:
|
||||
return L"Pause";
|
||||
|
||||
case 0x21: // return "Page Up";
|
||||
case 0x22: // return "Page Down";
|
||||
case 0x23: // return "End";
|
||||
case 0x24: // return "Home";
|
||||
case 0x25: // return "Left";
|
||||
case 0x26: // return "Up";
|
||||
case 0x27: // return "Right";
|
||||
case 0x28: // return "Down";
|
||||
case 0x2D: // return "Insert";
|
||||
case 0x2E: // return "Delete";
|
||||
case 0x5B: // return "Left Windows";
|
||||
case 0x5C: // return "Right Windows";
|
||||
case 0x5D: // return "Application";
|
||||
case 0x6F: // return "Num /";
|
||||
flag = 1 << 24;
|
||||
break;
|
||||
|
||||
case 0x29:
|
||||
return L"Select";
|
||||
case 0x2A:
|
||||
return L"Print";
|
||||
case 0x2B:
|
||||
return L"Execute";
|
||||
case 0x2C:
|
||||
return L"Prnt Scrn";
|
||||
case 0x2F:
|
||||
return L"Help";
|
||||
|
||||
case 0x6C:
|
||||
return L"|";
|
||||
case 0x90:
|
||||
return L"Num Lock";
|
||||
|
||||
case 0xA0:
|
||||
return L"Left Shift";
|
||||
case 0xA1:
|
||||
return L"Right Shift";
|
||||
case 0xA2:
|
||||
return L"Left Ctrl";
|
||||
case 0xA3:
|
||||
return L"Right Ctrl";
|
||||
case 0xA4:
|
||||
return L"Left Alt";
|
||||
case 0xA5:
|
||||
return L"Right Alt";
|
||||
|
||||
case 0xA6:
|
||||
return L"Back";
|
||||
case 0xA7:
|
||||
return L"Forward";
|
||||
case 0xA8:
|
||||
return L"Refresh";
|
||||
case 0xA9:
|
||||
return L"Stop";
|
||||
case 0xAA:
|
||||
return L"Search";
|
||||
case 0xAB:
|
||||
return L"Favorites";
|
||||
case 0xAC:
|
||||
return L"Browser";
|
||||
|
||||
case 0xFA:
|
||||
return L"Play";
|
||||
case 0xFB:
|
||||
return L"Zoom";
|
||||
default:
|
||||
flag = 0;
|
||||
break;
|
||||
}
|
||||
int res = MapVirtualKey(vk, MAPVK_VK_TO_VSC);
|
||||
if (res && GetKeyNameText((res << 16) | flag, t, 20)) {
|
||||
// don't trust windows
|
||||
t[19] = 0;
|
||||
} else {
|
||||
wsprintfW(t, L"Key %i", vk);
|
||||
}
|
||||
return t;
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
/* LilyPad - Pad plugin for PS2 Emulator
|
||||
* Copyright (C) 2002-2014 PCSX2 Dev Team/ChickenLiver
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Found- ation, either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* PCSX2 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 for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with PCSX2. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Maps virtual key codes to strings.
|
||||
wchar_t *GetVKStringW(unsigned char vk);
|
|
@ -0,0 +1,71 @@
|
|||
/* LilyPad - Pad plugin for PS2 Emulator
|
||||
* Copyright (C) 2002-2014 PCSX2 Dev Team/ChickenLiver
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Found- ation, either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* PCSX2 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 for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with PCSX2. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Global.h"
|
||||
#include "InputManager.h"
|
||||
#include "VKey.h"
|
||||
#include "WindowsKeyboard.h"
|
||||
#include "KeyboardQueue.h"
|
||||
|
||||
WindowsKeyboard::WindowsKeyboard(DeviceAPI api, wchar_t *displayName, wchar_t *instanceID, wchar_t *deviceID)
|
||||
: Device(api, KEYBOARD, displayName, instanceID, deviceID)
|
||||
{
|
||||
for (int i = 0; i < 256; i++) {
|
||||
AddPhysicalControl(PSHBTN, i, i);
|
||||
}
|
||||
}
|
||||
|
||||
wchar_t *WindowsKeyboard::GetPhysicalControlName(PhysicalControl *control)
|
||||
{
|
||||
int id = control->id;
|
||||
if (control->type == PSHBTN && id >= 0 && id < 256) {
|
||||
wchar_t *w = GetVKStringW(id);
|
||||
if (w)
|
||||
return w;
|
||||
}
|
||||
return Device::GetPhysicalControlName(control);
|
||||
}
|
||||
|
||||
void WindowsKeyboard::UpdateKey(int vkey, int state)
|
||||
{
|
||||
if (vkey > 7 && vkey < 256) {
|
||||
int newState = state * FULLY_DOWN;
|
||||
if (newState != physicalControlState[vkey]) {
|
||||
// Check for alt-F4 to avoid toggling skip mode incorrectly.
|
||||
if (vkey != VK_F4 || !(physicalControlState[VK_MENU] || physicalControlState[VK_RMENU] || physicalControlState[VK_LMENU])) {
|
||||
int event = KEYPRESS;
|
||||
if (!newState)
|
||||
event = KEYRELEASE;
|
||||
QueueKeyEvent(vkey, event);
|
||||
}
|
||||
}
|
||||
physicalControlState[vkey] = newState;
|
||||
}
|
||||
}
|
||||
|
||||
void WindowsKeyboard::InitState()
|
||||
{
|
||||
AllocState();
|
||||
for (int vkey = 5; vkey < 256; vkey++) {
|
||||
int value = (unsigned short)(((short)GetAsyncKeyState(vkey)) >> 15);
|
||||
value += value & 1;
|
||||
if (vkey == VK_CONTROL || vkey == VK_MENU || vkey == VK_SHIFT) {
|
||||
value = 0;
|
||||
}
|
||||
physicalControlState[vkey] = value;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/* LilyPad - Pad plugin for PS2 Emulator
|
||||
* Copyright (C) 2002-2014 PCSX2 Dev Team/ChickenLiver
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Found- ation, either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* PCSX2 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 for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with PCSX2. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Shared functionality for WM and RAW keyboards.
|
||||
class WindowsKeyboard : public Device
|
||||
{
|
||||
public:
|
||||
WindowsKeyboard(DeviceAPI api, wchar_t *displayName, wchar_t *instanceID = 0, wchar_t *deviceID = 0);
|
||||
wchar_t *GetPhysicalControlName(PhysicalControl *control);
|
||||
void UpdateKey(int vkey, int state);
|
||||
// Calls AllocState() and initializes to current keyboard state using
|
||||
// GetAsyncKeyState().
|
||||
void InitState();
|
||||
};
|
|
@ -0,0 +1,193 @@
|
|||
/* LilyPad - Pad plugin for PS2 Emulator
|
||||
* Copyright (C) 2002-2014 PCSX2 Dev Team/ChickenLiver
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Found- ation, either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* PCSX2 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 for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with PCSX2. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Global.h"
|
||||
#include "InputManager.h"
|
||||
#include "WindowsMessaging.h"
|
||||
#include "VKey.h"
|
||||
#include "DeviceEnumerator.h"
|
||||
#include "WndProcEater.h"
|
||||
#include "WindowsKeyboard.h"
|
||||
#include "WindowsMouse.h"
|
||||
|
||||
ExtraWndProcResult WindowsMessagingWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *output);
|
||||
|
||||
class WindowsMessagingKeyboard;
|
||||
class WindowsMessagingMouse;
|
||||
|
||||
static WindowsMessagingKeyboard *wmk = 0;
|
||||
static WindowsMessagingMouse *wmm = 0;
|
||||
|
||||
class WindowsMessagingKeyboard : public WindowsKeyboard
|
||||
{
|
||||
public:
|
||||
WindowsMessagingKeyboard()
|
||||
: WindowsKeyboard(WM, L"WM Keyboard")
|
||||
{
|
||||
}
|
||||
|
||||
int Activate(InitInfo *initInfo)
|
||||
{
|
||||
// Redundant. Should match the next line.
|
||||
// Deactivate();
|
||||
if (wmk)
|
||||
wmk->Deactivate();
|
||||
|
||||
hWndProc = initInfo->hWndProc;
|
||||
|
||||
if (!wmm)
|
||||
hWndProc->Eat(WindowsMessagingWndProc, EATPROC_NO_UPDATE_WHILE_UPDATING_DEVICES);
|
||||
|
||||
wmk = this;
|
||||
InitState();
|
||||
|
||||
active = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Deactivate()
|
||||
{
|
||||
if (active) {
|
||||
if (!wmm)
|
||||
hWndProc->ReleaseExtraProc(WindowsMessagingWndProc);
|
||||
wmk = 0;
|
||||
active = 0;
|
||||
FreeState();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CheckKey(int vkey)
|
||||
{
|
||||
UpdateKey(vkey, 1 & (((unsigned short)GetAsyncKeyState(vkey)) >> 15));
|
||||
}
|
||||
};
|
||||
|
||||
class WindowsMessagingMouse : public WindowsMouse
|
||||
{
|
||||
public:
|
||||
WindowsMessagingMouse()
|
||||
: WindowsMouse(WM, 1, L"WM Mouse")
|
||||
{
|
||||
}
|
||||
|
||||
int Activate(InitInfo *initInfo)
|
||||
{
|
||||
// Redundant. Should match the next line.
|
||||
// Deactivate();
|
||||
if (wmm)
|
||||
wmm->Deactivate();
|
||||
hWndProc = initInfo->hWndProc;
|
||||
|
||||
if (!wmk)
|
||||
hWndProc->Eat(WindowsMessagingWndProc, EATPROC_NO_UPDATE_WHILE_UPDATING_DEVICES);
|
||||
|
||||
GetMouseCapture(hWndProc->hWndEaten);
|
||||
|
||||
active = 1;
|
||||
|
||||
wmm = this;
|
||||
AllocState();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Deactivate()
|
||||
{
|
||||
if (active) {
|
||||
if (!wmk)
|
||||
hWndProc->ReleaseExtraProc(WindowsMessagingWndProc);
|
||||
ReleaseMouseCapture();
|
||||
wmm = 0;
|
||||
active = 0;
|
||||
FreeState();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ExtraWndProcResult WindowsMessagingWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *output)
|
||||
{
|
||||
if (wmk) {
|
||||
if (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN || uMsg == WM_KEYUP || uMsg == WM_SYSKEYUP) {
|
||||
if (wParam == VK_SHIFT) {
|
||||
wmk->CheckKey(VK_RSHIFT);
|
||||
wmk->CheckKey(VK_LSHIFT);
|
||||
} else if (wParam == VK_CONTROL) {
|
||||
wmk->CheckKey(VK_RCONTROL);
|
||||
wmk->CheckKey(VK_LCONTROL);
|
||||
} else if (wParam == VK_MENU) {
|
||||
wmk->CheckKey(VK_RMENU);
|
||||
wmk->CheckKey(VK_LMENU);
|
||||
} else
|
||||
wmk->UpdateKey(wParam, (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN));
|
||||
return NO_WND_PROC;
|
||||
}
|
||||
// Needed to prevent default handling of keys in some situations.
|
||||
else if (uMsg == WM_CHAR || uMsg == WM_UNICHAR) {
|
||||
return NO_WND_PROC;
|
||||
} else if (uMsg == WM_ACTIVATE) {
|
||||
// Not really needed, but doesn't hurt.
|
||||
memset(wmk->physicalControlState, 0, sizeof(int) * wmk->numPhysicalControls);
|
||||
}
|
||||
}
|
||||
if (wmm) {
|
||||
if (uMsg == WM_MOUSEMOVE) {
|
||||
POINT p;
|
||||
GetCursorPos(&p);
|
||||
// Need check to prevent cursor movement cascade.
|
||||
if (p.x != wmm->center.x || p.y != wmm->center.y) {
|
||||
wmm->UpdateAxis(0, p.x - wmm->center.x);
|
||||
wmm->UpdateAxis(1, p.y - wmm->center.y);
|
||||
|
||||
SetCursorPos(wmm->center.x, wmm->center.y);
|
||||
}
|
||||
return NO_WND_PROC;
|
||||
} else if (uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONUP) {
|
||||
wmm->UpdateButton(0, uMsg == WM_LBUTTONDOWN);
|
||||
return NO_WND_PROC;
|
||||
} else if (uMsg == WM_RBUTTONDOWN || uMsg == WM_RBUTTONUP) {
|
||||
wmm->UpdateButton(1, uMsg == WM_RBUTTONDOWN);
|
||||
return NO_WND_PROC;
|
||||
} else if (uMsg == WM_MBUTTONDOWN || uMsg == WM_MBUTTONUP) {
|
||||
wmm->UpdateButton(2, uMsg == WM_MBUTTONDOWN);
|
||||
return NO_WND_PROC;
|
||||
} else if (uMsg == WM_XBUTTONDOWN || uMsg == WM_XBUTTONUP) {
|
||||
wmm->UpdateButton(3 + ((wParam >> 16) == XBUTTON2), uMsg == WM_XBUTTONDOWN);
|
||||
return NO_WND_PROC;
|
||||
} else if (uMsg == WM_MOUSEWHEEL) {
|
||||
wmm->UpdateAxis(2, ((int)wParam >> 16) / WHEEL_DELTA);
|
||||
return NO_WND_PROC;
|
||||
} else if (uMsg == WM_MOUSEHWHEEL) {
|
||||
wmm->UpdateAxis(3, ((int)wParam >> 16) / WHEEL_DELTA);
|
||||
return NO_WND_PROC;
|
||||
} else if (uMsg == WM_SIZE && wmm->active) {
|
||||
WindowsMouse::WindowResized(hWnd);
|
||||
}
|
||||
// Taken care of elsewhere. When binding, killing focus means stop reading input.
|
||||
// When running PCSX2, I release all mouse and keyboard input elsewhere.
|
||||
/*else if (uMsg == WM_KILLFOCUS) {
|
||||
wmm->Deactivate();
|
||||
}//*/
|
||||
}
|
||||
return CONTINUE_BLISSFULLY;
|
||||
}
|
||||
|
||||
void EnumWindowsMessagingDevices()
|
||||
{
|
||||
dm->AddDevice(new WindowsMessagingKeyboard());
|
||||
dm->AddDevice(new WindowsMessagingMouse());
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/* LilyPad - Pad plugin for PS2 Emulator
|
||||
* Copyright (C) 2002-2014 PCSX2 Dev Team/ChickenLiver
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Found- ation, either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* PCSX2 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 for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with PCSX2. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
void EnumWindowsMessagingDevices();
|
|
@ -0,0 +1,102 @@
|
|||
/* LilyPad - Pad plugin for PS2 Emulator
|
||||
* Copyright (C) 2002-2014 PCSX2 Dev Team/ChickenLiver
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Found- ation, either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* PCSX2 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 for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with PCSX2. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Global.h"
|
||||
#include "InputManager.h"
|
||||
#include "VKey.h"
|
||||
#include "WindowsMouse.h"
|
||||
|
||||
POINT WindowsMouse::origCursorPos;
|
||||
POINT WindowsMouse::center;
|
||||
|
||||
WindowsMouse::WindowsMouse(DeviceAPI api, int hWheel, wchar_t *displayName, wchar_t *instanceID, wchar_t *deviceID)
|
||||
: Device(api, MOUSE, displayName, instanceID, deviceID)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 5; i++) {
|
||||
AddPhysicalControl(PSHBTN, i, i);
|
||||
}
|
||||
|
||||
for (i = 0; i < 3 + hWheel; i++) {
|
||||
AddPhysicalControl(RELAXIS, i + 5, i + 5);
|
||||
}
|
||||
}
|
||||
|
||||
wchar_t *WindowsMouse::GetPhysicalControlName(PhysicalControl *control)
|
||||
{
|
||||
wchar_t *names[9] = {
|
||||
L"L Button",
|
||||
L"R Button",
|
||||
L"M Button",
|
||||
L"Mouse 4",
|
||||
L"Mouse 5",
|
||||
L"X Axis",
|
||||
L"Y Axis",
|
||||
L"Y Wheel",
|
||||
L"X Wheel"};
|
||||
if (control->id < 9)
|
||||
return names[control->id];
|
||||
return Device::GetPhysicalControlName(control);
|
||||
}
|
||||
|
||||
void WindowsMouse::UpdateButton(unsigned int button, int state)
|
||||
{
|
||||
if (button > 4)
|
||||
return;
|
||||
physicalControlState[button] = (state << 16);
|
||||
}
|
||||
|
||||
void WindowsMouse::UpdateAxis(unsigned int axis, int delta)
|
||||
{
|
||||
if (axis > 3)
|
||||
return;
|
||||
// 1 mouse pixel = 1/8th way down.
|
||||
physicalControlState[5 + axis] += (delta << (16 - 3 * (axis < 2)));
|
||||
}
|
||||
|
||||
void WindowsMouse::WindowResized(HWND hWnd)
|
||||
{
|
||||
RECT r;
|
||||
GetWindowRect(hWnd, &r);
|
||||
ClipCursor(&r);
|
||||
center.x = (r.left + r.right) / 2;
|
||||
center.y = (r.top + r.bottom) / 2;
|
||||
SetCursorPos(center.x, center.y);
|
||||
}
|
||||
|
||||
void WindowsMouse::GetMouseCapture(HWND hWnd)
|
||||
{
|
||||
SetCapture(hWnd);
|
||||
ShowCursor(0);
|
||||
|
||||
GetCursorPos(&origCursorPos);
|
||||
|
||||
RECT r;
|
||||
GetWindowRect(hWnd, &r);
|
||||
ClipCursor(&r);
|
||||
center.x = (r.left + r.right) / 2;
|
||||
center.y = (r.top + r.bottom) / 2;
|
||||
SetCursorPos(center.x, center.y);
|
||||
}
|
||||
|
||||
void WindowsMouse::ReleaseMouseCapture()
|
||||
{
|
||||
ClipCursor(0);
|
||||
ReleaseCapture();
|
||||
ShowCursor(1);
|
||||
SetCursorPos(origCursorPos.x, origCursorPos.y);
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/* LilyPad - Pad plugin for PS2 Emulator
|
||||
* Copyright (C) 2002-2014 PCSX2 Dev Team/ChickenLiver
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Found- ation, either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* PCSX2 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 for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with PCSX2. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Shared functionality for WM and RAW keyboards.
|
||||
class WindowsMouse : public Device
|
||||
{
|
||||
public:
|
||||
// Used by GetMouseCapture()/ReleaseMouseCapture()
|
||||
// Static because can have multiple raw mice active at once,
|
||||
// and only get/release capture once.
|
||||
static POINT origCursorPos;
|
||||
static POINT center;
|
||||
|
||||
static void GetMouseCapture(HWND hWnd);
|
||||
static void WindowResized(HWND hWnd);
|
||||
static void ReleaseMouseCapture();
|
||||
|
||||
// hWheel variable lets me display no horizontal wheel for raw input, just to make it clear
|
||||
// that it's not supported.
|
||||
WindowsMouse(DeviceAPI api, int hWheel, wchar_t *displayName, wchar_t *instanceID = 0, wchar_t *deviceID = 0);
|
||||
wchar_t *GetPhysicalControlName(PhysicalControl *control);
|
||||
// State is 0 for up, 1 for down.
|
||||
void UpdateButton(unsigned int button, int state);
|
||||
// 0/1 are x/y. 2 is vert wheel, 3 is horiz wheel.
|
||||
// Delta is in my micro units. change of (1<<16) is 1 full unit, with
|
||||
// the default sensitivity.
|
||||
void UpdateAxis(unsigned int axis, int delta);
|
||||
};
|
|
@ -0,0 +1,155 @@
|
|||
/* LilyPad - Pad plugin for PS2 Emulator
|
||||
* Copyright (C) 2002-2014 PCSX2 Dev Team/ChickenLiver
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Found- ation, either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* PCSX2 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 for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with PCSX2. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Global.h"
|
||||
#include "WndProcEater.h"
|
||||
|
||||
WndProcEater::WndProcEater()
|
||||
{
|
||||
hWndEaten = 0;
|
||||
eatenWndProc = 0;
|
||||
|
||||
extraProcs = 0;
|
||||
numExtraProcs = 0;
|
||||
|
||||
hMutex = CreateMutex(0, 0, L"LilyPad");
|
||||
}
|
||||
|
||||
WndProcEater::~WndProcEater() throw()
|
||||
{
|
||||
if (hMutex) {
|
||||
ReleaseMutex(hMutex);
|
||||
CloseHandle(hMutex);
|
||||
}
|
||||
}
|
||||
|
||||
void WndProcEater::ReleaseExtraProc(ExtraWndProc proc)
|
||||
{
|
||||
// Probably isn't needed, but just in case...
|
||||
if (hMutex)
|
||||
WaitForSingleObject(hMutex, 100);
|
||||
|
||||
//printf( "(Lilypad) Regurgitating! -> 0x%x\n", proc );
|
||||
|
||||
for (int i = 0; i < numExtraProcs; i++) {
|
||||
if (extraProcs[i].proc == proc) {
|
||||
extraProcs[i] = extraProcs[--numExtraProcs];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!numExtraProcs && eatenWndProc) {
|
||||
free(extraProcs);
|
||||
extraProcs = 0;
|
||||
// As numExtraProcs is 0, won't cause recursion if called from Release().
|
||||
Release();
|
||||
}
|
||||
}
|
||||
|
||||
void WndProcEater::Release()
|
||||
{
|
||||
while (numExtraProcs)
|
||||
ReleaseExtraProc(extraProcs[0].proc);
|
||||
if (hWndEaten && IsWindow(hWndEaten)) {
|
||||
RemoveProp(hWndEaten, L"LilyHaxxor");
|
||||
SetWindowLongPtr(hWndEaten, GWLP_WNDPROC, (LONG_PTR)eatenWndProc);
|
||||
hWndEaten = 0;
|
||||
eatenWndProc = 0;
|
||||
}
|
||||
}
|
||||
|
||||
LRESULT WndProcEater::_OverrideWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if (hWnd != hWndEaten)
|
||||
fprintf(stderr, "Totally mismatched window handles on OverrideWndProc!\n");
|
||||
|
||||
ExtraWndProcResult res = CONTINUE_BLISSFULLY;
|
||||
LRESULT out = 0;
|
||||
// Here because want it for binding, even when no keyboard mode is selected.
|
||||
if (uMsg == WM_GETDLGCODE) {
|
||||
return DLGC_WANTALLKEYS | CallWindowProc(eatenWndProc, hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
for (int i = 0; i < numExtraProcs; i++) {
|
||||
// Note: Second bit of deviceUpdateQueued is only set when I receive a device change
|
||||
// notification, which is handled in the GS thread in one of the extraProcs, so this
|
||||
// is all I need to prevent bad things from happening while updating devices. No mutex needed.
|
||||
// if ((deviceUpdateQueued&2) && (extraProcs[i].flags & EATPROC_NO_UPDATE_WHILE_UPDATING_DEVICES)) continue;
|
||||
|
||||
ExtraWndProcResult res2 = extraProcs[i].proc(hWnd, uMsg, wParam, lParam, &out);
|
||||
if (res2 != res) {
|
||||
if (res2 == CONTINUE_BLISSFULLY_AND_RELEASE_PROC) {
|
||||
ReleaseExtraProc(extraProcs[i].proc);
|
||||
i--;
|
||||
} else if (res2 > res)
|
||||
res = res2;
|
||||
}
|
||||
}
|
||||
|
||||
if (res != NO_WND_PROC) {
|
||||
if (out == WM_DESTROY) {
|
||||
Release();
|
||||
}
|
||||
if (res == CONTINUE_BLISSFULLY)
|
||||
out = CallWindowProc(eatenWndProc, hWnd, uMsg, wParam, lParam);
|
||||
else if (res == USE_DEFAULT_WND_PROC)
|
||||
out = DefWindowProc(hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK OverrideWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
WndProcEater *obj = (WndProcEater *)GetProp(hWnd, L"LilyHaxxor");
|
||||
return (obj == NULL) ?
|
||||
DefWindowProc(hWnd, uMsg, wParam, lParam) :
|
||||
obj->_OverrideWndProc(hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
bool WndProcEater::SetWndHandle(HWND hWnd)
|
||||
{
|
||||
if (hWnd == hWndEaten)
|
||||
return true;
|
||||
|
||||
//printf( "(Lilypad) (Re)-Setting window handle! -> this=0x%08x, hWnd=0x%08x\n", this, hWnd );
|
||||
|
||||
Release();
|
||||
SetProp(hWnd, L"LilyHaxxor", (HANDLE) this);
|
||||
|
||||
eatenWndProc = (WNDPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)OverrideWndProc);
|
||||
hWndEaten = (eatenWndProc) ? hWnd : 0;
|
||||
|
||||
return !!hWndEaten;
|
||||
}
|
||||
|
||||
void WndProcEater::Eat(ExtraWndProc proc, DWORD flags)
|
||||
{
|
||||
|
||||
// check if Subclassing failed to init during SetWndHandle
|
||||
if (!hWndEaten)
|
||||
return;
|
||||
|
||||
// Probably isn't needed, but just in case...
|
||||
if (hMutex)
|
||||
WaitForSingleObject(hMutex, 100);
|
||||
|
||||
//printf( "(Lilypad) EatingWndProc! -> 0x%x\n", proc );
|
||||
|
||||
extraProcs = (ExtraWndProcInfo *)realloc(extraProcs, sizeof(ExtraWndProcInfo) * (numExtraProcs + 1));
|
||||
extraProcs[numExtraProcs].proc = proc;
|
||||
extraProcs[numExtraProcs].flags = flags;
|
||||
numExtraProcs++;
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/* LilyPad - Pad plugin for PS2 Emulator
|
||||
* Copyright (C) 2002-2014 PCSX2 Dev Team/ChickenLiver
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Found- ation, either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* PCSX2 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 for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with PCSX2. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define EATPROC_NO_UPDATE_WHILE_UPDATING_DEVICES 1
|
||||
|
||||
/* Need this to let window be subclassed multiple times but still clean up nicely.
|
||||
*/
|
||||
enum ExtraWndProcResult {
|
||||
CONTINUE_BLISSFULLY,
|
||||
// Calls ReleaseExtraProc without messing up order.
|
||||
CONTINUE_BLISSFULLY_AND_RELEASE_PROC,
|
||||
USE_DEFAULT_WND_PROC,
|
||||
NO_WND_PROC
|
||||
};
|
||||
|
||||
typedef ExtraWndProcResult (*ExtraWndProc)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *out);
|
||||
|
||||
struct ExtraWndProcInfo
|
||||
{
|
||||
ExtraWndProc proc;
|
||||
DWORD flags;
|
||||
};
|
||||
|
||||
class WndProcEater
|
||||
{
|
||||
public:
|
||||
HWND hWndEaten;
|
||||
WNDPROC eatenWndProc;
|
||||
ExtraWndProcInfo *extraProcs;
|
||||
int numExtraProcs;
|
||||
|
||||
HANDLE hMutex;
|
||||
|
||||
public:
|
||||
WndProcEater();
|
||||
virtual ~WndProcEater() throw();
|
||||
|
||||
bool SetWndHandle(HWND hWnd);
|
||||
void Eat(ExtraWndProc proc, DWORD flags);
|
||||
void ReleaseExtraProc(ExtraWndProc proc);
|
||||
void Release();
|
||||
|
||||
LRESULT _OverrideWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
};
|
||||
|
||||
extern WndProcEater hWndGSProc;
|
||||
extern WndProcEater hWndTopProc;
|
||||
extern WndProcEater hWndButtonProc;
|
|
@ -0,0 +1,305 @@
|
|||
/* LilyPad - Pad plugin for PS2 Emulator
|
||||
* Copyright (C) 2002-2014 PCSX2 Dev Team/ChickenLiver
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Found- ation, either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* PCSX2 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 for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with PCSX2. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Global.h"
|
||||
#include <VersionHelpers.h>
|
||||
#include <xinput.h>
|
||||
#include "VKey.h"
|
||||
#include "InputManager.h"
|
||||
#include "XInputEnum.h"
|
||||
#include "Config.h"
|
||||
|
||||
// Extra enum
|
||||
#define XINPUT_GAMEPAD_GUIDE 0x0400
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float SCP_UP;
|
||||
float SCP_RIGHT;
|
||||
float SCP_DOWN;
|
||||
float SCP_LEFT;
|
||||
|
||||
float SCP_LX;
|
||||
float SCP_LY;
|
||||
|
||||
float SCP_L1;
|
||||
float SCP_L2;
|
||||
float SCP_L3;
|
||||
|
||||
float SCP_RX;
|
||||
float SCP_RY;
|
||||
|
||||
float SCP_R1;
|
||||
float SCP_R2;
|
||||
float SCP_R3;
|
||||
|
||||
float SCP_T;
|
||||
float SCP_C;
|
||||
float SCP_X;
|
||||
float SCP_S;
|
||||
|
||||
float SCP_SELECT;
|
||||
float SCP_START;
|
||||
|
||||
float SCP_PS;
|
||||
|
||||
} SCP_EXTN;
|
||||
|
||||
|
||||
// This way, I don't require that XInput junk be installed.
|
||||
typedef void(CALLBACK *_XInputEnable)(BOOL enable);
|
||||
typedef DWORD(CALLBACK *_XInputGetStateEx)(DWORD dwUserIndex, XINPUT_STATE *pState);
|
||||
typedef DWORD(CALLBACK *_XInputGetExtended)(DWORD dwUserIndex, SCP_EXTN *pPressure);
|
||||
typedef DWORD(CALLBACK *_XInputSetState)(DWORD dwUserIndex, XINPUT_VIBRATION *pVibration);
|
||||
|
||||
_XInputEnable pXInputEnable = 0;
|
||||
_XInputGetStateEx pXInputGetStateEx = 0;
|
||||
_XInputGetExtended pXInputGetExtended = 0;
|
||||
_XInputSetState pXInputSetState = 0;
|
||||
static bool xinputNotInstalled = false;
|
||||
|
||||
static int xInputActiveCount = 0;
|
||||
|
||||
// Completely unncessary, really.
|
||||
__forceinline int ShortToAxis(int v)
|
||||
{
|
||||
// If positive and at least 1 << 14, increment.
|
||||
v += (!((v >> 15) & 1)) & ((v >> 14) & 1);
|
||||
// Just double.
|
||||
return v * 2;
|
||||
}
|
||||
|
||||
class XInputDevice : public Device
|
||||
{
|
||||
// Cached last vibration values by pad and motor.
|
||||
// Need this, as only one value is changed at a time.
|
||||
int ps2Vibration[2][4][2];
|
||||
// Minor optimization - cache last set vibration values
|
||||
// When there's no change, no need to do anything.
|
||||
XINPUT_VIBRATION xInputVibration;
|
||||
|
||||
public:
|
||||
int index;
|
||||
|
||||
XInputDevice(int index, wchar_t *displayName)
|
||||
: Device(XINPUT, OTHER, displayName)
|
||||
{
|
||||
memset(ps2Vibration, 0, sizeof(ps2Vibration));
|
||||
memset(&xInputVibration, 0, sizeof(xInputVibration));
|
||||
this->index = index;
|
||||
int i;
|
||||
for (i = 0; i < 17; i++) { // Skip empty bit
|
||||
AddPhysicalControl(PRESSURE_BTN, i + (i > 10), 0);
|
||||
}
|
||||
for (; i < 21; i++) {
|
||||
AddPhysicalControl(ABSAXIS, i + 2, 0);
|
||||
}
|
||||
AddFFAxis(L"Slow Motor", 0);
|
||||
AddFFAxis(L"Fast Motor", 1);
|
||||
AddFFEffectType(L"Constant Effect", L"Constant", EFFECT_CONSTANT);
|
||||
}
|
||||
|
||||
wchar_t *GetPhysicalControlName(PhysicalControl *c)
|
||||
{
|
||||
const static wchar_t *names[] = {
|
||||
L"D-pad Up",
|
||||
L"D-pad Down",
|
||||
L"D-pad Left",
|
||||
L"D-pad Right",
|
||||
L"Start",
|
||||
L"Back",
|
||||
L"Left Thumb",
|
||||
L"Right Thumb",
|
||||
L"Left Shoulder",
|
||||
L"Right Shoulder",
|
||||
L"Guide",
|
||||
L"A",
|
||||
L"B",
|
||||
L"X",
|
||||
L"Y",
|
||||
L"Left Trigger",
|
||||
L"Right Trigger",
|
||||
L"Left Thumb X",
|
||||
L"Left Thumb Y",
|
||||
L"Right Thumb X",
|
||||
L"Right Thumb Y",
|
||||
};
|
||||
unsigned int i = (unsigned int)(c - physicalControls);
|
||||
if (i < 21) {
|
||||
return (wchar_t *)names[i];
|
||||
}
|
||||
return Device::GetPhysicalControlName(c);
|
||||
}
|
||||
|
||||
int Activate(InitInfo *initInfo)
|
||||
{
|
||||
if (active)
|
||||
Deactivate();
|
||||
if (!xInputActiveCount) {
|
||||
pXInputEnable(1);
|
||||
}
|
||||
xInputActiveCount++;
|
||||
active = 1;
|
||||
AllocState();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Update()
|
||||
{
|
||||
if (!active)
|
||||
return 0;
|
||||
SCP_EXTN pressure;
|
||||
if (!pXInputGetExtended || (ERROR_SUCCESS != pXInputGetExtended(index, &pressure))) {
|
||||
XINPUT_STATE state;
|
||||
if (ERROR_SUCCESS != pXInputGetStateEx(index, &state)) {
|
||||
Deactivate();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int buttons = state.Gamepad.wButtons;
|
||||
for (int i = 0; i < 15; i++) {
|
||||
physicalControlState[i] = ((buttons >> physicalControls[i].id) & 1) << 16;
|
||||
}
|
||||
physicalControlState[15] = (int)(state.Gamepad.bLeftTrigger * 257.005);
|
||||
physicalControlState[16] = (int)(state.Gamepad.bRightTrigger * 257.005);
|
||||
physicalControlState[17] = ShortToAxis(state.Gamepad.sThumbLX);
|
||||
physicalControlState[18] = ShortToAxis(state.Gamepad.sThumbLY);
|
||||
physicalControlState[19] = ShortToAxis(state.Gamepad.sThumbRX);
|
||||
physicalControlState[20] = ShortToAxis(state.Gamepad.sThumbRY);
|
||||
} else {
|
||||
physicalControlState[0] = (int)(pressure.SCP_UP * FULLY_DOWN);
|
||||
physicalControlState[1] = (int)(pressure.SCP_DOWN * FULLY_DOWN);
|
||||
physicalControlState[2] = (int)(pressure.SCP_LEFT * FULLY_DOWN);
|
||||
physicalControlState[3] = (int)(pressure.SCP_RIGHT * FULLY_DOWN);
|
||||
physicalControlState[4] = (int)(pressure.SCP_START * FULLY_DOWN);
|
||||
physicalControlState[5] = (int)(pressure.SCP_SELECT * FULLY_DOWN);
|
||||
physicalControlState[6] = (int)(pressure.SCP_L3 * FULLY_DOWN);
|
||||
physicalControlState[7] = (int)(pressure.SCP_R3 * FULLY_DOWN);
|
||||
physicalControlState[8] = (int)(pressure.SCP_L1 * FULLY_DOWN);
|
||||
physicalControlState[9] = (int)(pressure.SCP_R1 * FULLY_DOWN);
|
||||
physicalControlState[10] = (int)(pressure.SCP_PS * FULLY_DOWN);
|
||||
physicalControlState[11] = (int)(pressure.SCP_X * FULLY_DOWN);
|
||||
physicalControlState[12] = (int)(pressure.SCP_C * FULLY_DOWN);
|
||||
physicalControlState[13] = (int)(pressure.SCP_S * FULLY_DOWN);
|
||||
physicalControlState[14] = (int)(pressure.SCP_T * FULLY_DOWN);
|
||||
physicalControlState[15] = (int)(pressure.SCP_L2 * FULLY_DOWN);
|
||||
physicalControlState[16] = (int)(pressure.SCP_R2 * FULLY_DOWN);
|
||||
physicalControlState[17] = (int)(pressure.SCP_LX * FULLY_DOWN);
|
||||
physicalControlState[18] = (int)(pressure.SCP_LY * FULLY_DOWN);
|
||||
physicalControlState[19] = (int)(pressure.SCP_RX * FULLY_DOWN);
|
||||
physicalControlState[20] = (int)(pressure.SCP_RY * FULLY_DOWN);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void SetEffects(unsigned char port, unsigned int slot, unsigned char motor, unsigned char force)
|
||||
{
|
||||
ps2Vibration[port][slot][motor] = force;
|
||||
int newVibration[2] = {0, 0};
|
||||
for (int p = 0; p < 2; p++) {
|
||||
for (int s = 0; s < 4; s++) {
|
||||
int padtype = config.padConfigs[p][s].type;
|
||||
for (int i = 0; i < pads[p][s][padtype].numFFBindings; i++) {
|
||||
// Technically should also be a *65535/BASE_SENSITIVITY, but that's close enough to 1 for me.
|
||||
ForceFeedbackBinding *ffb = &pads[p][s][padtype].ffBindings[i];
|
||||
newVibration[0] += (int)((ffb->axes[0].force * (__int64)ps2Vibration[p][s][ffb->motor]) / 255);
|
||||
newVibration[1] += (int)((ffb->axes[1].force * (__int64)ps2Vibration[p][s][ffb->motor]) / 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
newVibration[0] = abs(newVibration[0]);
|
||||
if (newVibration[0] > 65535) {
|
||||
newVibration[0] = 65535;
|
||||
}
|
||||
newVibration[1] = abs(newVibration[1]);
|
||||
if (newVibration[1] > 65535) {
|
||||
newVibration[1] = 65535;
|
||||
}
|
||||
if (newVibration[0] || newVibration[1] || newVibration[0] != xInputVibration.wLeftMotorSpeed || newVibration[1] != xInputVibration.wRightMotorSpeed) {
|
||||
XINPUT_VIBRATION newv = {(WORD)newVibration[0], (WORD)newVibration[1]};
|
||||
if (ERROR_SUCCESS == pXInputSetState(index, &newv)) {
|
||||
xInputVibration = newv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetEffect(ForceFeedbackBinding *binding, unsigned char force)
|
||||
{
|
||||
PadBindings pBackup = pads[0][0][0];
|
||||
pads[0][0][0].ffBindings = binding;
|
||||
pads[0][0][0].numFFBindings = 1;
|
||||
SetEffects(0, 0, binding->motor, 255);
|
||||
pads[0][0][0] = pBackup;
|
||||
}
|
||||
|
||||
void Deactivate()
|
||||
{
|
||||
memset(&xInputVibration, 0, sizeof(xInputVibration));
|
||||
memset(ps2Vibration, 0, sizeof(ps2Vibration));
|
||||
pXInputSetState(index, &xInputVibration);
|
||||
|
||||
FreeState();
|
||||
if (active) {
|
||||
if (!--xInputActiveCount) {
|
||||
pXInputEnable(0);
|
||||
}
|
||||
active = 0;
|
||||
}
|
||||
}
|
||||
|
||||
~XInputDevice()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
void EnumXInputDevices()
|
||||
{
|
||||
wchar_t temp[30];
|
||||
if (!pXInputSetState) {
|
||||
// XInput not installed, so don't repeatedly try to load it.
|
||||
if (xinputNotInstalled)
|
||||
return;
|
||||
|
||||
// Prefer XInput 1.3 since SCP only has an XInput 1.3 wrapper right now.
|
||||
// Also use LoadLibrary and not LoadLibraryEx for XInput 1.3, since some
|
||||
// Windows 7 systems have issues with it.
|
||||
// FIXME: Missing FreeLibrary call.
|
||||
HMODULE hMod = LoadLibrary(L"xinput1_3.dll");
|
||||
if (hMod == nullptr && IsWindows8OrGreater()) {
|
||||
hMod = LoadLibraryEx(L"XInput1_4.dll", nullptr, LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32);
|
||||
}
|
||||
|
||||
if (hMod) {
|
||||
if ((pXInputEnable = (_XInputEnable)GetProcAddress(hMod, "XInputEnable")) &&
|
||||
((pXInputGetStateEx = (_XInputGetStateEx)GetProcAddress(hMod, (LPCSTR)100)) || // Try Ex version first
|
||||
(pXInputGetStateEx = (_XInputGetStateEx)GetProcAddress(hMod, "XInputGetState")))) {
|
||||
pXInputGetExtended = (_XInputGetExtended)GetProcAddress(hMod, "XInputGetExtended");
|
||||
pXInputSetState = (_XInputSetState)GetProcAddress(hMod, "XInputSetState");
|
||||
}
|
||||
}
|
||||
if (!pXInputSetState) {
|
||||
xinputNotInstalled = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
pXInputEnable(1);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
wsprintfW(temp, L"XInput Pad %i", i);
|
||||
dm->AddDevice(new XInputDevice(i, temp));
|
||||
}
|
||||
pXInputEnable(0);
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/* LilyPad - Pad plugin for PS2 Emulator
|
||||
* Copyright (C) 2002-2014 PCSX2 Dev Team/ChickenLiver
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Found- ation, either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* PCSX2 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 for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with PCSX2. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
void EnumXInputDevices();
|
Binary file not shown.
After (image error) Size: 766 B |
|
@ -0,0 +1,169 @@
|
|||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by LilyPad.rc
|
||||
//
|
||||
#define IDD_GENERAL 0x66
|
||||
#define IDD_ABOUT 0x67
|
||||
#define IDI_FROG 0x68
|
||||
#define IDD_CONFIG 0x69
|
||||
#define IDD_CONFIG_GUITAR 0x6A
|
||||
#define IDD_PROPPAGE_LARGE 0x6B
|
||||
#define IDC_CURSOR1 0x6C
|
||||
#define IDD_DIAG 0x6D
|
||||
#define IDR_INI1 0x6E
|
||||
#define IDD_CONFIG_POPN 0x6F
|
||||
#define IDD_CONFIG_PS1_MOUSE 0x70
|
||||
#define IDD_CONFIG_NEGCON 0x71
|
||||
#define IDC_VERSION 0x72
|
||||
// General tab:
|
||||
#define IDC_KB_DISABLE 0x44C
|
||||
#define IDC_KB_DI 0x44D
|
||||
#define IDC_KB_WM 0x44E
|
||||
#define IDC_KB_RAW 0x44F
|
||||
#define IDC_DISABLE_PAD1 0x450
|
||||
#define IDC_M_DISABLE 0x451
|
||||
#define IDC_M_DI 0x452
|
||||
#define IDC_M_WM 0x453
|
||||
#define IDC_M_RAW 0x454
|
||||
#define IDC_G_XI 0x455
|
||||
#define IDC_G_DI 0x456
|
||||
#define IDC_G_DS3 0x457
|
||||
#define IDC_DEBUG_FILE 0x458
|
||||
#define IDC_GUITAR1 0x459
|
||||
#define IDC_MULTITAP1 0x45A
|
||||
#define IDC_MOUSE_UNFOCUS 0x45B
|
||||
#define IDC_AXIS_BUTTONS 0x45C
|
||||
#define IDC_MULTITAP2 0x45D
|
||||
#define IDC_BACKGROUND 0x45E
|
||||
#define IDC_MULTIPLE_BINDING 0x45F
|
||||
#define IDC_FORCE_HIDE 0x460
|
||||
#define IDC_GH2_HACK 0x461
|
||||
#define IDC_PAD_LIST 0x462
|
||||
#define IDC_COMBO1 0x463
|
||||
#define IDC_PAD_TYPE 0x464
|
||||
#define IDC_DIAG_LIST 0x465
|
||||
#define ID_SAVE 0x466
|
||||
#define ID_LOAD 0x467
|
||||
#define ID_RESTORE_DEFAULTS 0x468
|
||||
// Pad tabs:
|
||||
#define IDC_BINDINGS_LIST 0xF00
|
||||
// Pad Input configuration:
|
||||
#define IDC_SLIDER_SENSITIVITY 0x1000
|
||||
#define IDC_FLIP 0x1001
|
||||
#define IDC_AXIS_DIRECTION 0x1002
|
||||
#define IDC_AXIS_CONTROL 0x1003
|
||||
#define IDC_AXIS_SENSITIVITY 0x1004
|
||||
#define IDC_RAPID_FIRE 0x1005
|
||||
#define IDC_AXIS_DEVICE 0x1006
|
||||
#define ID_SENSITIVITY 0x1007
|
||||
#define IDC_SLIDER_DEADZONE 0x1008
|
||||
#define IDC_AXIS_DEADZONE 0x1009
|
||||
#define IDC_LABEL_SENSITIVITY 0x100A
|
||||
#define IDC_LABEL_DEADZONE 0x100B
|
||||
#define IDC_LABEL_SKIP_DEADZONE 0x100C
|
||||
#define IDC_SKIP_DEADZONE_OFF 0x100D
|
||||
#define IDC_SLIDER_SKIP_DEADZONE 0x100E
|
||||
#define IDC_AXIS_SKIP_DEADZONE 0x100F
|
||||
// Pad Input Boxes:
|
||||
#define IDC_DPAD 0x10D0
|
||||
#define IDC_LSTICK 0x10D1
|
||||
#define IDC_RSTICK 0x10D2
|
||||
#define IDC_FACE 0x10D3
|
||||
#define IDC_SHOULDER 0x10D4
|
||||
#define IDC_FACE_ANALOG 0x10D5
|
||||
// Pad Input Bindings:
|
||||
#define ID_MOUSE 0x10FF
|
||||
#define ID_SELECT 0x1100
|
||||
#define ID_L3 0x1101
|
||||
#define ID_R3 0x1102
|
||||
#define ID_START 0x1103
|
||||
#define ID_DPAD_UP 0x1104
|
||||
#define ID_DPAD_RIGHT 0x1105
|
||||
#define ID_DPAD_DOWN 0x1106
|
||||
#define ID_DPAD_LEFT 0x1107
|
||||
#define ID_L2 0x1108
|
||||
#define ID_R2 0x1109
|
||||
#define ID_L1 0x110A
|
||||
#define ID_R1 0x110B
|
||||
#define ID_TRIANGLE 0x110C
|
||||
#define ID_CIRCLE 0x110D
|
||||
#define ID_CROSS 0x110E
|
||||
#define ID_SQUARE 0x110F
|
||||
#define ID_LSTICK_UP 0x1110
|
||||
#define ID_LSTICK_RIGHT 0x1111
|
||||
#define ID_LSTICK_DOWN 0x1112
|
||||
#define ID_LSTICK_LEFT 0x1113
|
||||
#define ID_RSTICK_UP 0x1114
|
||||
#define ID_RSTICK_RIGHT 0x1115
|
||||
#define ID_RSTICK_DOWN 0x1116
|
||||
#define ID_RSTICK_LEFT 0x1117
|
||||
#define ID_ANALOG 0x1118
|
||||
// Special bindings:
|
||||
#define ID_EXCLUDE 0x1119
|
||||
#define ID_LOCK_BUTTONS 0x111A
|
||||
#define ID_LOCK_ALL_INPUT 0x111B
|
||||
#define ID_LOCK_DIRECTION 0x111C
|
||||
#define ID_TURBO_KEY 0x111D
|
||||
#define ID_QUICK_SETUP 0x111E
|
||||
#define IDC_QUICK_SETUP_TEXT 0x111F
|
||||
// Force Feedback bindings:
|
||||
#define IDC_FORCEFEEDBACK 0x1200
|
||||
#define IDC_FORCEFEEDBACK_FUNCTION 0x1201
|
||||
#define ID_BIG_MOTOR 0x1202
|
||||
#define ID_SMALL_MOTOR 0x1203
|
||||
#define ID_FORCEFEEDBACK_BOX 0x1204
|
||||
// Input options:
|
||||
#define IDC_CONFIGURE_ON_BIND 0x1230
|
||||
#define IDC_DEVICE_SELECT 0x1231
|
||||
#define ID_CLEAR 0x1232
|
||||
#define ID_SPECIAL_INPUTS 0x1233
|
||||
// Pad Force Feedback configuration:
|
||||
#define ID_TEST 0x1300
|
||||
#define ID_FF 0x1301
|
||||
#define IDC_FF_EFFECT 0x1302
|
||||
#define IDC_FF_AXIS1_ENABLED 0x1310
|
||||
#define IDC_FF_AXIS1 0x1311
|
||||
#define IDC_FF_AXIS1_FLIP 0x1312
|
||||
#define IDC_FF_AXIS1_SCALE 0x1313
|
||||
#define IDC_FF_AXIS2_ENABLED 0x1320
|
||||
#define IDC_FF_AXIS2 0x1321
|
||||
#define IDC_FF_AXIS2_FLIP 0x1322
|
||||
#define IDC_FF_AXIS2_SCALE 0x1323
|
||||
#define IDC_FF_AXIS3_ENABLED 0x1330
|
||||
#define IDC_FF_AXIS3 0x1331
|
||||
#define IDC_FF_AXIS3_FLIP 0x1332
|
||||
#define IDC_FF_AXIS3_SCALE 0x1333
|
||||
#define IDC_FF_AXIS4_ENABLED 0x1340
|
||||
#define IDC_FF_AXIS4 0x1341
|
||||
#define IDC_FF_AXIS4_FLIP 0x1342
|
||||
#define IDC_FF_AXIS4_SCALE 0x1343
|
||||
#define IDC_FF_AXIS5_ENABLED 0x1350
|
||||
#define IDC_FF_AXIS5 0x1351
|
||||
#define IDC_FF_AXIS5_FLIP 0x1352
|
||||
#define IDC_FF_AXIS5_SCALE 0x1353
|
||||
#define IDC_FF_AXIS6_ENABLED 0x1360
|
||||
#define IDC_FF_AXIS6 0x1361
|
||||
#define IDC_FF_AXIS6_FLIP 0x1362
|
||||
#define IDC_FF_AXIS6_SCALE 0x1363
|
||||
#define IDC_FF_AXIS7_ENABLED 0x1370
|
||||
#define IDC_FF_AXIS7 0x1371
|
||||
#define IDC_FF_AXIS7_FLIP 0x1372
|
||||
#define IDC_FF_AXIS7_SCALE 0x1373
|
||||
#define IDC_FF_AXIS8_ENABLED 0x1380
|
||||
#define IDC_FF_AXIS8 0x1381
|
||||
#define IDC_FF_AXIS8_FLIP 0x1382
|
||||
#define IDC_FF_AXIS8_SCALE 0x1383
|
||||
// Force Feedback & Input configurations:
|
||||
#define ID_CONTROLS 0x1390
|
||||
#define ID_RESET_CONFIG 0x1391
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 116
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 5010
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,434 @@
|
|||
/* LilyPad - Pad plugin for PS2 Emulator
|
||||
* Copyright (C) 2002-2014 PCSX2 Dev Team/ChickenLiver
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Found- ation, either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* PCSX2 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 for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with PCSX2. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Note: From libusb 0.1.12. We will redistribute it as LGPL3+ to keep a single license
|
||||
/*
|
||||
* Prototypes, structure definitions and macros.
|
||||
*
|
||||
* Copyright (c) 2000-2003 Johannes Erdfelt <johannes@erdfelt.com>
|
||||
*
|
||||
* This library is covered by the LGPL2+, read LICENSE for details.
|
||||
*
|
||||
* This file (and only this file) may alternatively be licensed under the
|
||||
* BSD license as well, read LICENSE for details.
|
||||
*/
|
||||
|
||||
#ifndef __USB_H__
|
||||
#define __USB_H__
|
||||
|
||||
/*
|
||||
* 'interface' is defined somewhere in the Windows header files. This macro
|
||||
* is deleted here to avoid conflicts and compile errors.
|
||||
*/
|
||||
|
||||
#ifdef interface
|
||||
#undef interface
|
||||
#endif
|
||||
|
||||
/*
|
||||
* PATH_MAX from limits.h can't be used on Windows if the dll and
|
||||
* import libraries are build/used by different compilers
|
||||
*/
|
||||
|
||||
#define LIBUSB_PATH_MAX 512
|
||||
|
||||
|
||||
/*
|
||||
* USB spec information
|
||||
*
|
||||
* This is all stuff grabbed from various USB specs and is pretty much
|
||||
* not subject to change
|
||||
*/
|
||||
|
||||
/*
|
||||
* Device and/or Interface Class codes
|
||||
*/
|
||||
#define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */
|
||||
#define USB_CLASS_AUDIO 1
|
||||
#define USB_CLASS_COMM 2
|
||||
#define USB_CLASS_HID 3
|
||||
#define USB_CLASS_PRINTER 7
|
||||
#define USB_CLASS_MASS_STORAGE 8
|
||||
#define USB_CLASS_HUB 9
|
||||
#define USB_CLASS_DATA 10
|
||||
#define USB_CLASS_VENDOR_SPEC 0xff
|
||||
|
||||
/*
|
||||
* Descriptor types
|
||||
*/
|
||||
#define USB_DT_DEVICE 0x01
|
||||
#define USB_DT_CONFIG 0x02
|
||||
#define USB_DT_STRING 0x03
|
||||
#define USB_DT_INTERFACE 0x04
|
||||
#define USB_DT_ENDPOINT 0x05
|
||||
|
||||
#define USB_DT_HID 0x21
|
||||
#define USB_DT_REPORT 0x22
|
||||
#define USB_DT_PHYSICAL 0x23
|
||||
#define USB_DT_HUB 0x29
|
||||
|
||||
/*
|
||||
* Descriptor sizes per descriptor type
|
||||
*/
|
||||
#define USB_DT_DEVICE_SIZE 18
|
||||
#define USB_DT_CONFIG_SIZE 9
|
||||
#define USB_DT_INTERFACE_SIZE 9
|
||||
#define USB_DT_ENDPOINT_SIZE 7
|
||||
#define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */
|
||||
#define USB_DT_HUB_NONVAR_SIZE 7
|
||||
|
||||
|
||||
/* ensure byte-packed structures */
|
||||
#include <pshpack1.h>
|
||||
|
||||
|
||||
/* All standard descriptors have these 2 fields in common */
|
||||
struct usb_descriptor_header
|
||||
{
|
||||
unsigned char bLength;
|
||||
unsigned char bDescriptorType;
|
||||
};
|
||||
|
||||
/* String descriptor */
|
||||
struct usb_string_descriptor
|
||||
{
|
||||
unsigned char bLength;
|
||||
unsigned char bDescriptorType;
|
||||
unsigned short wData[1];
|
||||
};
|
||||
|
||||
/* HID descriptor */
|
||||
struct usb_hid_descriptor
|
||||
{
|
||||
unsigned char bLength;
|
||||
unsigned char bDescriptorType;
|
||||
unsigned short bcdHID;
|
||||
unsigned char bCountryCode;
|
||||
unsigned char bNumDescriptors;
|
||||
};
|
||||
|
||||
/* Endpoint descriptor */
|
||||
#define USB_MAXENDPOINTS 32
|
||||
struct usb_endpoint_descriptor
|
||||
{
|
||||
unsigned char bLength;
|
||||
unsigned char bDescriptorType;
|
||||
unsigned char bEndpointAddress;
|
||||
unsigned char bmAttributes;
|
||||
unsigned short wMaxPacketSize;
|
||||
unsigned char bInterval;
|
||||
unsigned char bRefresh;
|
||||
unsigned char bSynchAddress;
|
||||
|
||||
unsigned char *extra; /* Extra descriptors */
|
||||
int extralen;
|
||||
};
|
||||
|
||||
#define USB_ENDPOINT_ADDRESS_MASK 0x0f /* in bEndpointAddress */
|
||||
#define USB_ENDPOINT_DIR_MASK 0x80
|
||||
|
||||
#define USB_ENDPOINT_TYPE_MASK 0x03 /* in bmAttributes */
|
||||
#define USB_ENDPOINT_TYPE_CONTROL 0
|
||||
#define USB_ENDPOINT_TYPE_ISOCHRONOUS 1
|
||||
#define USB_ENDPOINT_TYPE_BULK 2
|
||||
#define USB_ENDPOINT_TYPE_INTERRUPT 3
|
||||
|
||||
/* Interface descriptor */
|
||||
#define USB_MAXINTERFACES 32
|
||||
struct usb_interface_descriptor
|
||||
{
|
||||
unsigned char bLength;
|
||||
unsigned char bDescriptorType;
|
||||
unsigned char bInterfaceNumber;
|
||||
unsigned char bAlternateSetting;
|
||||
unsigned char bNumEndpoints;
|
||||
unsigned char bInterfaceClass;
|
||||
unsigned char bInterfaceSubClass;
|
||||
unsigned char bInterfaceProtocol;
|
||||
unsigned char iInterface;
|
||||
|
||||
struct usb_endpoint_descriptor *endpoint;
|
||||
|
||||
unsigned char *extra; /* Extra descriptors */
|
||||
int extralen;
|
||||
};
|
||||
|
||||
#define USB_MAXALTSETTING 128 /* Hard limit */
|
||||
|
||||
struct usb_interface
|
||||
{
|
||||
struct usb_interface_descriptor *altsetting;
|
||||
|
||||
int num_altsetting;
|
||||
};
|
||||
|
||||
/* Configuration descriptor information.. */
|
||||
#define USB_MAXCONFIG 8
|
||||
struct usb_config_descriptor
|
||||
{
|
||||
unsigned char bLength;
|
||||
unsigned char bDescriptorType;
|
||||
unsigned short wTotalLength;
|
||||
unsigned char bNumInterfaces;
|
||||
unsigned char bConfigurationValue;
|
||||
unsigned char iConfiguration;
|
||||
unsigned char bmAttributes;
|
||||
unsigned char MaxPower;
|
||||
|
||||
struct usb_interface *interface;
|
||||
|
||||
unsigned char *extra; /* Extra descriptors */
|
||||
int extralen;
|
||||
};
|
||||
|
||||
/* Device descriptor */
|
||||
struct usb_device_descriptor
|
||||
{
|
||||
unsigned char bLength;
|
||||
unsigned char bDescriptorType;
|
||||
unsigned short bcdUSB;
|
||||
unsigned char bDeviceClass;
|
||||
unsigned char bDeviceSubClass;
|
||||
unsigned char bDeviceProtocol;
|
||||
unsigned char bMaxPacketSize0;
|
||||
unsigned short idVendor;
|
||||
unsigned short idProduct;
|
||||
unsigned short bcdDevice;
|
||||
unsigned char iManufacturer;
|
||||
unsigned char iProduct;
|
||||
unsigned char iSerialNumber;
|
||||
unsigned char bNumConfigurations;
|
||||
};
|
||||
|
||||
struct usb_ctrl_setup
|
||||
{
|
||||
unsigned char bRequestType;
|
||||
unsigned char bRequest;
|
||||
unsigned short wValue;
|
||||
unsigned short wIndex;
|
||||
unsigned short wLength;
|
||||
};
|
||||
|
||||
/*
|
||||
* Standard requests
|
||||
*/
|
||||
#define USB_REQ_GET_STATUS 0x00
|
||||
#define USB_REQ_CLEAR_FEATURE 0x01
|
||||
/* 0x02 is reserved */
|
||||
#define USB_REQ_SET_FEATURE 0x03
|
||||
/* 0x04 is reserved */
|
||||
#define USB_REQ_SET_ADDRESS 0x05
|
||||
#define USB_REQ_GET_DESCRIPTOR 0x06
|
||||
#define USB_REQ_SET_DESCRIPTOR 0x07
|
||||
#define USB_REQ_GET_CONFIGURATION 0x08
|
||||
#define USB_REQ_SET_CONFIGURATION 0x09
|
||||
#define USB_REQ_GET_INTERFACE 0x0A
|
||||
#define USB_REQ_SET_INTERFACE 0x0B
|
||||
#define USB_REQ_SYNCH_FRAME 0x0C
|
||||
|
||||
#define USB_TYPE_STANDARD (0x00 << 5)
|
||||
#define USB_TYPE_CLASS (0x01 << 5)
|
||||
#define USB_TYPE_VENDOR (0x02 << 5)
|
||||
#define USB_TYPE_RESERVED (0x03 << 5)
|
||||
|
||||
#define USB_RECIP_DEVICE 0x00
|
||||
#define USB_RECIP_INTERFACE 0x01
|
||||
#define USB_RECIP_ENDPOINT 0x02
|
||||
#define USB_RECIP_OTHER 0x03
|
||||
|
||||
/*
|
||||
* Various libusb API related stuff
|
||||
*/
|
||||
|
||||
#define USB_ENDPOINT_IN 0x80
|
||||
#define USB_ENDPOINT_OUT 0x00
|
||||
|
||||
/* Error codes */
|
||||
#define USB_ERROR_BEGIN 500000
|
||||
|
||||
/*
|
||||
* This is supposed to look weird. This file is generated from autoconf
|
||||
* and I didn't want to make this too complicated.
|
||||
*/
|
||||
#define USB_LE16_TO_CPU(x)
|
||||
|
||||
/* Data types */
|
||||
/* struct usb_device; */
|
||||
/* struct usb_bus; */
|
||||
|
||||
struct usb_device
|
||||
{
|
||||
struct usb_device *next, *prev;
|
||||
|
||||
char filename[LIBUSB_PATH_MAX];
|
||||
|
||||
struct usb_bus *bus;
|
||||
|
||||
struct usb_device_descriptor descriptor;
|
||||
struct usb_config_descriptor *config;
|
||||
|
||||
void *dev; /* Darwin support */
|
||||
|
||||
unsigned char devnum;
|
||||
|
||||
unsigned char num_children;
|
||||
struct usb_device **children;
|
||||
};
|
||||
|
||||
struct usb_bus
|
||||
{
|
||||
struct usb_bus *next, *prev;
|
||||
|
||||
char dirname[LIBUSB_PATH_MAX];
|
||||
|
||||
struct usb_device *devices;
|
||||
unsigned long location;
|
||||
|
||||
struct usb_device *root_dev;
|
||||
};
|
||||
|
||||
/* Version information, Windows specific */
|
||||
struct usb_version
|
||||
{
|
||||
struct
|
||||
{
|
||||
int major;
|
||||
int minor;
|
||||
int micro;
|
||||
int nano;
|
||||
} dll;
|
||||
struct
|
||||
{
|
||||
int major;
|
||||
int minor;
|
||||
int micro;
|
||||
int nano;
|
||||
} driver;
|
||||
};
|
||||
|
||||
|
||||
struct usb_dev_handle;
|
||||
typedef struct usb_dev_handle usb_dev_handle;
|
||||
|
||||
/* Variables */
|
||||
#ifndef __USB_C__
|
||||
#define usb_busses usb_get_busses()
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#include <poppack.h>
|
||||
|
||||
#ifdef GOAT
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Function prototypes */
|
||||
|
||||
/* usb.c */
|
||||
usb_dev_handle *usb_open(struct usb_device *dev);
|
||||
int usb_close(usb_dev_handle *dev);
|
||||
int usb_get_string(usb_dev_handle *dev, int index, int langid, char *buf,
|
||||
size_t buflen);
|
||||
int usb_get_string_simple(usb_dev_handle *dev, int index, char *buf,
|
||||
size_t buflen);
|
||||
|
||||
/* descriptors.c */
|
||||
int usb_get_descriptor_by_endpoint(usb_dev_handle *udev, int ep,
|
||||
unsigned char type, unsigned char index,
|
||||
void *buf, int size);
|
||||
int usb_get_descriptor(usb_dev_handle *udev, unsigned char type,
|
||||
unsigned char index, void *buf, int size);
|
||||
|
||||
/* <arch>.c */
|
||||
int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size,
|
||||
int timeout);
|
||||
int usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size,
|
||||
int timeout);
|
||||
int usb_interrupt_write(usb_dev_handle *dev, int ep, char *bytes, int size,
|
||||
int timeout);
|
||||
int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size,
|
||||
int timeout);
|
||||
int usb_control_msg(usb_dev_handle *dev, int requesttype, int request,
|
||||
int value, int index, char *bytes, int size,
|
||||
int timeout);
|
||||
int usb_set_configuration(usb_dev_handle *dev, int configuration);
|
||||
int usb_claim_interface(usb_dev_handle *dev, int interface);
|
||||
int usb_release_interface(usb_dev_handle *dev, int interface);
|
||||
int usb_set_altinterface(usb_dev_handle *dev, int alternate);
|
||||
int usb_resetep(usb_dev_handle *dev, unsigned int ep);
|
||||
int usb_clear_halt(usb_dev_handle *dev, unsigned int ep);
|
||||
int usb_reset(usb_dev_handle *dev);
|
||||
|
||||
char *usb_strerror(void);
|
||||
|
||||
void usb_init(void);
|
||||
void usb_set_debug(int level);
|
||||
int usb_find_busses(void);
|
||||
int usb_find_devices(void);
|
||||
struct usb_device *usb_device(usb_dev_handle *dev);
|
||||
struct usb_bus *usb_get_busses(void);
|
||||
|
||||
|
||||
/* Windows specific functions */
|
||||
|
||||
#define LIBUSB_HAS_INSTALL_SERVICE_NP 1
|
||||
int usb_install_service_np(void);
|
||||
void CALLBACK usb_install_service_np_rundll(HWND wnd, HINSTANCE instance,
|
||||
LPSTR cmd_line, int cmd_show);
|
||||
|
||||
#define LIBUSB_HAS_UNINSTALL_SERVICE_NP 1
|
||||
int usb_uninstall_service_np(void);
|
||||
void CALLBACK usb_uninstall_service_np_rundll(HWND wnd, HINSTANCE instance,
|
||||
LPSTR cmd_line, int cmd_show);
|
||||
|
||||
#define LIBUSB_HAS_INSTALL_DRIVER_NP 1
|
||||
int usb_install_driver_np(const char *inf_file);
|
||||
void CALLBACK usb_install_driver_np_rundll(HWND wnd, HINSTANCE instance,
|
||||
LPSTR cmd_line, int cmd_show);
|
||||
|
||||
#define LIBUSB_HAS_TOUCH_INF_FILE_NP 1
|
||||
int usb_touch_inf_file_np(const char *inf_file);
|
||||
void CALLBACK usb_touch_inf_file_np_rundll(HWND wnd, HINSTANCE instance,
|
||||
LPSTR cmd_line, int cmd_show);
|
||||
|
||||
#define LIBUSB_HAS_INSTALL_NEEDS_RESTART_NP 1
|
||||
int usb_install_needs_restart_np(void);
|
||||
|
||||
const struct usb_version *usb_get_version(void);
|
||||
|
||||
int usb_isochronous_setup_async(usb_dev_handle *dev, void **context,
|
||||
unsigned char ep, int pktsize);
|
||||
int usb_bulk_setup_async(usb_dev_handle *dev, void **context,
|
||||
unsigned char ep);
|
||||
int usb_interrupt_setup_async(usb_dev_handle *dev, void **context,
|
||||
unsigned char ep);
|
||||
|
||||
int usb_submit_async(void *context, char *bytes, int size);
|
||||
int usb_reap_async(void *context, int timeout);
|
||||
int usb_reap_async_nocancel(void *context, int timeout);
|
||||
int usb_cancel_async(void *context);
|
||||
int usb_free_async(void **context);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* __USB_H__ */
|
Loading…
Reference in New Issue