mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-30 00:32:57 -04:00
device: overhaul InputDevice API:
- Rename "controls" terminology for analog inputs to "axes" - Change some naming of accessors - Unexpose methods where they are available as properties - Add serial_number field - Put battery levels under a "battery" field
This commit is contained in:
parent
8d8c5a546d
commit
8edc019307
@ -35,7 +35,7 @@ is_valid() const {
|
||||
*/
|
||||
INLINE int AnalogNode::
|
||||
get_num_controls() const {
|
||||
return _analog->get_num_controls();
|
||||
return _analog->get_num_axes();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -45,7 +45,7 @@ get_num_controls() const {
|
||||
*/
|
||||
INLINE double AnalogNode::
|
||||
get_control_state(int index) const {
|
||||
return _analog->get_control_state(index);
|
||||
return _analog->get_axis_value(index);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -54,7 +54,7 @@ get_control_state(int index) const {
|
||||
*/
|
||||
INLINE bool AnalogNode::
|
||||
is_control_known(int index) const {
|
||||
return _analog->is_control_known(index);
|
||||
return _analog->is_axis_known(index);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -81,7 +81,7 @@ write(std::ostream &out, int indent_level) const {
|
||||
DataNode::write(out, indent_level);
|
||||
|
||||
if (_analog != nullptr) {
|
||||
_analog->write_controls(out, indent_level + 2);
|
||||
_analog->write_axes(out, indent_level + 2);
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,12 +101,14 @@ do_transmit_data(DataGraphTraverser *, const DataNodeTransmit &,
|
||||
|
||||
LPoint2 out(0.0f, 0.0f);
|
||||
for (int i = 0; i < max_outputs; i++) {
|
||||
if (_outputs[i]._index >= 0 &&
|
||||
_analog->is_control_known(_outputs[i]._index)) {
|
||||
if (_outputs[i]._flip) {
|
||||
out[i] = -_analog->get_control_state(_outputs[i]._index);
|
||||
} else {
|
||||
out[i] = _analog->get_control_state(_outputs[i]._index);
|
||||
if (_outputs[i]._index >= 0) {
|
||||
InputDevice::AxisState state = _analog->get_axis(_outputs[i]._index);
|
||||
if (state.known) {
|
||||
if (_outputs[i]._flip) {
|
||||
out[i] = -state.value;
|
||||
} else {
|
||||
out[i] = state.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ get_num_buttons() const {
|
||||
*/
|
||||
INLINE void ButtonNode::
|
||||
set_button_map(int index, ButtonHandle button) {
|
||||
_device->set_button_map(index, button);
|
||||
_device->map_button(index, button);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -62,7 +62,7 @@ get_button_map(int index) const {
|
||||
*/
|
||||
INLINE bool ButtonNode::
|
||||
get_button_state(int index) const {
|
||||
return _device->get_button_state(index);
|
||||
return _device->is_button_pressed(index);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -23,5 +23,5 @@ TypeHandle ClientAnalogDevice::_type_handle;
|
||||
void ClientAnalogDevice::
|
||||
write(std::ostream &out, int indent_level) const {
|
||||
indent(out, indent_level) << get_type() << " " << get_name() << ":\n";
|
||||
write_controls(out, indent_level + 2);
|
||||
write_axes(out, indent_level + 2);
|
||||
}
|
||||
|
@ -392,10 +392,10 @@ init_device() {
|
||||
}
|
||||
|
||||
if (test_bit(i, states)) {
|
||||
button.state = S_down;
|
||||
button._state = S_down;
|
||||
all_values_zero = false;
|
||||
} else {
|
||||
button.state = S_up;
|
||||
button._state = S_up;
|
||||
}
|
||||
if (button.handle == GamepadButton::dpad_left()) {
|
||||
emulate_dpad = false;
|
||||
@ -415,7 +415,7 @@ init_device() {
|
||||
}
|
||||
|
||||
if (has_axes) {
|
||||
_control_indices.resize(num_bits, -1);
|
||||
_axis_indices.resize(num_bits, -1);
|
||||
|
||||
for (int i = 0; i < num_bits; ++i) {
|
||||
if (test_bit(i, axes)) {
|
||||
@ -545,12 +545,12 @@ init_device() {
|
||||
std::swap(absinfo.maximum, absinfo.minimum);
|
||||
}
|
||||
if (axis == Axis::throttle && (quirks & QB_centered_throttle) != 0) {
|
||||
index = add_control(axis, absinfo.maximum, absinfo.minimum, true);
|
||||
index = add_axis(axis, absinfo.maximum, absinfo.minimum, true);
|
||||
} else {
|
||||
index = add_control(axis, absinfo.minimum, absinfo.maximum);
|
||||
index = add_axis(axis, absinfo.minimum, absinfo.maximum);
|
||||
}
|
||||
control_changed(index, absinfo.value);
|
||||
_control_indices[i] = index;
|
||||
axis_changed(index, absinfo.value);
|
||||
_axis_indices[i] = index;
|
||||
|
||||
if (absinfo.value != 0) {
|
||||
all_values_zero = false;
|
||||
@ -583,9 +583,9 @@ init_device() {
|
||||
|
||||
if (_ltrigger_code >= 0 && _rtrigger_code >= 0 && !have_analog_triggers) {
|
||||
// Emulate analog triggers.
|
||||
_ltrigger_control = (int)_controls.size();
|
||||
add_control(Axis::left_trigger, 0, 1, false);
|
||||
add_control(Axis::right_trigger, 0, 1, false);
|
||||
_ltrigger_axis = (int)_axes.size();
|
||||
add_axis(Axis::left_trigger, 0, 1, false);
|
||||
add_axis(Axis::right_trigger, 0, 1, false);
|
||||
} else {
|
||||
_ltrigger_code = -1;
|
||||
_rtrigger_code = -1;
|
||||
@ -709,10 +709,10 @@ process_events() {
|
||||
button_changed(_dpad_up_button, events[i].value < 0);
|
||||
button_changed(_dpad_up_button+1, events[i].value > 0);
|
||||
}
|
||||
nassertd(code >= 0 && (size_t)code < _control_indices.size()) break;
|
||||
index = _control_indices[code];
|
||||
nassertd(code >= 0 && (size_t)code < _axis_indices.size()) break;
|
||||
index = _axis_indices[code];
|
||||
if (index >= 0) {
|
||||
control_changed(index, events[i].value);
|
||||
axis_changed(index, events[i].value);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -723,9 +723,9 @@ process_events() {
|
||||
button_changed(index, events[i].value != 0);
|
||||
}
|
||||
if (code == _ltrigger_code) {
|
||||
control_changed(_ltrigger_control, events[i].value);
|
||||
axis_changed(_ltrigger_axis, events[i].value);
|
||||
} else if (code == _rtrigger_code) {
|
||||
control_changed(_ltrigger_control + 1, events[i].value);
|
||||
axis_changed(_ltrigger_axis + 1, events[i].value);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -49,7 +49,7 @@ private:
|
||||
int _ff_strong;
|
||||
int _ff_weak;
|
||||
|
||||
pvector<int> _control_indices;
|
||||
pvector<int> _axis_indices;
|
||||
pvector<int> _button_indices;
|
||||
|
||||
// These are used for D-pad emulation.
|
||||
@ -59,7 +59,7 @@ private:
|
||||
int _dpad_up_button;
|
||||
|
||||
// This is used for axis emulation.
|
||||
int _ltrigger_control;
|
||||
int _ltrigger_axis;
|
||||
int _ltrigger_code;
|
||||
int _rtrigger_code;
|
||||
|
||||
|
@ -24,9 +24,7 @@ InputDevice() :
|
||||
_product_id(0),
|
||||
_is_connected(false),
|
||||
_event_sequence(0),
|
||||
_enable_pointer_events(false),
|
||||
_battery_level(-1),
|
||||
_max_battery_level(-1)
|
||||
_enable_pointer_events(false)
|
||||
{
|
||||
_button_events = new ButtonEventList;
|
||||
}
|
||||
@ -50,6 +48,16 @@ get_manufacturer() const {
|
||||
return _manufacturer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string containing the serial number of the device, if this
|
||||
* information is known.
|
||||
*/
|
||||
INLINE std::string InputDevice::
|
||||
get_serial_number() const {
|
||||
LightMutexHolder holder(_lock);
|
||||
return _serial_number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string containing the USB vendor ID of the device, if this
|
||||
* information is known.
|
||||
@ -160,23 +168,12 @@ get_tracker() const {
|
||||
|
||||
/**
|
||||
* Returns a rough indication of the battery level, ranging from 0 (completely
|
||||
* empty battery) to the number reported by get_max_battery_level(), which
|
||||
* represents a full battery. If this information is not known, returns -1.
|
||||
* empty battery) to the indicated max_level value.
|
||||
*/
|
||||
INLINE short InputDevice::
|
||||
get_battery_level() const {
|
||||
INLINE InputDevice::BatteryData InputDevice::
|
||||
get_battery() const {
|
||||
LightMutexHolder holder(_lock);
|
||||
return _battery_level;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum value that may be reported by get_battery_level(),
|
||||
* representing a full battery. Returns -1 if no battery information is known.
|
||||
*/
|
||||
INLINE short InputDevice::
|
||||
get_max_battery_level() const {
|
||||
LightMutexHolder holder(_lock);
|
||||
return _max_battery_level;
|
||||
return _battery_data;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -202,7 +199,7 @@ get_num_buttons() const {
|
||||
* generate ButtonEvents when the buttons change state.
|
||||
*/
|
||||
INLINE void InputDevice::
|
||||
set_button_map(size_t index, ButtonHandle button) {
|
||||
map_button(size_t index, ButtonHandle button) {
|
||||
LightMutexHolder holder(_lock);
|
||||
if (index >= _buttons.size()) {
|
||||
_buttons.resize(index + 1, ButtonState());
|
||||
@ -213,7 +210,7 @@ set_button_map(size_t index, ButtonHandle button) {
|
||||
|
||||
/**
|
||||
* Returns the ButtonHandle that was previously associated with the given index
|
||||
* number by a call to set_button_map(), or ButtonHandle::none() if no button
|
||||
* number by a call to map_button(), or ButtonHandle::none() if no button
|
||||
* was associated.
|
||||
*/
|
||||
INLINE ButtonHandle InputDevice::
|
||||
@ -230,9 +227,9 @@ get_button_map(size_t index) const {
|
||||
* currently known to be down, or false if it is up or unknown.
|
||||
*/
|
||||
INLINE bool InputDevice::
|
||||
get_button_state(size_t index) const {
|
||||
is_button_pressed(size_t index) const {
|
||||
if (index < _buttons.size()) {
|
||||
return (_buttons[index].state == S_down);
|
||||
return (_buttons[index]._state == S_down);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@ -245,14 +242,14 @@ get_button_state(size_t index) const {
|
||||
INLINE bool InputDevice::
|
||||
is_button_known(size_t index) const {
|
||||
if (index < _buttons.size()) {
|
||||
return _buttons[index].state != S_unknown;
|
||||
return _buttons[index]._state != S_unknown;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ButtonState that is set at the given index, or throw an assection
|
||||
* Returns the ButtonState that is set at the given index, or throw an assert
|
||||
* if the index was not found in the list.
|
||||
*/
|
||||
INLINE InputDevice::ButtonState InputDevice::
|
||||
@ -261,13 +258,13 @@ get_button(size_t index) const {
|
||||
return _buttons[index];
|
||||
} else {
|
||||
device_cat.error()
|
||||
<< "Index " << index << " was not found in the controls list\n";
|
||||
<< "Index " << index << " was not found in the axes list\n";
|
||||
return ButtonState();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first ButtonState found with the given axis, or throw an assection
|
||||
* Returns the first ButtonState found with the given axis, or throw an assert
|
||||
* if the button handle was not found in the list.
|
||||
*/
|
||||
INLINE InputDevice::ButtonState InputDevice::
|
||||
@ -278,103 +275,89 @@ find_button(ButtonHandle handle) const {
|
||||
}
|
||||
}
|
||||
device_cat.error()
|
||||
<< "Handle " << handle.get_name() << " was not found in the controls list\n";
|
||||
<< "Handle " << handle.get_name() << " was not found in the axes list\n";
|
||||
return ButtonState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of analog controls known to the InputDevice. This number
|
||||
* may change as more controls are discovered.
|
||||
* Returns the number of analog axes known to the InputDevice. This number
|
||||
* may change as more axes are discovered.
|
||||
*/
|
||||
INLINE size_t InputDevice::
|
||||
get_num_controls() const {
|
||||
return _controls.size();
|
||||
get_num_axes() const {
|
||||
return _axes.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Associates the indicated Axis with the control of the indicated index
|
||||
* Associates the indicated Axis with the axis of the indicated index
|
||||
* number. Pass Axis::none to turn off any association.
|
||||
*
|
||||
* It is not necessary to call this if you simply want to query the state of
|
||||
* the various controls by index number.
|
||||
* the various axes by index number.
|
||||
*/
|
||||
INLINE void InputDevice::
|
||||
set_control_map(size_t index, InputDevice::Axis axis) {
|
||||
map_axis(size_t index, InputDevice::Axis axis) {
|
||||
LightMutexHolder holder(_lock);
|
||||
if (index >= _controls.size()) {
|
||||
_controls.resize(index + 1, AnalogState());
|
||||
if (index >= _axes.size()) {
|
||||
_axes.resize(index + 1, AxisState());
|
||||
}
|
||||
|
||||
_controls[index].axis = axis;
|
||||
_axes[index].axis = axis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Axis that was previously associated with the given index
|
||||
* number by a call to set_control_map(), or Axis::none if no control was
|
||||
* associated.
|
||||
*/
|
||||
INLINE InputDevice::Axis InputDevice::
|
||||
get_control_map(size_t index) const {
|
||||
if (index < _controls.size()) {
|
||||
return _controls[index].axis;
|
||||
} else {
|
||||
return Axis::none;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current position of indicated analog control (identified by its
|
||||
* index number), or 0.0 if the control is unknown. The normal range of a
|
||||
* single control is -1.0 to 1.0.
|
||||
* Returns the current position of indicated analog axis (identified by its
|
||||
* index number), or 0.0 if the axis is unknown. The normal range of a
|
||||
* single axis is -1.0 to 1.0.
|
||||
*/
|
||||
INLINE double InputDevice::
|
||||
get_control_state(size_t index) const {
|
||||
if (index < _controls.size()) {
|
||||
return _controls[index].state;
|
||||
get_axis_value(size_t index) const {
|
||||
if (index < _axes.size()) {
|
||||
return _axes[index].value;
|
||||
} else {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the AnalogAxis that is set at the given index, or throw an assection
|
||||
* Returns the axis state that is set at the given index, or throw an assert
|
||||
* if the index was not found in the list.
|
||||
*/
|
||||
INLINE InputDevice::AnalogState InputDevice::
|
||||
get_control(size_t index) const {
|
||||
if (index < _controls.size()) {
|
||||
return _controls[index];
|
||||
INLINE InputDevice::AxisState InputDevice::
|
||||
get_axis(size_t index) const {
|
||||
if (index < _axes.size()) {
|
||||
return _axes[index];
|
||||
} else {
|
||||
device_cat.error()
|
||||
<< "Index " << index<< " was not found in the controls list\n";
|
||||
return AnalogState();
|
||||
<< "Index " << index << " was not found in the axes list\n";
|
||||
return AxisState();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first AnalogAxis found with the given axis, or throw an assection
|
||||
* Returns the first AnalogAxis found with the given axis, or throw an assert
|
||||
* if the axis was not found in the list.
|
||||
*/
|
||||
INLINE InputDevice::AnalogState InputDevice::
|
||||
find_control(InputDevice::Axis axis) const {
|
||||
for (size_t i = 0; i < _controls.size(); ++i) {
|
||||
if (_controls[i].axis == axis) {
|
||||
return _controls[i];
|
||||
INLINE InputDevice::AxisState InputDevice::
|
||||
find_axis(InputDevice::Axis axis) const {
|
||||
for (size_t i = 0; i < _axes.size(); ++i) {
|
||||
if (_axes[i].axis == axis) {
|
||||
return _axes[i];
|
||||
}
|
||||
}
|
||||
device_cat.error()
|
||||
<< "Axis " << axis << " was not found in the controls list\n";
|
||||
return AnalogState();
|
||||
<< "Axis " << axis << " was not found in the axes list\n";
|
||||
return AxisState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the state of the indicated analog control is known, or false
|
||||
* if we have never heard anything about this particular control.
|
||||
* Returns true if the state of the indicated analog axis is known, or false
|
||||
* if we have never heard anything about this particular axis.
|
||||
*/
|
||||
INLINE bool InputDevice::
|
||||
is_control_known(size_t index) const {
|
||||
if (index < _controls.size()) {
|
||||
return _controls[index].known;
|
||||
is_axis_known(size_t index) const {
|
||||
if (index < _axes.size()) {
|
||||
return _axes[index].known;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@ -382,8 +365,8 @@ is_control_known(size_t index) const {
|
||||
|
||||
/**
|
||||
* Sets the strength of the vibration effect, if supported. The values are
|
||||
* clamped to 0-1 range. The first value controls the low-frequency rumble
|
||||
* motor, whereas the second controls the high-frequency motor, if present.
|
||||
* clamped to 0-1 range. The first value axes the low-frequency rumble
|
||||
* motor, whereas the second axes the high-frequency motor, if present.
|
||||
*/
|
||||
INLINE void InputDevice::
|
||||
set_vibration(double strong, double weak) {
|
||||
@ -420,36 +403,26 @@ set_connected(bool connected) {
|
||||
_is_connected = connected;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INLINE bool InputDevice::
|
||||
operator == (const InputDevice &) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INLINE bool InputDevice::
|
||||
operator != (const InputDevice &) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INLINE bool InputDevice::
|
||||
operator < (const InputDevice &) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INLINE InputDevice::ButtonState::
|
||||
ButtonState(ButtonHandle handle) :
|
||||
handle(handle),
|
||||
state(S_unknown)
|
||||
{
|
||||
handle(handle) {
|
||||
}
|
||||
|
||||
/**
|
||||
* True if the button state is currently known.
|
||||
*/
|
||||
ALWAYS_INLINE bool InputDevice::ButtonState::
|
||||
is_known() const {
|
||||
return (_state != S_unknown);
|
||||
}
|
||||
|
||||
/**
|
||||
* True if the button is currently known to be pressed.
|
||||
*/
|
||||
ALWAYS_INLINE bool InputDevice::ButtonState::
|
||||
is_pressed() const {
|
||||
return (_state == S_down);
|
||||
}
|
||||
|
@ -32,8 +32,6 @@ InputDevice(const std::string &name, DeviceClass dev_class, int flags) :
|
||||
_is_connected(true),
|
||||
_event_sequence(0),
|
||||
_enable_pointer_events(false),
|
||||
_battery_level(-1),
|
||||
_max_battery_level(-1),
|
||||
_lock("InputDevice")
|
||||
{
|
||||
_button_events = new ButtonEventList;
|
||||
@ -119,13 +117,22 @@ get_pointer_events() {
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called by the implementation to add a new known control.
|
||||
* Called by the implementation to add a new known button.
|
||||
*/
|
||||
int InputDevice::
|
||||
add_control(Axis axis, int minimum, int maximum, bool centered) {
|
||||
AnalogState state;
|
||||
add_button(ButtonHandle button) {
|
||||
int index = (int)_buttons.size();
|
||||
_buttons.push_back(ButtonState(button));
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the implementation to add a new known axis.
|
||||
*/
|
||||
int InputDevice::
|
||||
add_axis(Axis axis, int minimum, int maximum, bool centered) {
|
||||
AxisState state;
|
||||
state.axis = axis;
|
||||
if (centered) {
|
||||
// Centered, eg. for sticks.
|
||||
@ -136,17 +143,17 @@ add_control(Axis axis, int minimum, int maximum, bool centered) {
|
||||
state._scale = 1.0 / maximum;
|
||||
state._bias = 0.0;
|
||||
}
|
||||
int index = (int)_controls.size();
|
||||
_controls.push_back(state);
|
||||
int index = (int)_axes.size();
|
||||
_axes.push_back(state);
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the implementation to add a new known control. This version
|
||||
* tries to guess whether the control is centered or not.
|
||||
* Called by the implementation to add a new known axis. This version tries
|
||||
* to guess whether the axis is centered or not.
|
||||
*/
|
||||
int InputDevice::
|
||||
add_control(Axis axis, int minimum, int maximum) {
|
||||
add_axis(Axis axis, int minimum, int maximum) {
|
||||
bool centered = (minimum < 0)
|
||||
|| axis == Axis::x
|
||||
|| axis == Axis::y
|
||||
@ -160,7 +167,7 @@ add_control(Axis axis, int minimum, int maximum) {
|
||||
|| axis == Axis::right_y
|
||||
|| axis == Axis::wheel
|
||||
|| axis == Axis::rudder;
|
||||
return add_control(axis, minimum, maximum, centered);
|
||||
return add_axis(axis, minimum, maximum, centered);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -246,10 +253,10 @@ button_changed(int index, bool down) {
|
||||
}
|
||||
|
||||
State new_state = down ? S_down : S_up;
|
||||
if (_buttons[index].state == new_state) {
|
||||
if (_buttons[index]._state == new_state) {
|
||||
return;
|
||||
}
|
||||
_buttons[index].state = new_state;
|
||||
_buttons[index]._state = new_state;
|
||||
|
||||
ButtonHandle handle = _buttons[index].handle;
|
||||
|
||||
@ -272,65 +279,67 @@ button_changed(int index, bool down) {
|
||||
/**
|
||||
* Sets the state of the indicated analog index. The caller should ensure that
|
||||
* the lock is held while this call is made. This should be a number in the
|
||||
* range -1.0 to 1.0, representing the current position of the control within
|
||||
* its total range of movement.
|
||||
* range -1.0 to 1.0, representing the current position of the axis within its
|
||||
* total range of movement.
|
||||
*/
|
||||
void InputDevice::
|
||||
set_control_state(int index, double state) {
|
||||
nassertv(_lock.debug_is_locked());
|
||||
set_axis_value(int index, double value) {
|
||||
LightMutexHolder holder(_lock);
|
||||
|
||||
nassertv(index >= 0);
|
||||
if (index >= (int)_controls.size()) {
|
||||
_controls.resize(index + 1, AnalogState());
|
||||
if ((size_t)index >= _axes.size()) {
|
||||
_axes.resize((size_t)index + 1u, AxisState());
|
||||
}
|
||||
|
||||
if (device_cat.is_spam() && _controls[index].state != state) {
|
||||
if (device_cat.is_spam() && _axes[index].value != value) {
|
||||
device_cat.spam()
|
||||
<< "Changed control " << index;
|
||||
<< "Changed axis " << index;
|
||||
|
||||
if (_controls[index].axis != Axis::none) {
|
||||
device_cat.spam(false) << " (" << _controls[index].axis << ")";
|
||||
if (_axes[index].axis != Axis::none) {
|
||||
device_cat.spam(false) << " (" << _axes[index].axis << ")";
|
||||
}
|
||||
|
||||
device_cat.spam(false) << " to " << state << "\n";
|
||||
device_cat.spam(false) << " to " << value << "\n";
|
||||
}
|
||||
|
||||
_controls[index].state = state;
|
||||
_controls[index].known = true;
|
||||
_axes[index].value = value;
|
||||
_axes[index].known = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Like set_control_state, but instead passes a raw, unscaled value.
|
||||
* Called by the implementation during do_poll to indicate that the indicated
|
||||
* axis has received a new raw value. Assumes the lock is held.
|
||||
*/
|
||||
void InputDevice::
|
||||
control_changed(int index, int state) {
|
||||
axis_changed(int index, int state) {
|
||||
nassertv(_lock.debug_is_locked());
|
||||
nassertv(index >= 0);
|
||||
if (index >= (int)_controls.size()) {
|
||||
_controls.resize(index + 1, AnalogState());
|
||||
if ((size_t)index >= _axes.size()) {
|
||||
_axes.resize((size_t)index + 1u, AxisState());
|
||||
}
|
||||
|
||||
double new_state = fma((double)state, _controls[index]._scale, _controls[index]._bias);
|
||||
double value = fma((double)state, _axes[index]._scale, _axes[index]._bias);
|
||||
|
||||
if (device_cat.is_spam() && _controls[index].state != new_state) {
|
||||
if (device_cat.is_spam() && !IS_NEARLY_EQUAL(_axes[index].value, value)) {
|
||||
device_cat.spam()
|
||||
<< "Changed control " << index;
|
||||
<< "Changed axis " << index;
|
||||
|
||||
if (_controls[index].axis != Axis::none) {
|
||||
device_cat.spam(false) << " (" << _controls[index].axis << ")";
|
||||
if (_axes[index].axis != Axis::none) {
|
||||
device_cat.spam(false) << " (" << _axes[index].axis << ")";
|
||||
}
|
||||
|
||||
device_cat.spam(false) << " to " << new_state << " (raw value " << state << ")\n";
|
||||
device_cat.spam(false) << " to " << value << " (raw value " << state << ")\n";
|
||||
}
|
||||
|
||||
_controls[index].state = new_state;
|
||||
_controls[index].known = true;
|
||||
_axes[index].value = value;
|
||||
_axes[index].known = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Records that a tracker movement has taken place.
|
||||
*/
|
||||
void InputDevice::
|
||||
set_tracker(const LPoint3 &pos, const LOrientation &orient, double time) {
|
||||
tracker_changed(const LPoint3 &pos, const LOrientation &orient, double time) {
|
||||
nassertv(_lock.debug_is_locked());
|
||||
|
||||
_tracker_data.set_pos(pos);
|
||||
@ -364,11 +373,9 @@ output(std::ostream &out) const {
|
||||
}
|
||||
}
|
||||
|
||||
if (_controls.size() > 0) {
|
||||
out << ", " << _controls.size() << " control";
|
||||
if (_controls.size() != 1) {
|
||||
out.put('s');
|
||||
}
|
||||
if (_axes.size() > 0) {
|
||||
out << ", " << _axes.size() << " ax"
|
||||
<< (_axes.size() != 1 ? 'e' : 'i') << 's';
|
||||
}
|
||||
|
||||
if (_flags & IDF_has_pointer) {
|
||||
@ -386,13 +393,13 @@ output(std::ostream &out) const {
|
||||
if (_flags & IDF_has_battery) {
|
||||
out << ", battery";
|
||||
|
||||
if (_battery_level > 0 && _max_battery_level > 0) {
|
||||
if (_battery_data.level > 0 && _battery_data.max_level > 0) {
|
||||
out << " [";
|
||||
short i = 0;
|
||||
for (; i < _battery_level; ++i) {
|
||||
for (; i < _battery_data.level; ++i) {
|
||||
out << '=';
|
||||
}
|
||||
for (; i < _max_battery_level; ++i) {
|
||||
for (; i < _battery_data.max_level; ++i) {
|
||||
out << ' ';
|
||||
}
|
||||
out << ']';
|
||||
@ -411,13 +418,13 @@ output_buttons(std::ostream &out) const {
|
||||
Buttons::const_iterator bi;
|
||||
for (bi = _buttons.begin(); bi != _buttons.end(); ++bi) {
|
||||
const ButtonState &state = (*bi);
|
||||
if (state.state != S_unknown) {
|
||||
if (state.is_known()) {
|
||||
if (any_buttons) {
|
||||
out << ", ";
|
||||
}
|
||||
any_buttons = true;
|
||||
out << (int)(bi - _buttons.begin()) << "=";
|
||||
if (state.state == S_up) {
|
||||
if (state._state == S_up) {
|
||||
out << "up";
|
||||
} else {
|
||||
out << "down";
|
||||
@ -439,7 +446,7 @@ write_buttons(std::ostream &out, int indent_level) const {
|
||||
Buttons::const_iterator bi;
|
||||
for (bi = _buttons.begin(); bi != _buttons.end(); ++bi) {
|
||||
const ButtonState &state = (*bi);
|
||||
if (state.state != S_unknown) {
|
||||
if (state.is_known()) {
|
||||
any_buttons = true;
|
||||
|
||||
indent(out, indent_level)
|
||||
@ -449,7 +456,7 @@ write_buttons(std::ostream &out, int indent_level) const {
|
||||
out << "(" << state.handle << ") ";
|
||||
}
|
||||
|
||||
if (state.state == S_up) {
|
||||
if (state._state == S_up) {
|
||||
out << "up";
|
||||
} else {
|
||||
out << "down";
|
||||
@ -465,27 +472,27 @@ write_buttons(std::ostream &out, int indent_level) const {
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a multi-line description of the current analog control states.
|
||||
* Writes a multi-line description of the current analog axis states.
|
||||
*/
|
||||
void InputDevice::
|
||||
write_controls(std::ostream &out, int indent_level) const {
|
||||
write_axes(std::ostream &out, int indent_level) const {
|
||||
LightMutexHolder holder(_lock);
|
||||
|
||||
bool any_controls = false;
|
||||
Controls::const_iterator ai;
|
||||
for (ai = _controls.begin(); ai != _controls.end(); ++ai) {
|
||||
const AnalogState &state = (*ai);
|
||||
bool any_axis = false;
|
||||
Axes::const_iterator ai;
|
||||
for (ai = _axes.begin(); ai != _axes.end(); ++ai) {
|
||||
const AxisState &state = (*ai);
|
||||
if (state.known) {
|
||||
any_controls = true;
|
||||
any_axis = true;
|
||||
|
||||
indent(out, indent_level)
|
||||
<< (int)(ai - _controls.begin()) << ". " << state.state << "\n";
|
||||
<< (int)(ai - _axes.begin()) << ". " << state.value << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (!any_controls) {
|
||||
if (!any_axis) {
|
||||
indent(out, indent_level)
|
||||
<< "(no known analog controls)\n";
|
||||
<< "(no known analog axes)\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,12 +33,12 @@ typedef MouseData PointerData;
|
||||
|
||||
/**
|
||||
* This is a structure representing a single input device. Input devices may
|
||||
* have zero or more buttons, pointers, or controls associated with them, and
|
||||
* have zero or more buttons, pointers, or axes associated with them, and
|
||||
* optionally a motion tracker.
|
||||
*
|
||||
* These devices are brought under a common interface because there is such a
|
||||
* large range of devices out there that may support any number of these types
|
||||
* of controls, we couldn't even begin to cover them with type-specific
|
||||
* of axes, we couldn't even begin to cover them with type-specific
|
||||
* subclasses.
|
||||
*
|
||||
* Use the various has_() and get_num_() methods to determine information about
|
||||
@ -85,16 +85,6 @@ PUBLISHED:
|
||||
DC_COUNT,
|
||||
};
|
||||
|
||||
protected:
|
||||
InputDevice(const std::string &name, DeviceClass dev_class, int flags);
|
||||
|
||||
public:
|
||||
InputDevice();
|
||||
InputDevice(const InputDevice ©);
|
||||
void operator = (const InputDevice ©);
|
||||
~InputDevice();
|
||||
|
||||
PUBLISHED:
|
||||
enum class Axis {
|
||||
none,
|
||||
|
||||
@ -126,19 +116,94 @@ PUBLISHED:
|
||||
brake,
|
||||
};
|
||||
|
||||
enum State {
|
||||
S_unknown,
|
||||
S_up,
|
||||
S_down
|
||||
};
|
||||
|
||||
class ButtonState {
|
||||
public:
|
||||
constexpr ButtonState() = default;
|
||||
INLINE ButtonState(ButtonHandle handle);
|
||||
ALWAYS_INLINE bool is_known() const;
|
||||
ALWAYS_INLINE bool is_pressed() const;
|
||||
|
||||
PUBLISHED:
|
||||
MAKE_PROPERTY(known, is_known);
|
||||
MAKE_PROPERTY(pressed, is_pressed);
|
||||
|
||||
ButtonHandle handle = ButtonHandle::none();
|
||||
|
||||
public:
|
||||
State _state = S_unknown;
|
||||
};
|
||||
|
||||
class AxisState {
|
||||
public:
|
||||
constexpr AxisState() = default;
|
||||
|
||||
PUBLISHED:
|
||||
Axis axis = Axis::none;
|
||||
double value = 0.0;
|
||||
bool known = false;
|
||||
|
||||
public:
|
||||
double _scale = 1.0;
|
||||
double _bias = 0.0;
|
||||
};
|
||||
|
||||
class BatteryData {
|
||||
PUBLISHED:
|
||||
// Ranges from 0 through max_level.
|
||||
short level = -1;
|
||||
|
||||
// Maximum value of 'level' field.
|
||||
short max_level = -1;
|
||||
};
|
||||
|
||||
protected:
|
||||
InputDevice(const std::string &name, DeviceClass dev_class, int flags);
|
||||
|
||||
public:
|
||||
InputDevice();
|
||||
InputDevice(const InputDevice ©);
|
||||
void operator = (const InputDevice ©);
|
||||
~InputDevice();
|
||||
|
||||
INLINE std::string get_name() const;
|
||||
INLINE std::string get_manufacturer() const;
|
||||
INLINE std::string get_serial_number() const;
|
||||
INLINE unsigned short get_vendor_id() const;
|
||||
INLINE unsigned short get_product_id() const;
|
||||
INLINE bool is_connected() const;
|
||||
INLINE DeviceClass get_device_class() const;
|
||||
|
||||
INLINE PointerData get_pointer() const;
|
||||
INLINE TrackerData get_tracker() const;
|
||||
INLINE BatteryData get_battery() const;
|
||||
|
||||
INLINE size_t get_num_buttons() const;
|
||||
INLINE ButtonHandle get_button_map(size_t index) const;
|
||||
INLINE bool is_button_pressed(size_t index) const;
|
||||
INLINE bool is_button_known(size_t index) const;
|
||||
INLINE ButtonState get_button(size_t index) const;
|
||||
|
||||
INLINE size_t get_num_axes() const;
|
||||
INLINE double get_axis_value(size_t index) const;
|
||||
INLINE bool is_axis_known(size_t index) const;
|
||||
INLINE AxisState get_axis(size_t index) const;
|
||||
|
||||
PUBLISHED:
|
||||
// The human-readable name of this input device.
|
||||
MAKE_PROPERTY(name, get_name);
|
||||
|
||||
// The device's manufacturer, or the empty string if not known.
|
||||
MAKE_PROPERTY(manufacturer, get_manufacturer);
|
||||
|
||||
// The device's serial number, or the empty string if not known.
|
||||
MAKE_PROPERTY(serial_number, get_serial_number);
|
||||
|
||||
// USB vendor ID of the device, or 0 if not known.
|
||||
MAKE_PROPERTY(vendor_id, get_vendor_id);
|
||||
|
||||
@ -159,24 +224,22 @@ PUBLISHED:
|
||||
INLINE bool has_vibration() const;
|
||||
INLINE bool has_battery() const;
|
||||
|
||||
INLINE PointerData get_pointer() const;
|
||||
INLINE TrackerData get_tracker() const;
|
||||
// Getters for the various types of device data.
|
||||
MAKE_PROPERTY2(pointer, has_pointer, get_pointer);
|
||||
MAKE_PROPERTY2(tracker, has_tracker, get_tracker);
|
||||
MAKE_PROPERTY2(battery, has_battery, get_battery);
|
||||
|
||||
INLINE short get_battery_level() const;
|
||||
INLINE short get_max_battery_level() const;
|
||||
// Make device buttons and axes iterable
|
||||
MAKE_SEQ_PROPERTY(buttons, get_num_buttons, get_button);
|
||||
MAKE_SEQ_PROPERTY(axes, get_num_axes, get_axis);
|
||||
|
||||
INLINE size_t get_num_buttons() const;
|
||||
INLINE void set_button_map(size_t index, ButtonHandle button);
|
||||
INLINE ButtonHandle get_button_map(size_t index) const;
|
||||
INLINE bool get_button_state(size_t index) const;
|
||||
INLINE bool is_button_known(size_t index) const;
|
||||
|
||||
INLINE size_t get_num_controls() const;
|
||||
INLINE void set_control_map(size_t index, Axis axis);
|
||||
INLINE Axis get_control_map(size_t index) const;
|
||||
INLINE double get_control_state(size_t index) const;
|
||||
INLINE bool is_control_known(size_t index) const;
|
||||
// Associate buttons/axes with symbolic handles.
|
||||
INLINE void map_button(size_t index, ButtonHandle handle);
|
||||
INLINE void map_axis(size_t index, Axis axis);
|
||||
INLINE ButtonState find_button(ButtonHandle handle) const;
|
||||
INLINE AxisState find_axis(Axis axis) const;
|
||||
|
||||
// Enable rumble force-feedback effects
|
||||
INLINE void set_vibration(double strong, double weak);
|
||||
|
||||
INLINE void enable_pointer_events();
|
||||
@ -194,19 +257,20 @@ PUBLISHED:
|
||||
static std::string format_axis(Axis axis);
|
||||
|
||||
protected:
|
||||
// Called during the constructor to add new controls or buttons
|
||||
int add_control(Axis axis, int minimum, int maximum, bool centered);
|
||||
int add_control(Axis axis, int minimum, int maximum);
|
||||
// Called during the constructor to add new axes or buttons
|
||||
int add_button(ButtonHandle handle);
|
||||
int add_axis(Axis axis, int minimum, int maximum, bool centered);
|
||||
int add_axis(Axis axis, int minimum, int maximum);
|
||||
|
||||
void set_pointer(bool inwin, double x, double y, double time);
|
||||
void set_pointer_out_of_window(double time);
|
||||
|
||||
void pointer_moved(double x, double y, double time);
|
||||
void button_changed(int index, bool down);
|
||||
void control_changed(int index, int value);
|
||||
void set_control_state(int index, double state);
|
||||
void axis_changed(int index, int value);
|
||||
void set_axis_value(int index, double state);
|
||||
|
||||
void set_tracker(const LPoint3 &pos, const LOrientation &orient, double time);
|
||||
void tracker_changed(const LPoint3 &pos, const LOrientation &orient, double time);
|
||||
|
||||
virtual void do_set_vibration(double low, double high);
|
||||
virtual void do_poll();
|
||||
@ -214,16 +278,9 @@ protected:
|
||||
public:
|
||||
INLINE void set_connected(bool connected);
|
||||
|
||||
// We need these methods to make VC++ happy when we try to
|
||||
// instantiate a pvector<InputDevice>. They don't do
|
||||
// anything useful.
|
||||
INLINE bool operator == (const InputDevice &other) const;
|
||||
INLINE bool operator != (const InputDevice &other) const;
|
||||
INLINE bool operator < (const InputDevice &other) const;
|
||||
|
||||
void output_buttons(std::ostream &out) const;
|
||||
void write_buttons(std::ostream &out, int indent_level) const;
|
||||
void write_controls(std::ostream &out, int indent_level) const;
|
||||
void write_axes(std::ostream &out, int indent_level) const;
|
||||
|
||||
protected:
|
||||
enum InputDeviceFlags {
|
||||
@ -263,56 +320,14 @@ protected:
|
||||
PT(PointerEventList) _pointer_events;
|
||||
|
||||
PUBLISHED:
|
||||
enum State {
|
||||
S_unknown,
|
||||
S_up,
|
||||
S_down
|
||||
};
|
||||
|
||||
class ButtonState {
|
||||
public:
|
||||
constexpr ButtonState() = default;
|
||||
INLINE ButtonState(ButtonHandle handle);
|
||||
|
||||
PUBLISHED:
|
||||
ButtonHandle handle = ButtonHandle::none();
|
||||
State state = S_unknown;
|
||||
};
|
||||
typedef pvector<ButtonState> Buttons;
|
||||
typedef pvector<AxisState> Axes;
|
||||
Buttons _buttons;
|
||||
Axes _axes;
|
||||
|
||||
class AnalogState {
|
||||
public:
|
||||
constexpr AnalogState() = default;
|
||||
|
||||
PUBLISHED:
|
||||
Axis axis = Axis::none;
|
||||
double state = 0.0;
|
||||
bool known = false;
|
||||
|
||||
public:
|
||||
double _scale = 1.0;
|
||||
double _bias = 0.0;
|
||||
};
|
||||
typedef pvector<AnalogState> Controls;
|
||||
Controls _controls;
|
||||
|
||||
short _battery_level;
|
||||
short _max_battery_level;
|
||||
|
||||
BatteryData _battery_data;
|
||||
TrackerData _tracker_data;
|
||||
|
||||
|
||||
INLINE ButtonState get_button(size_t index) const;
|
||||
INLINE ButtonState find_button(ButtonHandle handle) const;
|
||||
|
||||
INLINE AnalogState get_control(size_t index) const;
|
||||
INLINE AnalogState find_control(Axis axis) const;
|
||||
|
||||
// Make device buttons and controls iterable
|
||||
MAKE_SEQ_PROPERTY(buttons, get_num_buttons, get_button);
|
||||
MAKE_SEQ_PROPERTY(controls, get_num_controls, get_control);
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
|
@ -46,9 +46,6 @@ PUBLISHED:
|
||||
|
||||
INLINE static InputDeviceManager *get_global_ptr();
|
||||
|
||||
// The set of all currently connected devices.
|
||||
MAKE_PROPERTY(devices, get_devices);
|
||||
|
||||
protected:
|
||||
LightMutex _lock;
|
||||
|
||||
|
@ -54,9 +54,27 @@ get_device() const {
|
||||
void InputDeviceNode::
|
||||
do_transmit_data(DataGraphTraverser *, const DataNodeTransmit &,
|
||||
DataNodeTransmit &output) {
|
||||
|
||||
if (_device == nullptr && !_device->is_connected()) {
|
||||
return;
|
||||
}
|
||||
|
||||
_device->poll();
|
||||
|
||||
// get all button events of the device and forward them to the data graph
|
||||
if (_device->has_button_event()) {
|
||||
PT(ButtonEventList) bel = _device->get_button_events();
|
||||
|
||||
// Register the current state for each button.
|
||||
for (int i = 0; i < bel->get_num_events(); ++i) {
|
||||
const ButtonEvent &event = bel->get_event(i);
|
||||
if (event._type == ButtonEvent::T_down) {
|
||||
_button_states[event._button] = true;
|
||||
} else if (event._type == ButtonEvent::T_down) {
|
||||
_button_states[event._button] = false;
|
||||
}
|
||||
}
|
||||
|
||||
output.set_data(_button_events_output, EventParameter(bel));
|
||||
}
|
||||
|
||||
|
@ -21,17 +21,22 @@
|
||||
#include "linmath_events.h"
|
||||
|
||||
/**
|
||||
* Reads the controler data sent from the InputDeviceManager, and
|
||||
* transmits it down the data graph.
|
||||
*
|
||||
* Reads the controller data sent from the InputDeviceManager, and transmits
|
||||
* it down the data graph.
|
||||
*
|
||||
* This is intended to only be accessed from the app thread.
|
||||
*/
|
||||
class EXPCL_PANDA_DEVICE InputDeviceNode : public DataNode {
|
||||
PUBLISHED:
|
||||
InputDeviceNode(InputDevice *device, const std::string &name);
|
||||
|
||||
public:
|
||||
void set_device(InputDevice *device);
|
||||
PT(InputDevice) get_device() const;
|
||||
|
||||
PUBLISHED:
|
||||
MAKE_PROPERTY(device, get_device, set_device);
|
||||
|
||||
protected:
|
||||
// Inherited from DataNode
|
||||
virtual void do_transmit_data(DataGraphTraverser *trav,
|
||||
@ -39,6 +44,9 @@ protected:
|
||||
DataNodeTransmit &output);
|
||||
|
||||
private:
|
||||
pmap<ButtonHandle, bool> _button_states;
|
||||
pmap<InputDevice::Axis, double> _control_states;
|
||||
|
||||
// outputs
|
||||
int _button_events_output;
|
||||
int _low_battery_event_output;
|
||||
|
@ -287,14 +287,14 @@ parse_element(IOHIDElementRef element) {
|
||||
int max = IOHIDElementGetLogicalMax(element);
|
||||
if (_vendor_id == 0x044f && _product_id == 0xb108 && axis == Axis::throttle) {
|
||||
// T.Flight Hotas X throttle is reversed and can go backwards.
|
||||
add_control(axis, max, min, true);
|
||||
add_axis(axis, max, min, true);
|
||||
} else if (axis == Axis::yaw || axis == Axis::rudder || axis == Axis::left_y || axis == Axis::right_y ||
|
||||
(_device_class == DC_3d_mouse && (axis == Axis::y || axis == Axis::z || axis == Axis::roll))) {
|
||||
// We'd like to reverse the Y axis to match the XInput behavior.
|
||||
// We also reverse yaw to obey the right-hand rule.
|
||||
add_control(axis, max, min);
|
||||
add_axis(axis, max, min);
|
||||
} else {
|
||||
add_control(axis, min, max);
|
||||
add_axis(axis, min, max);
|
||||
}
|
||||
|
||||
_analog_elements.push_back(element);
|
||||
@ -734,7 +734,7 @@ do_poll() {
|
||||
IOHIDValueRef value_ref;
|
||||
if (IOHIDDeviceGetValue(_device, _analog_elements[i], &value_ref) == kIOReturnSuccess) {
|
||||
int value = IOHIDValueGetIntegerValue(value_ref);
|
||||
control_changed(i, value);
|
||||
axis_changed(i, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -121,7 +121,7 @@ open_device() {
|
||||
ioctl(_fd, JSIOCGBUTTONS, &num_buttons);
|
||||
|
||||
_buttons.resize(num_buttons);
|
||||
_controls.resize(num_axes);
|
||||
_axes.resize(num_axes);
|
||||
|
||||
if (num_buttons > 0) {
|
||||
uint16_t btnmap[512];
|
||||
@ -225,11 +225,11 @@ open_device() {
|
||||
_dpad_x_axis = i;
|
||||
_dpad_left_button = (int)_buttons.size();
|
||||
if (_device_class == DC_gamepad) {
|
||||
_buttons.push_back(ButtonState(GamepadButton::dpad_left()));
|
||||
_buttons.push_back(ButtonState(GamepadButton::dpad_right()));
|
||||
add_button(GamepadButton::dpad_left());
|
||||
add_button(GamepadButton::dpad_right());
|
||||
} else {
|
||||
_buttons.push_back(ButtonState(GamepadButton::hat_left()));
|
||||
_buttons.push_back(ButtonState(GamepadButton::hat_right()));
|
||||
add_button(GamepadButton::hat_left());
|
||||
add_button(GamepadButton::hat_right());
|
||||
}
|
||||
axis = Axis::none;
|
||||
}
|
||||
@ -241,11 +241,11 @@ open_device() {
|
||||
_dpad_y_axis = i;
|
||||
_dpad_up_button = (int)_buttons.size();
|
||||
if (_device_class == DC_gamepad) {
|
||||
_buttons.push_back(ButtonState(GamepadButton::dpad_up()));
|
||||
_buttons.push_back(ButtonState(GamepadButton::dpad_down()));
|
||||
add_button(GamepadButton::dpad_up());
|
||||
add_button(GamepadButton::dpad_down());
|
||||
} else {
|
||||
_buttons.push_back(ButtonState(GamepadButton::hat_up()));
|
||||
_buttons.push_back(ButtonState(GamepadButton::hat_down()));
|
||||
add_button(GamepadButton::hat_up());
|
||||
add_button(GamepadButton::hat_down());
|
||||
}
|
||||
axis = Axis::none;
|
||||
}
|
||||
@ -259,28 +259,28 @@ open_device() {
|
||||
axis = Axis::none;
|
||||
break;
|
||||
}
|
||||
_controls[i].axis = axis;
|
||||
_axes[i].axis = axis;
|
||||
|
||||
if (axis == Axis::left_trigger || axis == Axis::right_trigger) {
|
||||
// We'd like to use 0.0 to indicate the resting position.
|
||||
_controls[i]._scale = 1.0 / 65534.0;
|
||||
_controls[i]._bias = 0.5;
|
||||
_axes[i]._scale = 1.0 / 65534.0;
|
||||
_axes[i]._bias = 0.5;
|
||||
have_analog_triggers = true;
|
||||
} else if (axis == Axis::left_y || axis == Axis::right_y || axis == Axis::y) {
|
||||
_controls[i]._scale = 1.0 / -32767.0;
|
||||
_controls[i]._bias = 0.0;
|
||||
_axes[i]._scale = 1.0 / -32767.0;
|
||||
_axes[i]._bias = 0.0;
|
||||
} else {
|
||||
_controls[i]._scale = 1.0 / 32767.0;
|
||||
_controls[i]._bias = 0.0;
|
||||
_axes[i]._scale = 1.0 / 32767.0;
|
||||
_axes[i]._bias = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_ltrigger_button >= 0 && _rtrigger_button >= 0 && !have_analog_triggers) {
|
||||
// Emulate analog triggers.
|
||||
_ltrigger_control = (int)_controls.size();
|
||||
add_control(Axis::left_trigger, 0, 1, false);
|
||||
add_control(Axis::right_trigger, 0, 1, false);
|
||||
_ltrigger_control = (int)_axes.size();
|
||||
add_axis(Axis::left_trigger, 0, 1, false);
|
||||
add_axis(Axis::right_trigger, 0, 1, false);
|
||||
} else {
|
||||
_ltrigger_button = -1;
|
||||
_rtrigger_button = -1;
|
||||
@ -343,8 +343,8 @@ open_device() {
|
||||
// are all 0, which indicates that the driver hasn't received any data for
|
||||
// this gamepad yet (which means it hasn't been plugged in for this session)
|
||||
if (strncmp(name, "Xbox 360 Wireless Receiver", 26) == 0) {
|
||||
for (const auto &control : _controls) {
|
||||
if (control.state != 0.0) {
|
||||
for (const auto &control : _axes) {
|
||||
if (control.value != 0.0) {
|
||||
_is_connected = true;
|
||||
return true;
|
||||
}
|
||||
@ -398,9 +398,9 @@ process_events() {
|
||||
|
||||
if (events[i].type & JS_EVENT_BUTTON) {
|
||||
if (index == _ltrigger_button) {
|
||||
control_changed(_ltrigger_control, events[i].value);
|
||||
axis_changed(_ltrigger_control, events[i].value);
|
||||
} else if (index == _rtrigger_button) {
|
||||
control_changed(_ltrigger_control + 1, events[i].value);
|
||||
axis_changed(_ltrigger_control + 1, events[i].value);
|
||||
}
|
||||
button_changed(index, (events[i].value != 0));
|
||||
|
||||
@ -413,7 +413,7 @@ process_events() {
|
||||
button_changed(_dpad_up_button+1, events[i].value > 1000);
|
||||
}
|
||||
|
||||
control_changed(index, events[i].value);
|
||||
axis_changed(index, events[i].value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -362,11 +362,11 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, std::string name) {
|
||||
gamepad_buttons = gamepad_buttons_snes;
|
||||
}
|
||||
|
||||
// Prepare a mapping of data indices to button/control indices.
|
||||
// Prepare a mapping of data indices to button/axis indices.
|
||||
_indices.resize(caps.NumberInputDataIndices);
|
||||
|
||||
_buttons.clear();
|
||||
_controls.clear();
|
||||
_axes.clear();
|
||||
|
||||
USHORT num_button_caps = caps.NumberInputButtonCaps;
|
||||
PHIDP_BUTTON_CAPS button_caps = (PHIDP_BUTTON_CAPS)alloca(num_button_caps * sizeof(HIDP_BUTTON_CAPS));
|
||||
@ -553,17 +553,17 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, std::string name) {
|
||||
break;
|
||||
}
|
||||
|
||||
int control_index;
|
||||
int axis_index;
|
||||
if (_vendor_id == 0x044f && _product_id == 0xb108 && axis == Axis::throttle) {
|
||||
// T.Flight Hotas X throttle is reversed and can go backwards.
|
||||
control_index = add_control(axis, cap.LogicalMax, cap.LogicalMin, true);
|
||||
axis_index = add_axis(axis, cap.LogicalMax, cap.LogicalMin, true);
|
||||
} else if (!is_signed) {
|
||||
// All axes on the weird XInput-style mappings go from -1 to 1
|
||||
control_index = add_control(axis, cap.LogicalMin, cap.LogicalMax, true);
|
||||
axis_index = add_axis(axis, cap.LogicalMin, cap.LogicalMax, true);
|
||||
} else {
|
||||
control_index = add_control(axis, cap.LogicalMin, cap.LogicalMax);
|
||||
axis_index = add_axis(axis, cap.LogicalMin, cap.LogicalMax);
|
||||
}
|
||||
_indices[data_index] = Index::control(control_index, is_signed);
|
||||
_indices[data_index] = Index::axis(axis_index, is_signed);
|
||||
}
|
||||
}
|
||||
|
||||
@ -635,11 +635,11 @@ on_input(PRAWINPUT input) {
|
||||
for (ULONG di = 0; di < count; ++di) {
|
||||
if (data[di].DataIndex != _hat_data_index) {
|
||||
const Index &idx = _indices[data[di].DataIndex];
|
||||
if (idx._control >= 0) {
|
||||
if (idx._axis >= 0) {
|
||||
if (idx._signed) {
|
||||
control_changed(idx._control, (SHORT)data[di].RawValue);
|
||||
axis_changed(idx._axis, (SHORT)data[di].RawValue);
|
||||
} else {
|
||||
control_changed(idx._control, data[di].RawValue);
|
||||
axis_changed(idx._axis, data[di].RawValue);
|
||||
}
|
||||
}
|
||||
if (idx._button >= 0) {
|
||||
|
@ -49,28 +49,28 @@ private:
|
||||
// Indexed by report ID
|
||||
pvector<BitArray> _report_buttons;
|
||||
|
||||
// Either a button index or a control index.
|
||||
// Either a button index or a axis index.
|
||||
struct Index {
|
||||
Index() : _button(-1), _control(-1) {}
|
||||
Index() : _button(-1), _axis(-1) {}
|
||||
|
||||
static Index button(int index) {
|
||||
Index idx;
|
||||
idx._button = index;
|
||||
return idx;
|
||||
}
|
||||
static Index control(int index, bool is_signed=true) {
|
||||
static Index axis(int index, bool is_signed=true) {
|
||||
Index idx;
|
||||
idx._control = index;
|
||||
idx._axis = index;
|
||||
idx._signed = is_signed;
|
||||
return idx;
|
||||
}
|
||||
|
||||
int _button;
|
||||
int _control;
|
||||
int _axis;
|
||||
bool _signed;
|
||||
};
|
||||
|
||||
// Maps a "data index" to either button index or control index.
|
||||
// Maps a "data index" to either button index or axis index.
|
||||
pvector<Index> _indices;
|
||||
int _hat_data_index;
|
||||
int _hat_data_minimum;
|
||||
|
@ -126,7 +126,7 @@ XInputDevice(DWORD user_index) :
|
||||
|
||||
nassertv(user_index >= 0 && user_index < XUSER_MAX_COUNT);
|
||||
|
||||
_controls.resize(6);
|
||||
_axes.resize(6);
|
||||
_buttons.resize(16);
|
||||
}
|
||||
|
||||
@ -301,6 +301,7 @@ init_xinput() {
|
||||
|
||||
/**
|
||||
* Initializes the device. Called when the device was just connected.
|
||||
* Assumes either the lock is held or this is called from the constructor.
|
||||
*/
|
||||
void XInputDevice::
|
||||
init_device(const XINPUT_CAPABILITIES_EX &caps, const XINPUT_STATE &state) {
|
||||
@ -315,81 +316,81 @@ init_device(const XINPUT_CAPABILITIES_EX &caps, const XINPUT_STATE &state) {
|
||||
default:
|
||||
case XINPUT_DEVSUBTYPE_GAMEPAD:
|
||||
_device_class = DC_gamepad;
|
||||
set_control_map(0, Axis::left_trigger);
|
||||
set_control_map(1, Axis::right_trigger);
|
||||
set_control_map(2, Axis::left_x);
|
||||
set_control_map(3, Axis::left_y);
|
||||
set_control_map(4, Axis::right_x);
|
||||
set_control_map(5, Axis::right_y);
|
||||
_axes[0].axis = Axis::left_trigger;
|
||||
_axes[1].axis = Axis::right_trigger;
|
||||
_axes[2].axis = Axis::left_x;
|
||||
_axes[3].axis = Axis::left_y;
|
||||
_axes[4].axis = Axis::right_x;
|
||||
_axes[5].axis = Axis::right_y;
|
||||
break;
|
||||
|
||||
case XINPUT_DEVSUBTYPE_WHEEL:
|
||||
_device_class = DC_steering_wheel;
|
||||
set_control_map(0, Axis::brake);
|
||||
set_control_map(1, Axis::accelerator);
|
||||
set_control_map(2, Axis::wheel);
|
||||
set_control_map(3, Axis::none);
|
||||
set_control_map(4, Axis::none);
|
||||
set_control_map(5, Axis::none);
|
||||
_axes[0].axis = Axis::brake;
|
||||
_axes[1].axis = Axis::accelerator;
|
||||
_axes[2].axis = Axis::wheel;
|
||||
_axes[3].axis = Axis::none;
|
||||
_axes[4].axis = Axis::none;
|
||||
_axes[5].axis = Axis::none;
|
||||
break;
|
||||
|
||||
case XINPUT_DEVSUBTYPE_FLIGHT_STICK:
|
||||
_device_class = DC_flight_stick;
|
||||
set_control_map(0, Axis::yaw);
|
||||
set_control_map(1, Axis::throttle);
|
||||
set_control_map(2, Axis::roll);
|
||||
set_control_map(3, Axis::pitch);
|
||||
set_control_map(4, Axis::none);
|
||||
set_control_map(5, Axis::none);
|
||||
_axes[0].axis = Axis::yaw;
|
||||
_axes[1].axis = Axis::throttle;
|
||||
_axes[2].axis = Axis::roll;
|
||||
_axes[3].axis = Axis::pitch;
|
||||
_axes[4].axis = Axis::none;
|
||||
_axes[5].axis = Axis::none;
|
||||
break;
|
||||
|
||||
case XINPUT_DEVSUBTYPE_DANCE_PAD:
|
||||
_device_class = DC_dance_pad;
|
||||
set_control_map(0, Axis::none);
|
||||
set_control_map(1, Axis::none);
|
||||
set_control_map(2, Axis::none);
|
||||
set_control_map(3, Axis::none);
|
||||
set_control_map(4, Axis::none);
|
||||
set_control_map(5, Axis::none);
|
||||
_axes[0].axis = Axis::none;
|
||||
_axes[1].axis = Axis::none;
|
||||
_axes[2].axis = Axis::none;
|
||||
_axes[3].axis = Axis::none;
|
||||
_axes[4].axis = Axis::none;
|
||||
_axes[5].axis = Axis::none;
|
||||
break;
|
||||
}
|
||||
|
||||
_controls[0]._scale = 1.0 / 255.0;
|
||||
_controls[1]._scale = 1.0 / 255.0;
|
||||
_controls[2]._scale = 1.0 / 32767.5;
|
||||
_controls[3]._scale = 1.0 / 32767.5;
|
||||
_controls[4]._scale = 1.0 / 32767.5;
|
||||
_controls[5]._scale = 1.0 / 32767.5;
|
||||
_axes[0]._scale = 1.0 / 255.0;
|
||||
_axes[1]._scale = 1.0 / 255.0;
|
||||
_axes[2]._scale = 1.0 / 32767.5;
|
||||
_axes[3]._scale = 1.0 / 32767.5;
|
||||
_axes[4]._scale = 1.0 / 32767.5;
|
||||
_axes[5]._scale = 1.0 / 32767.5;
|
||||
|
||||
_controls[2]._bias = 0.5 / 32767.5;
|
||||
_controls[3]._bias = 0.5 / 32767.5;
|
||||
_controls[4]._bias = 0.5 / 32767.5;
|
||||
_controls[5]._bias = 0.5 / 32767.5;
|
||||
_axes[2]._bias = 0.5 / 32767.5;
|
||||
_axes[3]._bias = 0.5 / 32767.5;
|
||||
_axes[4]._bias = 0.5 / 32767.5;
|
||||
_axes[5]._bias = 0.5 / 32767.5;
|
||||
|
||||
if (caps.Flags & XINPUT_CAPS_NO_NAVIGATION) {
|
||||
set_button_map(0, ButtonHandle::none());
|
||||
set_button_map(1, ButtonHandle::none());
|
||||
set_button_map(2, ButtonHandle::none());
|
||||
set_button_map(3, ButtonHandle::none());
|
||||
set_button_map(4, ButtonHandle::none());
|
||||
set_button_map(5, ButtonHandle::none());
|
||||
_buttons[0].handle = ButtonHandle::none();
|
||||
_buttons[1].handle = ButtonHandle::none();
|
||||
_buttons[2].handle = ButtonHandle::none();
|
||||
_buttons[3].handle = ButtonHandle::none();
|
||||
_buttons[4].handle = ButtonHandle::none();
|
||||
_buttons[5].handle = ButtonHandle::none();
|
||||
} else {
|
||||
set_button_map(0, GamepadButton::dpad_up());
|
||||
set_button_map(1, GamepadButton::dpad_down());
|
||||
set_button_map(2, GamepadButton::dpad_left());
|
||||
set_button_map(3, GamepadButton::dpad_right());
|
||||
set_button_map(4, GamepadButton::start());
|
||||
set_button_map(5, GamepadButton::back());
|
||||
_buttons[0].handle = GamepadButton::dpad_up();
|
||||
_buttons[1].handle = GamepadButton::dpad_down();
|
||||
_buttons[2].handle = GamepadButton::dpad_left();
|
||||
_buttons[3].handle = GamepadButton::dpad_right();
|
||||
_buttons[4].handle = GamepadButton::start();
|
||||
_buttons[5].handle = GamepadButton::back();
|
||||
}
|
||||
set_button_map(6, GamepadButton::lstick());
|
||||
set_button_map(7, GamepadButton::rstick());
|
||||
set_button_map(8, GamepadButton::lshoulder());
|
||||
set_button_map(9, GamepadButton::rshoulder());
|
||||
set_button_map(10, GamepadButton::guide());
|
||||
set_button_map(11, GamepadButton::face_a());
|
||||
set_button_map(12, GamepadButton::face_b());
|
||||
set_button_map(13, GamepadButton::face_x());
|
||||
set_button_map(14, GamepadButton::face_y());
|
||||
_buttons[6].handle = GamepadButton::lstick();
|
||||
_buttons[7].handle = GamepadButton::rstick();
|
||||
_buttons[8].handle = GamepadButton::lshoulder();
|
||||
_buttons[9].handle = GamepadButton::rshoulder();
|
||||
_buttons[10].handle = GamepadButton::guide();
|
||||
_buttons[11].handle = GamepadButton::face_a();
|
||||
_buttons[12].handle = GamepadButton::face_b();
|
||||
_buttons[13].handle = GamepadButton::face_x();
|
||||
_buttons[14].handle = GamepadButton::face_y();
|
||||
|
||||
if (caps.Vibration.wLeftMotorSpeed != 0 ||
|
||||
caps.Vibration.wRightMotorSpeed != 0) {
|
||||
@ -403,8 +404,8 @@ init_device(const XINPUT_CAPABILITIES_EX &caps, const XINPUT_STATE &state) {
|
||||
batt.BatteryType != BATTERY_TYPE_WIRED) {
|
||||
// This device has a battery. Report the battery level.
|
||||
_flags |= IDF_has_battery;
|
||||
_battery_level = batt.BatteryLevel;
|
||||
_max_battery_level = BATTERY_LEVEL_FULL;
|
||||
_battery_data.level = batt.BatteryLevel;
|
||||
_battery_data.max_level = BATTERY_LEVEL_FULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -413,7 +414,7 @@ init_device(const XINPUT_CAPABILITIES_EX &caps, const XINPUT_STATE &state) {
|
||||
WORD mask = 1;
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
// Set the state without triggering a button event.
|
||||
_buttons[i].state = (buttons & mask) ? S_down : S_up;
|
||||
_buttons[i]._state = (buttons & mask) ? S_down : S_up;
|
||||
mask <<= 1;
|
||||
if (i == 10) {
|
||||
// XInput skips 0x0800.
|
||||
@ -421,12 +422,12 @@ init_device(const XINPUT_CAPABILITIES_EX &caps, const XINPUT_STATE &state) {
|
||||
}
|
||||
}
|
||||
|
||||
control_changed(0, state.Gamepad.bLeftTrigger);
|
||||
control_changed(1, state.Gamepad.bRightTrigger);
|
||||
control_changed(2, state.Gamepad.sThumbLX);
|
||||
control_changed(3, state.Gamepad.sThumbLY);
|
||||
control_changed(4, state.Gamepad.sThumbRX);
|
||||
control_changed(5, state.Gamepad.sThumbRY);
|
||||
axis_changed(0, state.Gamepad.bLeftTrigger);
|
||||
axis_changed(1, state.Gamepad.bRightTrigger);
|
||||
axis_changed(2, state.Gamepad.sThumbLX);
|
||||
axis_changed(3, state.Gamepad.sThumbLY);
|
||||
axis_changed(4, state.Gamepad.sThumbRX);
|
||||
axis_changed(5, state.Gamepad.sThumbRY);
|
||||
|
||||
_last_buttons = buttons;
|
||||
_last_packet = state.dwPacketNumber;
|
||||
@ -491,12 +492,12 @@ do_poll() {
|
||||
}
|
||||
}
|
||||
|
||||
control_changed(0, state.Gamepad.bLeftTrigger);
|
||||
control_changed(1, state.Gamepad.bRightTrigger);
|
||||
control_changed(2, state.Gamepad.sThumbLX);
|
||||
control_changed(3, state.Gamepad.sThumbLY);
|
||||
control_changed(4, state.Gamepad.sThumbRX);
|
||||
control_changed(5, state.Gamepad.sThumbRY);
|
||||
axis_changed(0, state.Gamepad.bLeftTrigger);
|
||||
axis_changed(1, state.Gamepad.bRightTrigger);
|
||||
axis_changed(2, state.Gamepad.sThumbLX);
|
||||
axis_changed(3, state.Gamepad.sThumbLY);
|
||||
axis_changed(4, state.Gamepad.sThumbRX);
|
||||
axis_changed(5, state.Gamepad.sThumbRY);
|
||||
|
||||
_last_buttons = state.Gamepad.wButtons;
|
||||
_last_packet = state.dwPacketNumber;
|
||||
|
@ -100,13 +100,7 @@ vrpn_analog_callback(void *userdata, const vrpn_ANALOGCB info) {
|
||||
for (di = self->_devices.begin(); di != self->_devices.end(); ++di) {
|
||||
VrpnAnalogDevice *device = (*di);
|
||||
for (int i = 0; i < info.num_channel; i++) {
|
||||
if (vrpn_cat.is_debug()) {
|
||||
if (device->get_control_state(i) != info.channel[i]) {
|
||||
vrpn_cat.debug()
|
||||
<< *self << " got analog " << i << " = " << info.channel[i] << "\n";
|
||||
}
|
||||
}
|
||||
device->set_control_state(i, info.channel[i]);
|
||||
device->set_axis_value(i, info.channel[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -107,10 +107,10 @@ vrpn_position_callback(void *userdata, const vrpn_TRACKERCB info) {
|
||||
VrpnTrackerDevice *device = (*di);
|
||||
if (device->get_sensor() == info.sensor &&
|
||||
device->get_data_type() == VrpnTrackerDevice::DT_position) {
|
||||
device->set_tracker(LPoint3(info.pos[0], info.pos[1], info.pos[2]),
|
||||
LOrientation(info.quat[3], info.quat[0],
|
||||
info.quat[1], info.quat[2]),
|
||||
VrpnClient::convert_to_secs(info.msg_time));
|
||||
device->tracker_changed(LPoint3(info.pos[0], info.pos[1], info.pos[2]),
|
||||
LOrientation(info.quat[3], info.quat[0],
|
||||
info.quat[1], info.quat[2]),
|
||||
VrpnClient::convert_to_secs(info.msg_time));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -132,10 +132,10 @@ vrpn_velocity_callback(void *userdata, const vrpn_TRACKERVELCB info) {
|
||||
VrpnTrackerDevice *device = (*di);
|
||||
if (device->get_sensor() == info.sensor &&
|
||||
device->get_data_type() == VrpnTrackerDevice::DT_velocity) {
|
||||
device->set_tracker(LPoint3(info.vel[0], info.vel[1], info.vel[2]),
|
||||
LOrientation(info.vel_quat[3], info.vel_quat[0],
|
||||
info.vel_quat[1], info.vel_quat[2]),
|
||||
VrpnClient::convert_to_secs(info.msg_time));
|
||||
device->tracker_changed(LPoint3(info.vel[0], info.vel[1], info.vel[2]),
|
||||
LOrientation(info.vel_quat[3], info.vel_quat[0],
|
||||
info.vel_quat[1], info.vel_quat[2]),
|
||||
VrpnClient::convert_to_secs(info.msg_time));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -157,10 +157,10 @@ vrpn_acceleration_callback(void *userdata, const vrpn_TRACKERACCCB info) {
|
||||
VrpnTrackerDevice *device = (*di);
|
||||
if (device->get_sensor() == info.sensor &&
|
||||
device->get_data_type() == VrpnTrackerDevice::DT_acceleration) {
|
||||
device->set_tracker(LPoint3(info.acc[0], info.acc[1], info.acc[2]),
|
||||
LOrientation(info.acc_quat[3], info.acc_quat[0],
|
||||
info.acc_quat[1], info.acc_quat[2]),
|
||||
VrpnClient::convert_to_secs(info.msg_time));
|
||||
device->tracker_changed(LPoint3(info.acc[0], info.acc[1], info.acc[2]),
|
||||
LOrientation(info.acc_quat[3], info.acc_quat[0],
|
||||
info.acc_quat[1], info.acc_quat[2]),
|
||||
VrpnClient::convert_to_secs(info.msg_time));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user