Wilbert's website at SocSci

> Software> Python> Hardware> Joystick

computer/joystick.html 2019-04-05

Joystick in Python

Low level, Linux and other unices except osx

#!/usr/bin/python2
import struct
with open("/dev/input/js0", "rb") as f:
	while True:
		a = f.read(8)
		t, value, code, index = struct.unpack("<Ihbb", a) # 4 bytes, 2 bytes, 1 byte, 1 byte
		# t: time in ms
		# index: button/axis number (0 for x-axis)
		# code: 1 for buttons, 2 for axis
		# value: axis position, 0 for center, 1 for buttonpress, 0 for button release
		print("t: {:10d} ms, value: {:6d}, code: {:1d}, index: {:1d}".format(t, value, code, index))

Psychopy, all OSes

#!/usr/bin/python
from __future__ import print_function
import sys
from psychopy.hardware import joystick
from psychopy import visual

#init
joystick.backend = 'pygame' # must match the Window
win = visual.Window([400,400], winType=joystick.backend)

j = joystick.Joystick(0)

while True:
	win.flip() # flipping updates the joystick info
	val = ["{:6.3f}".format(i) for i in j.getAllAxes()]
	buttons = [int(i) for i in j.getAllButtons()]
	print("val: {}, {}".format(val, buttons), end='\r')
	sys.stdout.flush()

Note that you can use either 'pygame' or 'pyglet' as value for joystick.backend and winType. With Psychopy version 1.84.2 on OSX only 'pygame' will work. Otherwise you get the error:

AttributeError: 'PygletDevice' object has no attribute 'dispatch_events'
as decribed in this post. Note that it is similar to a problem with the same Psychopy version on windows which has a workaround described here as 'problem 2'.

Pyglet, all OSes

#!/usr/bin/python
import pyglet

window = pyglet.window.Window(width=400, height=400)

# open first joystick
joysticks = pyglet.input.get_joysticks()  # requires pyglet 1.2
if joysticks:
	joystick = joysticks[0]
else:
	print("ERROR: no joystick")
	exit()
joystick.open()

@window.event
def on_draw():
	window.clear()

@window.event
def on_key_press(symbol, modifiers):
	print("keypress")
	print("query based joystick position: {}".format(joystick.x))
	
@joystick.event
def on_joybutton_press(joystick, button):
	print("event based joystick response")

pyglet.app.run()

Pyglet, in Psychopy

You can also use the Pyglet functions directly in Psychopy. Note the opening and closing of the joystick in the event loop. This can be used as a workaround in osx, and is not generally the preferred method. This method may not work at all.

#!/usr/bin/python
import pyglet
from psychopy import visual

#init
win = visual.Window([400,400], winType='pyglet')
text = visual.TextStim(win, "")
joysticks = pyglet.input.get_joysticks()  # requires pyglet 1.2
j = joysticks[0]
j.open()


while True:
    j.close()
    j.open()
    text.text = "{:6.3f}, {:6.3f}".format(j.x, j.y)
    text.draw()
    win.flip()