mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-30 08:44:19 -04:00
device: various button/axis mapping fixes in Windows raw impl
Now uses a table like on Linux with the various mappings.
This commit is contained in:
parent
f8d7941fe8
commit
0ef9f9bef5
@ -14,6 +14,7 @@
|
||||
#include "winRawInputDevice.h"
|
||||
#include "gamepadButton.h"
|
||||
#include "mouseButton.h"
|
||||
#include "buttonRegistry.h"
|
||||
|
||||
#if defined(_WIN32) && !defined(CPPPARSER)
|
||||
|
||||
@ -21,6 +22,49 @@
|
||||
#include <devpkey.h>
|
||||
#include "phidsdi.h"
|
||||
|
||||
enum QuirkBits : int {
|
||||
// Has no trigger axes.
|
||||
QB_no_analog_triggers = 1,
|
||||
|
||||
// Throttle goes from -1 to 1 rather than from 0 to 1.
|
||||
QB_centered_throttle = 2,
|
||||
|
||||
// Throttle is reversed.
|
||||
QB_reversed_throttle = 4,
|
||||
};
|
||||
|
||||
// Some nonstandard gamepads have different button mappings.
|
||||
static const struct DeviceMapping {
|
||||
unsigned short vendor;
|
||||
unsigned short product;
|
||||
InputDevice::DeviceClass device_class;
|
||||
int quirks;
|
||||
const char *buttons[16];
|
||||
} mapping_presets[] = {
|
||||
// SNES-style USB gamepad
|
||||
{0x0810, 0xe501, InputDevice::DeviceClass::gamepad, QB_no_analog_triggers,
|
||||
{"face_x", "face_a", "face_b", "face_y", "lshoulder", "rshoulder", "none", "none", "back", "start"}
|
||||
},
|
||||
// SPEED Link SL-6535-SBK-01
|
||||
{0x0079, 0x0006, InputDevice::DeviceClass::gamepad, QB_no_analog_triggers,
|
||||
{"face_y", "face_b", "face_a", "face_x", "lshoulder", "rshoulder", "ltrigger", "rtrigger", "back", "start", "lstick", "rstick"}
|
||||
},
|
||||
// T.Flight Hotas X
|
||||
{0x044f, 0xb108, InputDevice::DeviceClass::flight_stick, QB_centered_throttle | QB_reversed_throttle,
|
||||
{0}
|
||||
},
|
||||
// NVIDIA Shield Controller
|
||||
{0x0955, 0x7214, InputDevice::DeviceClass::gamepad, 0,
|
||||
{"face_a", "face_b", "n", "face_x", "face_y", "rshoulder", "lshoulder", "rshoulder", "e", "f", "g", "start", "h", "lstick", "rstick", "i"}
|
||||
},
|
||||
{0},
|
||||
};
|
||||
|
||||
// This is our fallback button mapping, used with Xbox 360 and other devices.
|
||||
static const char *default_gamepad_mapping[16] = {
|
||||
"face_a", "face_b", "face_x", "face_y", "lshoulder", "rshoulder", "back", "start", "lstick", "rstick"
|
||||
};
|
||||
|
||||
static pHidP_GetCaps _HidP_GetCaps = nullptr;
|
||||
static pHidP_GetButtonCaps _HidP_GetButtonCaps = nullptr;
|
||||
static pHidP_GetValueCaps _HidP_GetValueCaps = nullptr;
|
||||
@ -102,6 +146,9 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, std::string name) {
|
||||
|
||||
_name = std::move(name);
|
||||
|
||||
int quirks = 0;
|
||||
const char *const *gamepad_buttons = default_gamepad_mapping;
|
||||
|
||||
switch (info.dwType) {
|
||||
case RIM_TYPEMOUSE:
|
||||
_device_class = DeviceClass::mouse;
|
||||
@ -120,7 +167,7 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, std::string name) {
|
||||
info.hid.usUsage == HID_USAGE_GENERIC_GAMEPAD) {
|
||||
_device_class = DeviceClass::gamepad;
|
||||
|
||||
// Flight sticks
|
||||
// Various game controllers, incl. flight sticks and some gamepads
|
||||
} else if (info.hid.usUsagePage == HID_USAGE_PAGE_GENERIC &&
|
||||
info.hid.usUsage == HID_USAGE_GENERIC_JOYSTICK) {
|
||||
_device_class = DeviceClass::flight_stick;
|
||||
@ -129,11 +176,6 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, std::string name) {
|
||||
// Well, it claims to be a gamepad...
|
||||
_device_class = DeviceClass::gamepad;
|
||||
}
|
||||
//TODO: better solution for this
|
||||
if (_vendor_id == 0x0079 && _product_id == 0x0006) {
|
||||
// Trust GXT 24
|
||||
_device_class = DeviceClass::gamepad;
|
||||
}
|
||||
|
||||
// Mice
|
||||
} else if (info.hid.usUsagePage == HID_USAGE_PAGE_GENERIC &&
|
||||
@ -162,6 +204,28 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, std::string name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_device_class == DeviceClass::gamepad ||
|
||||
_device_class == DeviceClass::flight_stick) {
|
||||
// Do we have a built-in mapping?
|
||||
const DeviceMapping *mapping = mapping_presets;
|
||||
while (mapping->vendor != 0) {
|
||||
if (info.hid.dwVendorId == mapping->vendor &&
|
||||
info.hid.dwProductId == mapping->product) {
|
||||
_device_class = mapping->device_class;
|
||||
gamepad_buttons = mapping->buttons;
|
||||
quirks = mapping->quirks;
|
||||
if (device_cat.is_debug()) {
|
||||
device_cat.debug()
|
||||
<< "Using preset mapping for " << mapping->device_class
|
||||
<< " with VID=" << std::hex << mapping->vendor
|
||||
<< " PID=" << mapping->product << std::dec << "\n";
|
||||
}
|
||||
break;
|
||||
}
|
||||
++mapping;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize hid.dll, which provides the HID parser functions.
|
||||
static bool hid_initialized = false;
|
||||
if (!hid_initialized) {
|
||||
@ -198,38 +262,7 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, std::string name) {
|
||||
<< caps.NumberInputValueCaps << " value caps\n";
|
||||
}
|
||||
|
||||
// Do we have a button mapping?
|
||||
static const ButtonHandle gamepad_buttons_common[] = {
|
||||
ButtonHandle::none(),
|
||||
GamepadButton::face_a(),
|
||||
GamepadButton::face_b(),
|
||||
GamepadButton::face_x(),
|
||||
GamepadButton::face_y(),
|
||||
GamepadButton::lshoulder(),
|
||||
GamepadButton::rshoulder(),
|
||||
GamepadButton::start(),
|
||||
GamepadButton::back(),
|
||||
GamepadButton::lstick(),
|
||||
GamepadButton::rstick(),
|
||||
};
|
||||
const ButtonHandle *gamepad_buttons = gamepad_buttons_common;
|
||||
if (_vendor_id == 0x0810 && _product_id == 0xe501) {
|
||||
// SNES-style USB gamepad
|
||||
static const ButtonHandle gamepad_buttons_snes[] = {
|
||||
ButtonHandle::none(),
|
||||
GamepadButton::face_x(),
|
||||
GamepadButton::face_a(),
|
||||
GamepadButton::face_b(),
|
||||
GamepadButton::face_y(),
|
||||
GamepadButton::lshoulder(),
|
||||
GamepadButton::rshoulder(),
|
||||
ButtonHandle::none(),
|
||||
ButtonHandle::none(),
|
||||
GamepadButton::back(),
|
||||
GamepadButton::start(),
|
||||
};
|
||||
gamepad_buttons = gamepad_buttons_snes;
|
||||
}
|
||||
ButtonRegistry *registry = ButtonRegistry::ptr();
|
||||
|
||||
// Prepare a mapping of data indices to button/axis indices.
|
||||
_indices.resize(caps.NumberInputDataIndices);
|
||||
@ -270,7 +303,7 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, std::string name) {
|
||||
}
|
||||
}
|
||||
|
||||
nassertd(cap.Range.DataIndexMin + upper < _indices.size()) continue;
|
||||
nassertd(cap.Range.DataIndexMin + upper < (int)_indices.size()) continue;
|
||||
|
||||
// Windows will only tell us which buttons in a report are "on", so we
|
||||
// need to keep track of which buttons exist in which report so that we
|
||||
@ -285,8 +318,10 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, std::string name) {
|
||||
switch (cap.UsagePage) {
|
||||
case HID_USAGE_PAGE_BUTTON:
|
||||
if (_device_class == DeviceClass::gamepad) {
|
||||
if (usage < sizeof(gamepad_buttons_common) / sizeof(ButtonHandle)) {
|
||||
handle = gamepad_buttons[usage];
|
||||
if (usage > 0 && usage - 1 < _countof(default_gamepad_mapping)) {
|
||||
if (gamepad_buttons[usage - 1] != nullptr) {
|
||||
handle = registry->find_button(gamepad_buttons[usage - 1]);
|
||||
}
|
||||
}
|
||||
} else if (_device_class == DeviceClass::flight_stick) {
|
||||
if (usage > 0) {
|
||||
@ -347,7 +382,7 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, std::string name) {
|
||||
}
|
||||
}
|
||||
|
||||
nassertd(cap.Range.DataIndexMin + upper < _indices.size()) continue;
|
||||
nassertd(cap.Range.DataIndexMin + upper < (int)_indices.size()) continue;
|
||||
|
||||
for (int j = 0; j <= upper; ++j) {
|
||||
USAGE usage = j + cap.Range.UsageMin;
|
||||
@ -386,9 +421,17 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, std::string name) {
|
||||
break;
|
||||
case HID_USAGE_GENERIC_Z:
|
||||
if (_device_class == DeviceClass::gamepad) {
|
||||
axis = Axis::left_trigger;
|
||||
if ((quirks & QB_no_analog_triggers) == 0) {
|
||||
axis = Axis::left_trigger;
|
||||
}
|
||||
} else if (_device_class == DeviceClass::flight_stick) {
|
||||
axis = Axis::throttle;
|
||||
if ((quirks & QB_reversed_throttle) != 0) {
|
||||
std::swap(cap.LogicalMin, cap.LogicalMax);
|
||||
}
|
||||
if ((quirks & QB_centered_throttle) != 0) {
|
||||
is_signed = false;
|
||||
}
|
||||
} else {
|
||||
axis = Axis::z;
|
||||
swap(cap.LogicalMin, cap.LogicalMax);
|
||||
@ -411,7 +454,9 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, std::string name) {
|
||||
break;
|
||||
case HID_USAGE_GENERIC_RZ:
|
||||
if (_device_class == DeviceClass::gamepad) {
|
||||
axis = Axis::right_trigger;
|
||||
if ((quirks & QB_no_analog_triggers) == 0) {
|
||||
axis = Axis::right_trigger;
|
||||
}
|
||||
} else {
|
||||
// Flip to match Panda's convention for heading.
|
||||
axis = Axis::yaw;
|
||||
@ -436,10 +481,7 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, std::string name) {
|
||||
}
|
||||
|
||||
int axis_index;
|
||||
if (_vendor_id == 0x044f && _product_id == 0xb108 && axis == Axis::throttle) {
|
||||
// T.Flight Hotas X throttle is reversed and can go backwards.
|
||||
axis_index = add_axis(axis, cap.LogicalMax, cap.LogicalMin, true);
|
||||
} else if (!is_signed) {
|
||||
if (!is_signed) {
|
||||
// All axes on the weird XInput-style mappings go from -1 to 1
|
||||
axis_index = add_axis(axis, cap.LogicalMin, cap.LogicalMax, true);
|
||||
} else {
|
||||
|
Loading…
x
Reference in New Issue
Block a user