mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-02 09:52:27 -04:00
input: let InputDevice manage axis remapping, add C_twist axis
This commit is contained in:
parent
ef9803b25e
commit
12cfc93b79
@ -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:
|
||||
|
@ -44,12 +44,6 @@ private:
|
||||
int _ff_strong;
|
||||
int _ff_weak;
|
||||
|
||||
struct AxisRange {
|
||||
double _scale;
|
||||
double _bias;
|
||||
};
|
||||
pvector<AxisRange> _axis_ranges;
|
||||
|
||||
// These are used for D-pad emulation.
|
||||
int _dpad_x_axis;
|
||||
int _dpad_y_axis;
|
||||
|
@ -461,6 +461,8 @@ INLINE InputDevice::AnalogState::
|
||||
AnalogState() :
|
||||
axis(C_none),
|
||||
state(0.0),
|
||||
known(false)
|
||||
known(false),
|
||||
_scale(1.0),
|
||||
_bias(0.0)
|
||||
{
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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<AnalogState> Controls;
|
||||
Controls _controls;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user