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 unsigned short WORD;
|
||||||
typedef long LONG;
|
typedef long LONG;
|
||||||
typedef long UINT;
|
typedef long UINT;
|
||||||
|
typedef unsigned char BYTE;
|
||||||
typedef unsigned long ULONG;
|
typedef unsigned long ULONG;
|
||||||
typedef long long LONGLONG;
|
typedef long long LONGLONG;
|
||||||
typedef long HRESULT;
|
typedef long HRESULT;
|
||||||
|
@ -578,6 +578,7 @@ if (COMPILER == "MSVC"):
|
|||||||
LibName("WINGDI", "gdi32.lib")
|
LibName("WINGDI", "gdi32.lib")
|
||||||
LibName("ADVAPI", "advapi32.lib")
|
LibName("ADVAPI", "advapi32.lib")
|
||||||
LibName("IPHLPAPI", "iphlpapi.lib")
|
LibName("IPHLPAPI", "iphlpapi.lib")
|
||||||
|
LibName("SETUPAPI", "setupapi.lib")
|
||||||
LibName("GL", "opengl32.lib")
|
LibName("GL", "opengl32.lib")
|
||||||
LibName("GLES", "libgles_cm.lib")
|
LibName("GLES", "libgles_cm.lib")
|
||||||
LibName("GLES2", "libGLESv2.lib")
|
LibName("GLES2", "libGLESv2.lib")
|
||||||
@ -3849,8 +3850,8 @@ if (not RUNTIME):
|
|||||||
#
|
#
|
||||||
|
|
||||||
if (not RUNTIME):
|
if (not RUNTIME):
|
||||||
OPTS=['DIR:panda/metalibs/panda', 'BUILDING:PANDA', 'JPEG', 'PNG',
|
OPTS=['DIR:panda/metalibs/panda', 'BUILDING:PANDA', 'JPEG', 'PNG', 'TIFF',
|
||||||
'TIFF', 'ZLIB', 'OPENSSL', 'FREETYPE', 'FFTW', 'ADVAPI', 'WINSOCK2',
|
'ZLIB', 'OPENSSL', 'FREETYPE', 'FFTW', 'ADVAPI', 'WINSOCK2', 'SETUPAPI',
|
||||||
'SQUISH', 'NVIDIACG', 'VORBIS', 'WINUSER', 'WINMM', 'WINGDI', 'IPHLPAPI']
|
'SQUISH', 'NVIDIACG', 'VORBIS', 'WINUSER', 'WINMM', 'WINGDI', 'IPHLPAPI']
|
||||||
|
|
||||||
TargetAdd('panda_panda.obj', opts=OPTS, input='panda.cxx')
|
TargetAdd('panda_panda.obj', opts=OPTS, input='panda.cxx')
|
||||||
|
@ -21,6 +21,8 @@ INLINE InputDevice::
|
|||||||
InputDevice() :
|
InputDevice() :
|
||||||
_flags(0),
|
_flags(0),
|
||||||
_device_class(DC_unknown),
|
_device_class(DC_unknown),
|
||||||
|
_vendor_id(0),
|
||||||
|
_product_id(0),
|
||||||
_is_connected(false),
|
_is_connected(false),
|
||||||
_event_sequence(0),
|
_event_sequence(0),
|
||||||
_enable_pointer_events(false),
|
_enable_pointer_events(false),
|
||||||
|
@ -32,6 +32,8 @@ InputDevice(const string &name, DeviceClass dev_class, int flags) :
|
|||||||
_name(name),
|
_name(name),
|
||||||
_flags(flags),
|
_flags(flags),
|
||||||
_device_class(dev_class),
|
_device_class(dev_class),
|
||||||
|
_vendor_id(0),
|
||||||
|
_product_id(0),
|
||||||
_is_connected(true),
|
_is_connected(true),
|
||||||
_event_sequence(0),
|
_event_sequence(0),
|
||||||
_enable_pointer_events(false),
|
_enable_pointer_events(false),
|
||||||
@ -48,7 +50,7 @@ InputDevice(const string &name, DeviceClass dev_class, int flags) :
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
InputDevice::
|
InputDevice::
|
||||||
InputDevice(const InputDevice ©) {
|
InputDevice(const InputDevice ©) {
|
||||||
*this = copy;
|
nassertv(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -58,16 +60,7 @@ InputDevice(const InputDevice ©) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void InputDevice::
|
void InputDevice::
|
||||||
operator = (const InputDevice ©) {
|
operator = (const InputDevice ©) {
|
||||||
LightMutexHolder holder(_lock);
|
nassertv(false);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -315,10 +308,9 @@ output(ostream &out) const {
|
|||||||
if (_battery_level > 0 && _max_battery_level > 0) {
|
if (_battery_level > 0 && _max_battery_level > 0) {
|
||||||
out << " [";
|
out << " [";
|
||||||
short i = 0;
|
short i = 0;
|
||||||
for (; i < _battery_level - 1; ++i) {
|
for (; i < _battery_level; ++i) {
|
||||||
out << '=';
|
out << '=';
|
||||||
}
|
}
|
||||||
out << '/';
|
|
||||||
for (; i < _max_battery_level; ++i) {
|
for (; i < _max_battery_level; ++i) {
|
||||||
out << ' ';
|
out << ' ';
|
||||||
}
|
}
|
||||||
|
@ -206,9 +206,13 @@ protected:
|
|||||||
LightMutex _lock;
|
LightMutex _lock;
|
||||||
|
|
||||||
string _name;
|
string _name;
|
||||||
|
string _serial_number;
|
||||||
|
string _manufacturer;
|
||||||
DeviceClass _device_class;
|
DeviceClass _device_class;
|
||||||
int _flags;
|
int _flags;
|
||||||
int _event_sequence;
|
int _event_sequence;
|
||||||
|
short _vendor_id;
|
||||||
|
short _product_id;
|
||||||
bool _is_connected;
|
bool _is_connected;
|
||||||
bool _enable_pointer_events;
|
bool _enable_pointer_events;
|
||||||
PointerData _pointer_data;
|
PointerData _pointer_data;
|
||||||
|
@ -143,7 +143,7 @@ add_device(InputDevice *device) {
|
|||||||
LightMutexHolder holder(_lock);
|
LightMutexHolder holder(_lock);
|
||||||
_all_devices.push_back(device);
|
_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);
|
_all_devices.erase(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw_event("device-removed", device);
|
throw_event("disconnect-device", device);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -220,7 +220,7 @@ poll() {
|
|||||||
device_cat.info()
|
device_cat.info()
|
||||||
<< "Removed input device " << *device << "\n";
|
<< "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)) {
|
} else if (event->mask & (IN_CREATE | IN_ATTRIB)) {
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include "gamepadButton.h"
|
#include "gamepadButton.h"
|
||||||
|
|
||||||
#include <XInput.h>
|
#include <XInput.h>
|
||||||
|
#include <CfgMgr32.h>
|
||||||
|
|
||||||
#ifndef XUSER_MAX_COUNT
|
#ifndef XUSER_MAX_COUNT
|
||||||
#define XUSER_MAX_COUNT 4
|
#define XUSER_MAX_COUNT 4
|
||||||
@ -27,13 +28,47 @@
|
|||||||
#define XINPUT_CAPS_FFB_SUPPORTED 0x0001
|
#define XINPUT_CAPS_FFB_SUPPORTED 0x0001
|
||||||
#endif
|
#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 (*pXInputGetState)(DWORD, XINPUT_STATE *);
|
||||||
typedef DWORD (*pXInputGetCapabilities)(DWORD, DWORD, XINPUT_CAPABILITIES *);
|
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 pXInputGetState get_state = NULL;
|
||||||
static pXInputGetCapabilities get_capabilities = 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;
|
bool XInputDevice::_initialized = false;
|
||||||
|
|
||||||
@ -73,10 +108,9 @@ XInputDevice(DWORD user_index) :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
if (get_battery_information != NULL) {
|
if (get_battery_information != NULL) {
|
||||||
XINPUT_BATTERY_INFORMATION batt;
|
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) {
|
if (batt.BatteryType == BATTERY_TYPE_DISCONNECTED) {
|
||||||
_is_connected = false;
|
_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);
|
_buttons.resize(16);
|
||||||
|
|
||||||
// Get the initial state.
|
// Get the initial state.
|
||||||
@ -103,6 +181,19 @@ XInputDevice(DWORD user_index) :
|
|||||||
|
|
||||||
WORD buttons = state.Gamepad.wButtons;
|
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_map(0, GamepadButton::dpad_up());
|
||||||
set_button_state(0, (buttons & XINPUT_GAMEPAD_DPAD_UP) != 0);
|
set_button_state(0, (buttons & XINPUT_GAMEPAD_DPAD_UP) != 0);
|
||||||
set_button_map(1, GamepadButton::dpad_down());
|
set_button_map(1, GamepadButton::dpad_down());
|
||||||
@ -146,6 +237,9 @@ bool XInputDevice::
|
|||||||
init_xinput() {
|
init_xinput() {
|
||||||
_initialized = true;
|
_initialized = true;
|
||||||
HMODULE module = LoadLibraryA("Xinput1_4.dll");
|
HMODULE module = LoadLibraryA("Xinput1_4.dll");
|
||||||
|
if (!module) {
|
||||||
|
module = LoadLibraryA("Xinput1_3.dll");
|
||||||
|
}
|
||||||
if (module) {
|
if (module) {
|
||||||
// Undocumented version (XInputGetStateEx) that includes a
|
// Undocumented version (XInputGetStateEx) that includes a
|
||||||
// state bit for the guide button.
|
// state bit for the guide button.
|
||||||
@ -160,11 +254,13 @@ init_xinput() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get_capabilities = (pXInputGetCapabilities)GetProcAddress(module, "XInputGetCapabilities");
|
get_capabilities = (pXInputGetCapabilities)GetProcAddress(module, "XInputGetCapabilities");
|
||||||
|
get_battery_information = (pXInputGetBatteryInformation)GetProcAddress(module, "XInputGetBatteryInformation");
|
||||||
|
get_base_bus_information = (pXInputGetBaseBusInformation)GetProcAddress(module, MAKEINTRESOURCE(104));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
device_cat.error()
|
device_cat.error()
|
||||||
<< "Failed to load Xinput1_4.dll.\n";
|
<< "Failed to load XInput DLL.\n";
|
||||||
return false;
|
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_buttons = state.Gamepad.wButtons;
|
||||||
_last_packet = state.dwPacketNumber;
|
_last_packet = state.dwPacketNumber;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user