Skip to content

Instantly share code, notes, and snippets.

@sraboy
Forked from rdb/js_linux.py
Last active October 1, 2018 15:17
Show Gist options
  • Save sraboy/2d9177fa0791b6953bb48d192997d679 to your computer and use it in GitHub Desktop.
Save sraboy/2d9177fa0791b6953bb48d192997d679 to your computer and use it in GitHub Desktop.
Access joysticks/game controllers from Python in Linux via the joystick driver. See https://www.panda3d.org/forums/viewtopic.php?f=8&t=16767
# Released by rdb under the Unlicense (unlicense.org)
# Modified for N64 controller from https://gist.github.com/rdb/8864666
import os, struct, array
from fcntl import ioctl
# Iterate over the joystick devices.
print('Available devices:')
for fn in os.listdir('/dev/input'):
if fn.startswith('js'):
print(' /dev/input/%s' % (fn))
# We'll store the states here.
axis_states = {}
button_states = {}
# These constants were borrowed from linux/input.h
axis_names = {
0x00 : 'x',
0x01 : 'y',
0x02 : 'z',
0x03 : 'rx',
0x04 : 'ry',
0x05 : 'rz',
}
button_names = {
0x120 : 'C-Up',
0x121 : 'C-Right',
0x122 : 'C-Down',
0x123 : 'C-Left',
#
# ignore so we don't unintentionally register two hits
#
0x124 : 'A',
0x125 : 'B',
0x126 : 'L',
0x127 : 'R',
0x128 : 'A',
0x129 : 'B',
0x12a : 'Z (trigger)',
0x12b : 'Start',
0x12c : 'Up',
0x12d : 'Right',
0x12e : 'Down',
0x12f : 'Left',
}
axis_map = []
button_map = []
# Open the joystick device.
fn = '/dev/input/js0'
print('Opening %s...' % fn)
jsdev = open(fn, 'rb')
# Get the device name.
#buf = bytearray(63)
buf = array.array('c', ['\0'] * 64)
ioctl(jsdev, 0x80006a13 + (0x10000 * len(buf)), buf) # JSIOCGNAME(len)
js_name = buf.tostring()
print('Device name: %s' % js_name)
# Get number of axes and buttons.
buf = array.array('B', [0])
ioctl(jsdev, 0x80016a11, buf) # JSIOCGAXES
num_axes = buf[0]
buf = array.array('B', [0])
ioctl(jsdev, 0x80016a12, buf) # JSIOCGBUTTONS
num_buttons = buf[0]
# Get the axis map.
buf = array.array('B', [0] * 0x40)
ioctl(jsdev, 0x80406a32, buf) # JSIOCGAXMAP
for axis in buf[:num_axes]:
axis_name = axis_names.get(axis, 'unknown(0x%02x)' % axis)
axis_map.append(axis_name)
axis_states[axis_name] = 0.0
# Get the button map.
buf = array.array('H', [0] * 200)
ioctl(jsdev, 0x80406a34, buf) # JSIOCGBTNMAP
for btn in buf[:num_buttons]:
btn_name = button_names.get(btn, 'unknown(0x%03x)' % btn)
button_map.append(btn_name)
button_states[btn_name] = 0
print '%d axes found: %s' % (num_axes, ', '.join(axis_map))
print '%d buttons found: %s' % (num_buttons, ', '.join(button_map))
# Main event loop
while True:
evbuf = jsdev.read(8)
if evbuf:
time, value, type, number = struct.unpack('IhBB', evbuf)
if type & 0x80:
print "(initial)",
if type & 0x01:
button = button_map[number]
if button:
button_states[button] = value
if value:
print "%s pressed" % (button)
else:
print "%s released" % (button)
if type & 0x02:
axis = axis_map[number]
if axis:
fvalue = value / 32767.0
axis_states[axis] = fvalue
print "%s: %.3f" % (axis, fvalue)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment