mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 10:54:24 -04:00
XInput gamepad control states, battery information, HID properties
This commit is contained in:
parent
35add447e6
commit
dd8344455c
@ -42,6 +42,7 @@ typedef unsigned long DWORD;
|
||||
typedef unsigned short WORD;
|
||||
typedef long LONG;
|
||||
typedef long UINT;
|
||||
typedef unsigned char BYTE;
|
||||
typedef unsigned long ULONG;
|
||||
typedef long long LONGLONG;
|
||||
typedef long HRESULT;
|
||||
|
@ -578,6 +578,7 @@ if (COMPILER == "MSVC"):
|
||||
LibName("WINGDI", "gdi32.lib")
|
||||
LibName("ADVAPI", "advapi32.lib")
|
||||
LibName("IPHLPAPI", "iphlpapi.lib")
|
||||
LibName("SETUPAPI", "setupapi.lib")
|
||||
LibName("GL", "opengl32.lib")
|
||||
LibName("GLES", "libgles_cm.lib")
|
||||
LibName("GLES2", "libGLESv2.lib")
|
||||
@ -3849,8 +3850,8 @@ if (not RUNTIME):
|
||||
#
|
||||
|
||||
if (not RUNTIME):
|
||||
OPTS=['DIR:panda/metalibs/panda', 'BUILDING:PANDA', 'JPEG', 'PNG',
|
||||
'TIFF', 'ZLIB', 'OPENSSL', 'FREETYPE', 'FFTW', 'ADVAPI', 'WINSOCK2',
|
||||
OPTS=['DIR:panda/metalibs/panda', 'BUILDING:PANDA', 'JPEG', 'PNG', 'TIFF',
|
||||
'ZLIB', 'OPENSSL', 'FREETYPE', 'FFTW', 'ADVAPI', 'WINSOCK2', 'SETUPAPI',
|
||||
'SQUISH', 'NVIDIACG', 'VORBIS', 'WINUSER', 'WINMM', 'WINGDI', 'IPHLPAPI']
|
||||
|
||||
TargetAdd('panda_panda.obj', opts=OPTS, input='panda.cxx')
|
||||
|
@ -21,6 +21,8 @@ INLINE InputDevice::
|
||||
InputDevice() :
|
||||
_flags(0),
|
||||
_device_class(DC_unknown),
|
||||
_vendor_id(0),
|
||||
_product_id(0),
|
||||
_is_connected(false),
|
||||
_event_sequence(0),
|
||||
_enable_pointer_events(false),
|
||||
|
@ -32,6 +32,8 @@ InputDevice(const string &name, DeviceClass dev_class, int flags) :
|
||||
_name(name),
|
||||
_flags(flags),
|
||||
_device_class(dev_class),
|
||||
_vendor_id(0),
|
||||
_product_id(0),
|
||||
_is_connected(true),
|
||||
_event_sequence(0),
|
||||
_enable_pointer_events(false),
|
||||
@ -48,7 +50,7 @@ InputDevice(const string &name, DeviceClass dev_class, int flags) :
|
||||
////////////////////////////////////////////////////////////////////
|
||||
InputDevice::
|
||||
InputDevice(const InputDevice ©) {
|
||||
*this = copy;
|
||||
nassertv(false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -58,16 +60,7 @@ InputDevice(const InputDevice ©) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void InputDevice::
|
||||
operator = (const InputDevice ©) {
|
||||
LightMutexHolder holder(_lock);
|
||||
LightMutexHolder holder1(copy._lock);
|
||||
_name = copy._name;
|
||||
_flags = copy._flags;
|
||||
_is_connected = copy._is_connected;
|
||||
_event_sequence = copy._event_sequence;
|
||||
_enable_pointer_events = copy._enable_pointer_events;
|
||||
_pointer_data = copy._pointer_data;
|
||||
_button_events = copy._button_events;
|
||||
_pointer_events = copy._pointer_events;
|
||||
nassertv(false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -315,10 +308,9 @@ output(ostream &out) const {
|
||||
if (_battery_level > 0 && _max_battery_level > 0) {
|
||||
out << " [";
|
||||
short i = 0;
|
||||
for (; i < _battery_level - 1; ++i) {
|
||||
for (; i < _battery_level; ++i) {
|
||||
out << '=';
|
||||
}
|
||||
out << '/';
|
||||
for (; i < _max_battery_level; ++i) {
|
||||
out << ' ';
|
||||
}
|
||||
|
@ -206,9 +206,13 @@ protected:
|
||||
LightMutex _lock;
|
||||
|
||||
string _name;
|
||||
string _serial_number;
|
||||
string _manufacturer;
|
||||
DeviceClass _device_class;
|
||||
int _flags;
|
||||
int _event_sequence;
|
||||
short _vendor_id;
|
||||
short _product_id;
|
||||
bool _is_connected;
|
||||
bool _enable_pointer_events;
|
||||
PointerData _pointer_data;
|
||||
|
@ -143,7 +143,7 @@ add_device(InputDevice *device) {
|
||||
LightMutexHolder holder(_lock);
|
||||
_all_devices.push_back(device);
|
||||
}
|
||||
throw_event("device-added", device);
|
||||
throw_event("connect-device", device);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -163,7 +163,7 @@ remove_device(InputDevice *device) {
|
||||
_all_devices.erase(it);
|
||||
}
|
||||
|
||||
throw_event("device-removed", device);
|
||||
throw_event("disconnect-device", device);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -220,7 +220,7 @@ poll() {
|
||||
device_cat.info()
|
||||
<< "Removed input device " << *device << "\n";
|
||||
}
|
||||
throw_event("device-removed", device.p());
|
||||
throw_event("disconnect-device", device.p());
|
||||
}
|
||||
|
||||
} else if (event->mask & (IN_CREATE | IN_ATTRIB)) {
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "gamepadButton.h"
|
||||
|
||||
#include <XInput.h>
|
||||
#include <CfgMgr32.h>
|
||||
|
||||
#ifndef XUSER_MAX_COUNT
|
||||
#define XUSER_MAX_COUNT 4
|
||||
@ -27,13 +28,47 @@
|
||||
#define XINPUT_CAPS_FFB_SUPPORTED 0x0001
|
||||
#endif
|
||||
|
||||
#ifndef BATTERY_DEVTYPE_GAMEPAD
|
||||
#define BATTERY_DEVTYPE_GAMEPAD 0x00
|
||||
#endif
|
||||
|
||||
#ifndef BATTERY_TYPE_DISCONNECTED
|
||||
#define BATTERY_TYPE_DISCONNECTED 0x00
|
||||
#endif
|
||||
|
||||
#ifndef BATTERY_TYPE_WIRED
|
||||
#define BATTERY_TYPE_WIRED 0x01
|
||||
#endif
|
||||
|
||||
#ifndef BATTERY_LEVEL_FULL
|
||||
#define BATTERY_LEVEL_FULL 0x03
|
||||
#endif
|
||||
|
||||
typedef struct _XINPUT_BATTERY_INFORMATION {
|
||||
BYTE BatteryType;
|
||||
BYTE BatteryLevel;
|
||||
} XINPUT_BATTERY_INFORMATION;
|
||||
|
||||
// Undocumented, I figured out how this looks by trial and error.
|
||||
struct XINPUT_BUSINFO {
|
||||
WORD VendorID;
|
||||
WORD ProductID;
|
||||
WORD RevisionID;
|
||||
WORD Unknown1; // Unknown - padding?
|
||||
DWORD InstanceID;
|
||||
DWORD Unknown2;
|
||||
//WORD Unknown3;
|
||||
};
|
||||
|
||||
typedef DWORD (*pXInputGetState)(DWORD, XINPUT_STATE *);
|
||||
typedef DWORD (*pXInputGetCapabilities)(DWORD, DWORD, XINPUT_CAPABILITIES *);
|
||||
//typedef DWORD (*pXInputGetBatteryInformation)(DWORD, BYTE, XINPUT_BATTERY_INFORMATION *);
|
||||
typedef DWORD (*pXInputGetBatteryInformation)(DWORD, BYTE, XINPUT_BATTERY_INFORMATION *);
|
||||
typedef DWORD (*pXInputGetBaseBusInformation)(DWORD, XINPUT_BUSINFO *);
|
||||
|
||||
static pXInputGetState get_state = NULL;
|
||||
static pXInputGetCapabilities get_capabilities = NULL;
|
||||
//static pXInputGetBatteryInformation get_battery_information = NULL;
|
||||
static pXInputGetBatteryInformation get_battery_information = NULL;
|
||||
static pXInputGetBaseBusInformation get_base_bus_information = NULL;
|
||||
|
||||
bool XInputDevice::_initialized = false;
|
||||
|
||||
@ -73,10 +108,9 @@ XInputDevice(DWORD user_index) :
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (get_battery_information != NULL) {
|
||||
XINPUT_BATTERY_INFORMATION batt;
|
||||
if (XInputGetBatteryInformation(_index, BATTERY_DEVTYPE_GAMEPAD, &batt) == ERROR_SUCCESS) {
|
||||
if (get_battery_information(_index, 0, &batt) == ERROR_SUCCESS) {
|
||||
if (batt.BatteryType == BATTERY_TYPE_DISCONNECTED) {
|
||||
_is_connected = false;
|
||||
|
||||
@ -89,8 +123,52 @@ XInputDevice(DWORD user_index) :
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Get information about the USB device.
|
||||
// This is not documented at all. I'm probably the first to try this.
|
||||
XINPUT_BUSINFO businfo;
|
||||
if (get_base_bus_information != NULL &&
|
||||
get_base_bus_information(0, &businfo) == ERROR_SUCCESS) {
|
||||
_vendor_id = businfo.VendorID;
|
||||
_product_id = businfo.ProductID;
|
||||
|
||||
{
|
||||
// Reformat the serial number into its original hex string form.
|
||||
char sn[10];
|
||||
sprintf(sn, "%08X", businfo.InstanceID);
|
||||
_serial_number.assign(sn, 8);
|
||||
}
|
||||
|
||||
// Get information about the device from Windows. For that, we'll
|
||||
// first need to construct the device path. Fortunately, we now have
|
||||
// enough information to do so.
|
||||
char path[32];
|
||||
sprintf(path, "USB\\VID_%04X&PID_%04X\\%08X", businfo.VendorID, businfo.ProductID, businfo.InstanceID);
|
||||
|
||||
DEVINST inst;
|
||||
if (CM_Locate_DevNodeA(&inst, path, 0) != 0) {
|
||||
if (device_cat.is_debug()) {
|
||||
device_cat.debug()
|
||||
<< "Could not locate device node " << path << "\n";
|
||||
}
|
||||
} else {
|
||||
// Get the device properties we need.
|
||||
char buffer[4096];
|
||||
ULONG buflen = 4096;
|
||||
if (CM_Get_DevNode_Registry_Property(inst, CM_DRP_DEVICEDESC, 0, buffer, &buflen, 0) == CR_SUCCESS) {
|
||||
_name.assign(buffer);
|
||||
}
|
||||
buflen = 4096;
|
||||
if (CM_Get_DevNode_Registry_Property(inst, CM_DRP_MFG, 0, buffer, &buflen, 0) == CR_SUCCESS) {
|
||||
_manufacturer.assign(buffer);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// We need something to name it.
|
||||
_name = "XInput Device";
|
||||
}
|
||||
|
||||
_controls.resize(6);
|
||||
_buttons.resize(16);
|
||||
|
||||
// Get the initial state.
|
||||
@ -103,6 +181,19 @@ XInputDevice(DWORD user_index) :
|
||||
|
||||
WORD buttons = state.Gamepad.wButtons;
|
||||
|
||||
set_control_map(0, C_left_trigger);
|
||||
set_control_state(0, state.Gamepad.bLeftTrigger / 255.0);
|
||||
set_control_map(1, C_right_trigger);
|
||||
set_control_state(1, state.Gamepad.bRightTrigger / 255.0);
|
||||
set_control_map(2, C_left_x);
|
||||
set_control_state(2, state.Gamepad.sThumbLX / 32767.0);
|
||||
set_control_map(3, C_left_y);
|
||||
set_control_state(3, state.Gamepad.sThumbLY / 32767.0);
|
||||
set_control_map(4, C_right_x);
|
||||
set_control_state(4, state.Gamepad.sThumbRX / 32767.0);
|
||||
set_control_map(5, C_right_y);
|
||||
set_control_state(5, state.Gamepad.sThumbRY / 32767.0);
|
||||
|
||||
set_button_map(0, GamepadButton::dpad_up());
|
||||
set_button_state(0, (buttons & XINPUT_GAMEPAD_DPAD_UP) != 0);
|
||||
set_button_map(1, GamepadButton::dpad_down());
|
||||
@ -146,6 +237,9 @@ bool XInputDevice::
|
||||
init_xinput() {
|
||||
_initialized = true;
|
||||
HMODULE module = LoadLibraryA("Xinput1_4.dll");
|
||||
if (!module) {
|
||||
module = LoadLibraryA("Xinput1_3.dll");
|
||||
}
|
||||
if (module) {
|
||||
// Undocumented version (XInputGetStateEx) that includes a
|
||||
// state bit for the guide button.
|
||||
@ -160,11 +254,13 @@ init_xinput() {
|
||||
}
|
||||
|
||||
get_capabilities = (pXInputGetCapabilities)GetProcAddress(module, "XInputGetCapabilities");
|
||||
get_battery_information = (pXInputGetBatteryInformation)GetProcAddress(module, "XInputGetBatteryInformation");
|
||||
get_base_bus_information = (pXInputGetBaseBusInformation)GetProcAddress(module, MAKEINTRESOURCE(104));
|
||||
return true;
|
||||
}
|
||||
|
||||
device_cat.error()
|
||||
<< "Failed to load Xinput1_4.dll.\n";
|
||||
<< "Failed to load XInput DLL.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -207,6 +303,13 @@ do_poll() {
|
||||
}
|
||||
}
|
||||
|
||||
set_control_state(0, state.Gamepad.bLeftTrigger / 255.0);
|
||||
set_control_state(1, state.Gamepad.bRightTrigger / 255.0);
|
||||
set_control_state(2, state.Gamepad.sThumbLX / 32767.0);
|
||||
set_control_state(3, state.Gamepad.sThumbLY / 32767.0);
|
||||
set_control_state(4, state.Gamepad.sThumbRX / 32767.0);
|
||||
set_control_state(5, state.Gamepad.sThumbRY / 32767.0);
|
||||
|
||||
_last_buttons = state.Gamepad.wButtons;
|
||||
_last_packet = state.dwPacketNumber;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user