diff --git a/panda/src/device/evdevInputDevice.cxx b/panda/src/device/evdevInputDevice.cxx index ca2247c012..21ce8d2fa1 100644 --- a/panda/src/device/evdevInputDevice.cxx +++ b/panda/src/device/evdevInputDevice.cxx @@ -371,17 +371,10 @@ init_device() { } if (has_axes) { - AxisRange range; - range._scale = 1.0; - range._bias = 0.0; - _axis_ranges.resize(ABS_CNT, range); - - for (int i = 0; i < num_bits; ++i) { if (test_bit(i, axes)) { + ControlAxis axis = C_none; if (i >= ABS_HAT0X) { - set_control_map(i, C_none); - // Emulate D-Pad buttons if necessary. if (i == ABS_HAT0X && emulate_dpad) { _dpad_x_axis = i; @@ -395,38 +388,25 @@ init_device() { _buttons.push_back(ButtonState(GamepadButton::dpad_up())); _buttons.push_back(ButtonState(GamepadButton::dpad_down())); } else if (i == ABS_HAT0X) { - set_control_map(i, C_hat_x); + axis = C_hat_x; } else if (i == ABS_HAT0Y) { - set_control_map(i, C_hat_y); + axis = C_hat_y; } } else { - set_control_map(i, axis_map[i]); + axis = axis_map[i]; //cerr << "Axis " << axis_map[i] << " is mapped by the driver to " << i << "\n"; } // Check the initial value and ranges. struct input_absinfo absinfo; if (ioctl(_fd, EVIOCGABS(i), &absinfo) >= 0) { - double factor, bias; - if (absinfo.minimum < 0) { - // Centered, eg. for sticks. - factor = 2.0 / (absinfo.maximum - absinfo.minimum); - bias = (absinfo.maximum + absinfo.minimum) / (double)(absinfo.minimum - absinfo.maximum); - } else { - // 0-based, eg. for triggers. - factor = 1.0 / absinfo.maximum; - bias = 0.0; - } - // Flip Y axis to match Windows implementation. if (i == ABS_Y || i == ABS_RY) { - factor = -factor; - bias = -bias; + swap(absinfo.minimum, absinfo.maximum); } - _axis_ranges[i]._scale = factor; - _axis_ranges[i]._bias = bias; - _controls[i].state = fma(absinfo.value, factor, bias); + add_control(axis, absinfo.minimum, absinfo.maximum); + control_changed(axis, absinfo.value); if (absinfo.value != 0) { all_values_zero = false; @@ -562,13 +542,13 @@ process_events() { case EV_ABS: if (code == _dpad_x_axis) { - set_button_state(_dpad_left_button, events[i].value < 0); - set_button_state(_dpad_left_button+1, events[i].value > 0); + button_changed(_dpad_left_button, events[i].value < 0); + button_changed(_dpad_left_button+1, events[i].value > 0); } else if (code == _dpad_y_axis) { - set_button_state(_dpad_up_button, events[i].value < 0); - set_button_state(_dpad_up_button+1, events[i].value > 0); + button_changed(_dpad_up_button, events[i].value < 0); + button_changed(_dpad_up_button+1, events[i].value > 0); } - set_control_state(code, fma(events[i].value, _axis_ranges[code]._scale, _axis_ranges[code]._bias)); + control_changed(code, events[i].value); break; case EV_KEY: diff --git a/panda/src/device/evdevInputDevice.h b/panda/src/device/evdevInputDevice.h index 5a604b8617..849d72ae27 100644 --- a/panda/src/device/evdevInputDevice.h +++ b/panda/src/device/evdevInputDevice.h @@ -44,12 +44,6 @@ private: int _ff_strong; int _ff_weak; - struct AxisRange { - double _scale; - double _bias; - }; - pvector _axis_ranges; - // These are used for D-pad emulation. int _dpad_x_axis; int _dpad_y_axis; diff --git a/panda/src/device/inputDevice.I b/panda/src/device/inputDevice.I index b512b973a8..c10ba4a172 100644 --- a/panda/src/device/inputDevice.I +++ b/panda/src/device/inputDevice.I @@ -461,6 +461,8 @@ INLINE InputDevice::AnalogState:: AnalogState() : axis(C_none), state(0.0), - known(false) + known(false), + _scale(1.0), + _bias(0.0) { } diff --git a/panda/src/device/inputDevice.cxx b/panda/src/device/inputDevice.cxx index eae889bd1b..a5b1f1cd45 100644 --- a/panda/src/device/inputDevice.cxx +++ b/panda/src/device/inputDevice.cxx @@ -114,6 +114,45 @@ get_pointer_events() { return result; } + +/** + * Called by the implementation to add a new known control. + */ +void InputDevice:: +add_control(ControlAxis axis, int minimum, int maximum, bool centered) { + AnalogState state; + state.axis = axis; + if (centered) { + // Centered, eg. for sticks. + state._scale = 2.0 / (maximum - minimum); + state._bias = (maximum + minimum) / (double)(minimum - maximum); + } else { + // 0-based, eg. for triggers. + state._scale = 1.0 / maximum; + state._bias = 0.0; + } + _controls.push_back(state); +} + +/** + * Called by the implementation to add a new known control. This version + * tries to guess whether the control is centered or not. + */ +void InputDevice:: +add_control(ControlAxis axis, int minimum, int maximum) { + bool centered = (minimum < 0) + || axis == C_left_x + || axis == C_left_y + || axis == C_right_x + || axis == C_right_y + || axis == C_x + || axis == C_y + || axis == C_wheel + || axis == C_twist + || axis == C_rudder; + add_control(axis, minimum, maximum, centered); +} + /** * Records that a mouse movement has taken place. */ @@ -165,6 +204,11 @@ pointer_moved(double x, double y, double time) { _pointer_data._xpos += x; _pointer_data._ypos += y; + if (device_cat.is_spam() && (x != 0 || y != 0)) { + device_cat.spam() + << "Pointer moved by " << x << " x " << y << "\n"; + } + if (_enable_pointer_events) { int seq = _event_sequence++; if (_pointer_events.is_null()) { @@ -184,7 +228,7 @@ pointer_moved(double x, double y, double time) { * while this call is made. */ void InputDevice:: -set_button_state(int index, bool down) { +button_changed(int index, bool down) { nassertv(_lock.debug_is_locked()); nassertv(index >= 0); if (index >= (int)_buttons.size()) { @@ -244,6 +288,34 @@ set_control_state(int index, double state) { _controls[index].known = true; } +/** + * Like set_control_state, but instead passes a raw, unscaled value. + */ +void InputDevice:: +control_changed(int index, int state) { + nassertv(_lock.debug_is_locked()); + nassertv(index >= 0); + if (index >= (int)_controls.size()) { + _controls.resize(index + 1, AnalogState()); + } + + double new_state = fma((double)state, _controls[index]._scale, _controls[index]._bias); + + if (device_cat.is_spam() && _controls[index].state != new_state) { + device_cat.spam() + << "Changed control " << index; + + if (_controls[index].axis != C_none) { + device_cat.spam(false) << " (" << _controls[index].axis << ")"; + } + + device_cat.spam(false) << " to " << new_state << " (raw value " << state << ")\n"; + } + + _controls[index].state = new_state; + _controls[index].known = true; +} + /** * Records that a tracker movement has taken place. */ @@ -467,6 +539,9 @@ operator << (ostream &out, InputDevice::DeviceClass dc) { case InputDevice::DC_hmd: out << "hmd"; break; + + case InputDevice::DC_COUNT: + break; } return out; } @@ -518,6 +593,10 @@ operator << (ostream &out, InputDevice::ControlAxis axis) { out << "throttle"; break; + case InputDevice::C_twist: + out << "twist"; + break; + case InputDevice::C_rudder: out << "rudder"; break; diff --git a/panda/src/device/inputDevice.h b/panda/src/device/inputDevice.h index 67b6084b77..7f0e459bc3 100644 --- a/panda/src/device/inputDevice.h +++ b/panda/src/device/inputDevice.h @@ -108,6 +108,7 @@ PUBLISHED: C_y, C_trigger, C_throttle, + C_twist, C_rudder, C_hat_x, C_hat_y, @@ -183,11 +184,18 @@ PUBLISHED: virtual void output(ostream &out) const; protected: + // Called during the constructor to add new controls or buttons + void add_control(ControlAxis axis, int minimum, int maximum, bool centered); + void add_control(ControlAxis 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 set_button_state(int index, bool down); + void button_changed(int index, bool down); + void control_changed(int index, int value); void set_control_state(int index, double state); + void set_tracker(const LPoint3 &pos, const LOrientation &orient, double time); virtual void do_set_vibration(double low, double high); @@ -271,6 +279,10 @@ PUBLISHED: ControlAxis axis; double state; bool known; + + public: + double _scale; + double _bias; }; typedef pvector Controls; Controls _controls; diff --git a/panda/src/device/linuxJoystickDevice.cxx b/panda/src/device/linuxJoystickDevice.cxx index fc2e2ba7b1..8cd612f2d7 100644 --- a/panda/src/device/linuxJoystickDevice.cxx +++ b/panda/src/device/linuxJoystickDevice.cxx @@ -322,6 +322,18 @@ open_device() { break; } _controls[i].axis = axis; + + if (axis == C_left_trigger || axis == C_right_trigger || axis == C_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; + } else if (axis == C_left_y || axis == C_right_y || axis == C_y) { + _controls[i]._scale = 1.0 / -32767.0; + _controls[i]._bias = 0.0; + } else { + _controls[i]._scale = 1.0 / 32767.0; + _controls[i]._bias = 0.0; + } } } @@ -436,27 +448,18 @@ process_events() { int index = events[i].number; if (events[i].type & JS_EVENT_BUTTON) { - set_button_state(index, (events[i].value != 0)); + button_changed(index, (events[i].value != 0)); } else if (events[i].type & JS_EVENT_AXIS) { if (index == _dpad_x_axis) { - set_button_state(_dpad_left_button, events[i].value < -1000); - set_button_state(_dpad_left_button+1, events[i].value > 1000); + button_changed(_dpad_left_button, events[i].value < -1000); + button_changed(_dpad_left_button+1, events[i].value > 1000); } else if (index == _dpad_y_axis) { - set_button_state(_dpad_up_button, events[i].value < -1000); - set_button_state(_dpad_up_button+1, events[i].value > 1000); + button_changed(_dpad_up_button, events[i].value < -1000); + button_changed(_dpad_up_button+1, events[i].value > 1000); } - ControlAxis axis = _controls[index].axis; - - if (axis == C_left_trigger || axis == C_right_trigger || axis == C_trigger) { - // We'd like to use 0.0 to indicate the resting position. - set_control_state(index, (events[i].value + 32767) / 65534.0); - } else if (axis == C_left_y || axis == C_right_y || axis == C_y) { - set_control_state(index, events[i].value / -32767.0); - } else { - set_control_state(index, events[i].value / 32767.0); - } + control_changed(index, events[i].value); } } diff --git a/panda/src/device/xInputDevice.cxx b/panda/src/device/xInputDevice.cxx index d6832adee3..04d88996f5 100644 --- a/panda/src/device/xInputDevice.cxx +++ b/panda/src/device/xInputDevice.cxx @@ -290,6 +290,18 @@ init_device(const XINPUT_CAPABILITIES &caps, const XINPUT_STATE &state) { 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; + + _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; + if (caps.Flags & XINPUT_CAPS_NO_NAVIGATION) { set_button_map(0, ButtonHandle::none()); set_button_map(1, ButtonHandle::none()); @@ -387,12 +399,12 @@ init_device(const XINPUT_CAPABILITIES &caps, const XINPUT_STATE &state) { } } - 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); + 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); _last_buttons = buttons; _last_packet = state.dwPacketNumber; @@ -453,7 +465,7 @@ do_poll() { WORD mask = 1; for (int i = 0; i < 16; ++i) { if (changed_buttons & mask) { - set_button_state(i, (state.Gamepad.wButtons & mask) != 0); + button_changed(i, (state.Gamepad.wButtons & mask) != 0); } mask <<= 1; if (i == 10) { @@ -462,12 +474,12 @@ 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 + 0.5) / 32767.5); - set_control_state(3, (state.Gamepad.sThumbLY + 0.5) / 32767.5); - set_control_state(4, (state.Gamepad.sThumbRX + 0.5) / 32767.5); - set_control_state(5, (state.Gamepad.sThumbRY + 0.5) / 32767.5); + 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); _last_buttons = state.Gamepad.wButtons; _last_packet = state.dwPacketNumber; diff --git a/panda/src/vrpn/vrpnButton.cxx b/panda/src/vrpn/vrpnButton.cxx index c1505619d8..60aff640e7 100644 --- a/panda/src/vrpn/vrpnButton.cxx +++ b/panda/src/vrpn/vrpnButton.cxx @@ -103,6 +103,6 @@ vrpn_button_callback(void *userdata, const vrpn_BUTTONCB info) { Devices::iterator di; for (di = self->_devices.begin(); di != self->_devices.end(); ++di) { VrpnButtonDevice *device = (*di); - device->set_button_state(info.button, info.state != 0); + device->button_changed(info.button, info.state != 0); } }