Jump To …

js.py

import pygame
from pygame.locals import *
import time
import sys

class Js:
  def __init__(self):
    pygame.display.init()   # pygame.init() may block audio
    self.js_number = 0
    self.loop_delay = 0.001
    self.hathit_threshold = 0.1/self.loop_delay
    self.ax_threshold = .0001
    self.event_types = ['axis', 'hat', 'button', 'init', 'run', 'stop']
    self.event_listeners = {}
    for event_type in self.event_types:
      self.event_listeners[event_type] = [] 

  def auto_hathit_threshold(self):
    self.hathit_threshold = 0.1/self.loop_delay

events have an event_type and a tuple e of event values

  def event(self, event_type, e):
    for l in self.event_listeners[event_type]:
      l(event_type, e)

  def add_event_listener(self, event_type, listener):
    self.event_listeners[event_type].append(listener)
    return len(self.event_listeners[event_type]) - 1

  def set_joystick_number(self, js_number):
    self.js_number = js_number

  def init(self):

Choose and initialize the joystick

    pygame.joystick.init()
    self.js = pygame.joystick.Joystick(self.js_number)
    self.js.init()
    self.js_name = self.js.get_name()

initialize axes

    self.ax = []
    self.num_axes = self.js.get_numaxes()
    for i in range(self.num_axes):

should probably use getaxes here and initialize with actual axis values

      self.ax.append(self.js.get_axis(i))

initialize buttons

    self.button_states = []
    self.numbuttons = self.js.get_numbuttons()
    for i in range(self.numbuttons):
      self.button_states.append(self.js.get_button(i))

initialize hats. Hats always have two axes, so hat events return the hat number, the axis number, and the value (+/-1).

    self.numhats = self.js.get_numhats()

report out final configuration

    config = {}
    for i in ['js_number', 'js_name', 'loop_delay', 'ax_threshold', 
        'hathit_threshold']:
      config[i] = self.__dict__[i]
    self.event('init', config)

  def run(self):

don't forget to send out initial values

    hathit = False
    while True:
      pygame.event.pump()

debounced hats

      if hathit == True:
        self.hathittimer = self.hathittimer + 1
        if self.hathittimer > self.hathit_threshold:
          hathit = False
      else:
        for i in range(self.numhats):
          hat = self.js.get_hat(i)
          if hat[0] or hat[1]:
            hathit = True
            self.hathittimer = 0
            for j in range(2):
              if hat[j] != 0:
                self.event('hat', (i, j, hat[j]))

axes

      for i in range(4):
        ax = self.js.get_axis(i)

watch the step size on axis change

        if abs(ax - self.ax[i]) > self.ax_threshold:
          self.event('axis', (i, ax, self.ax[i]))
          self.ax[i] = ax

buttons

      for i in range(self.numbuttons):
        bu = self.js.get_button(i)

was false, now true

        if bu: 
          if not self.button_states[i]:
            self.event('button', (i, bu, self.button_states[i]))
            self.button_states[i] = bu

was true, now false

        else:
          if self.button_states[i]:
            self.event('button', (i, bu, self.button_states[i]))
            self.button_states[i] = bu

      time.sleep(self.loop_delay)

  def stop(self):
    self.js.quit()
    self.display.quit()