Skip to content

Commit fd16e34

Browse files
committed
Fix Xbox One controller on Windows, add untested support for flight sticks and steering wheels
1 parent 01e57e1 commit fd16e34

File tree

5 files changed

+224
-54
lines changed

5 files changed

+224
-54
lines changed

panda/src/device/evdevInputDevice.cxx

Lines changed: 71 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,54 @@
2323
#include <fcntl.h>
2424
#include <linux/input.h>
2525

26-
#define test_bit(bit, array) ((array)[(bit)/8] & (1<<((bit)&7)))
26+
#define test_bit(bit, array) ((array)[(bit)>>3] & (1<<((bit)&7)))
2727

2828
static InputDevice::ControlAxis axis_map[] = {
29-
InputDevice::C_left_x, InputDevice::C_left_y, InputDevice::C_left_trigger,
30-
InputDevice::C_right_x, InputDevice::C_right_y, InputDevice::C_right_trigger
29+
// ABS_X = 0x00
30+
InputDevice::C_left_x,
31+
// ABS_Y = 0x01
32+
InputDevice::C_left_y,
33+
// ABS_Z = 0x02
34+
InputDevice::C_left_trigger,
35+
// ABS_RX = 0x03
36+
InputDevice::C_right_x,
37+
// ABS_RY = 0x04
38+
InputDevice::C_right_y,
39+
// ABS_RZ = 0x05
40+
InputDevice::C_right_trigger,
41+
// ABS_THROTTLE = 0x06
42+
InputDevice::C_throttle,
43+
// ABS_RUDDER = 0x07
44+
InputDevice::C_rudder,
45+
// ABS_WHEEL = 0x08
46+
InputDevice::C_wheel,
47+
// ABS_GAS = 0x09
48+
InputDevice::C_accelerator,
49+
// ABS_BRAKE = 0x0a
50+
InputDevice::C_brake,
51+
52+
InputDevice::C_none,
53+
InputDevice::C_none,
54+
InputDevice::C_none,
55+
InputDevice::C_none,
56+
InputDevice::C_none,
57+
58+
// ABS_HAT0X = 0x10
59+
InputDevice::C_hat_x,
60+
// ABS_HAT0Y = 0x11
61+
InputDevice::C_hat_y,
62+
63+
// ABS_HAT1X = 0x12
64+
// ABS_HAT1Y = 0x13
65+
// ABS_HAT2X = 0x14
66+
// ABS_HAT2Y = 0x15
67+
// ABS_HAT3X = 0x16
68+
// ABS_HAT3Y = 0x17
69+
// ABS_PRESSURE = 0x18
70+
// ABS_DISTANCE = 0x19
71+
// ABS_TILT_X = 0x1a
72+
// ABS_TILT_Y = 0x1b
73+
// ABS_TOOL_WIDTH = 0x1c
3174
};
3275

3376
TypeHandle EvdevInputDevice::_type_handle;
@@ -189,7 +232,7 @@ init_device() {
189232
}
190233

191234
bool all_values_zero = true;
192-
bool have_dpad_buttons = false;
235+
bool emulate_dpad = true;
193236

194237
if (test_bit(EV_KEY, evtypes)) {
195238
// Check which buttons are on the device.
@@ -213,7 +256,7 @@ init_device() {
213256
_buttons[bi]._state = S_up;
214257
}
215258
if (_buttons[bi]._handle == GamepadButton::dpad_left()) {
216-
have_dpad_buttons = true;
259+
emulate_dpad = false;
217260
}
218261
++bi;
219262
}
@@ -241,6 +284,10 @@ init_device() {
241284
}
242285
}
243286

287+
if (_device_class != DC_gamepad) {
288+
emulate_dpad = false;
289+
}
290+
244291
if (test_bit(EV_ABS, evtypes)) {
245292
// Check which axes are on the device.
246293
uint8_t axes[(ABS_CNT + 7) >> 3];
@@ -254,7 +301,25 @@ init_device() {
254301
int num_bits = ioctl(_fd, EVIOCGBIT(EV_ABS, sizeof(axes)), axes) << 3;
255302
for (int i = 0; i < num_bits; ++i) {
256303
if (test_bit(i, axes)) {
257-
set_control_map(i, axis_map[i]);
304+
// Emulate D-Pad buttons if necessary.
305+
if (i > ABS_HAT0Y) {
306+
set_control_map(i, C_none);
307+
308+
} else if (i == ABS_HAT0X && emulate_dpad) {
309+
_dpad_x_axis = i;
310+
_dpad_left_button = (int)_buttons.size();
311+
_buttons.push_back(ButtonState(GamepadButton::dpad_left()));
312+
_buttons.push_back(ButtonState(GamepadButton::dpad_right()));
313+
314+
} else if (i == ABS_HAT0Y && emulate_dpad) {
315+
_dpad_y_axis = i;
316+
_dpad_up_button = (int)_buttons.size();
317+
_buttons.push_back(ButtonState(GamepadButton::dpad_up()));
318+
_buttons.push_back(ButtonState(GamepadButton::dpad_down()));
319+
320+
} else {
321+
set_control_map(i, axis_map[i]);
322+
}
258323

259324
// Check the initial value and ranges.
260325
struct input_absinfo absinfo;
@@ -284,20 +349,6 @@ init_device() {
284349
all_values_zero = false;
285350
}
286351
}
287-
288-
// Emulate D-Pad buttons if necessary.
289-
if (i == ABS_HAT0X && !have_dpad_buttons) {
290-
_dpad_x_axis = i;
291-
_dpad_left_button = (int)_buttons.size();
292-
_buttons.push_back(ButtonState(GamepadButton::dpad_left()));
293-
_buttons.push_back(ButtonState(GamepadButton::dpad_right()));
294-
}
295-
if (i == ABS_HAT0Y && !have_dpad_buttons) {
296-
_dpad_y_axis = i;
297-
_dpad_up_button = (int)_buttons.size();
298-
_buttons.push_back(ButtonState(GamepadButton::dpad_up()));
299-
_buttons.push_back(ButtonState(GamepadButton::dpad_down()));
300-
}
301352
}
302353
}
303354
}

panda/src/device/inputDevice.cxx

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,9 +170,25 @@ set_button_state(int index, bool down) {
170170
_buttons.resize(index + 1, ButtonState());
171171
}
172172

173-
_buttons[index]._state = down ? S_down : S_up;
173+
State new_state = down ? S_down : S_up;
174+
if (_buttons[index]._state == new_state) {
175+
return;
176+
}
177+
_buttons[index]._state = new_state;
174178

175179
ButtonHandle handle = _buttons[index]._handle;
180+
181+
if (device_cat.is_spam()) {
182+
device_cat.spam()
183+
<< "Changed button " << index;
184+
185+
if (handle != ButtonHandle::none()) {
186+
device_cat.spam(false) << " (" << handle << ")";
187+
}
188+
189+
device_cat.spam(false) << " to " << (down ? "down" : "up") << "\n";
190+
}
191+
176192
if (handle != ButtonHandle::none()) {
177193
_button_events->add_event(ButtonEvent(handle, down ? ButtonEvent::T_down : ButtonEvent::T_up));
178194
}
@@ -192,7 +208,7 @@ set_control_state(int index, double state) {
192208
_controls.resize(index + 1, AnalogState());
193209
}
194210

195-
if (device_cat.is_spam()) {
211+
if (device_cat.is_spam() && _controls[index]._state != state) {
196212
device_cat.spam()
197213
<< "Changed control " << index;
198214

panda/src/device/inputDevice.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ class EXPCL_PANDA_DEVICE InputDevice : public TypedReferenceCount {
7373

7474
DC_flight_stick,
7575
DC_steering_wheel,
76+
DC_dance_pad,
77+
78+
// Head-mounted display.
79+
DC_hmd,
7680
};
7781

7882
protected:
@@ -101,6 +105,14 @@ class EXPCL_PANDA_DEVICE InputDevice : public TypedReferenceCount {
101105
C_y,
102106
C_trigger,
103107
C_throttle,
108+
C_rudder,
109+
C_hat_x,
110+
C_hat_y,
111+
112+
// Steering wheel / pedals
113+
C_wheel,
114+
C_accelerator,
115+
C_brake,
104116
};
105117

106118
INLINE string get_name() const;

panda/src/device/linuxJoystickDevice.cxx

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -257,26 +257,50 @@ open_device() {
257257
axis = C_right_trigger;
258258
break;
259259

260+
case ABS_THROTTLE:
261+
axis = InputDevice::C_throttle;
262+
break;
263+
264+
case ABS_RUDDER:
265+
axis = InputDevice::C_rudder;
266+
break;
267+
268+
case ABS_WHEEL:
269+
axis = InputDevice::C_wheel;
270+
break;
271+
272+
case ABS_GAS:
273+
axis = InputDevice::C_accelerator;
274+
break;
275+
276+
case ABS_BRAKE:
277+
axis = InputDevice::C_brake;
278+
break;
279+
260280
case ABS_HAT0X:
261-
if (_dpad_left_button == -1) {
281+
if (_dpad_left_button == -1 && _device_class == DC_gamepad) {
262282
// Emulate D-Pad.
263283
_dpad_x_axis = i;
264284
_dpad_left_button = (int)_buttons.size();
265285
_buttons.push_back(ButtonState(GamepadButton::dpad_left()));
266286
_buttons.push_back(ButtonState(GamepadButton::dpad_right()));
287+
axis = C_none;
288+
} else {
289+
axis = C_hat_x;
267290
}
268-
axis = C_none;
269291
break;
270292

271293
case ABS_HAT0Y:
272-
if (_dpad_up_button == -1) {
294+
if (_dpad_up_button == -1 && _device_class == DC_gamepad) {
273295
// Emulate D-Pad.
274296
_dpad_y_axis = i;
275297
_dpad_up_button = (int)_buttons.size();
276298
_buttons.push_back(ButtonState(GamepadButton::dpad_up()));
277299
_buttons.push_back(ButtonState(GamepadButton::dpad_down()));
300+
axis = C_none;
301+
} else {
302+
axis = C_hat_y;
278303
}
279-
axis = C_none;
280304
break;
281305

282306
default:

0 commit comments

Comments
 (0)