2009-02-07
A few years ago, I converted a Nintendo NES gamepad to a USB gamepad, using a hardware chip from Raphnet, in order to control an MPD frontend that I wrote using Pygame. Fast forward to the present...... While working on my new media player application, I needed a way to receive joystick events but I didn't want to include the Pygame library just for joystick support. Thus was born the need for a python gobject joystick class.
Where is it? I looked all over the inter-tubes and couldn't find what I needed.
A bit of the old "clickity click click" on the keyboard ( a quite a bit on documentation reading ) and I came up with:
It still needs a bit of work, not all of the button/axis init signals are emitted when the class is started. The remaining init signals are sent on the first button press or axis movement. All in all, it fits my needs wonderfully.
Where is it? I looked all over the inter-tubes and couldn't find what I needed.
A bit of the old "clickity click click" on the keyboard ( a quite a bit on documentation reading ) and I came up with:
''' Copyright 2009 Jezra Lickter This software is distributed AS IS. Use at your own risk. If it borks your system, you have been forewarned. This software is licensed under the LGPL Version 3 http://www.gnu.org/licenses/lgpl-3.0.txt for documentation on Linux Joystick programming please see http://www.mjmwired.net/kernel/Documentation/input/joystick-api.txt ''' import gobject #needed for sending signals import struct #needed for holding chunks of data class Joystick(gobject.GObject): '''The Joystick class is a GObject that sends signals that represent Joystick events''' EVENT_BUTTON = 0x01 #button pressed/released EVENT_AXIS = 0x02 #axis moved EVENT_INIT = 0x80 #button/axis initialized #see http://docs.python.org/library/struct.html for the format determination EVENT_FORMAT = "IhBB" EVENT_SIZE = struct.calcsize(EVENT_FORMAT) # we need a few signals to send data to the main '''signals will return 4 variables as follows: 1. a string representing if the signal is from an axis or a button 2. an integer representation of a particular button/axis 3. an integer representing axis direction or button press/release 4. an integer representing the "init" of the button/axis ''' __gsignals__ = { 'axis' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_INT,gobject.TYPE_INT,gobject.TYPE_INT)), 'button' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_INT,gobject.TYPE_INT,gobject.TYPE_INT)) } def __init__(self,dev_num): gobject.GObject.__init__(self) #define the device device = '/dev/input/js%s' % dev_num #error check that this can be read try: #open the joystick device self.device = open(device) #keep an eye on the device, when there is data to read, execute the read function gobject.io_add_watch(self.device,gobject.IO_IN,self.read_buttons) except Exception,ex: #raise an exception raise Exception( ex ) def read_buttons(self, arg0='', arg1=''): ''' read the button and axis press event from the joystick device and emit a signal containing the event data ''' #read self.EVENT_SIZE bytes from the joystick read_event = self.device.read(self.EVENT_SIZE) #get the event structure values from the read event time, value, type, number = struct.unpack(self.EVENT_FORMAT, read_event) #get just the button/axis press event from the event type event = type & ~self.EVENT_INIT #get just the INIT event from the event type init = type & ~event if event == self.EVENT_AXIS: signal = "axis" elif event == self.EVENT_BUTTON: signal = "button" if signal: print("%s %s %s %s" % (signal,number,value,init) ) self.emit(signal,number,value,init) return True if __name__ == "__main__": try: j = Joystick(0) loop = gobject.MainLoop() loop.run() except Exception,e: print(e)
It still needs a bit of work, not all of the button/axis init signals are emitted when the class is started. The remaining init signals are sent on the first button press or axis movement. All in all, it fits my needs wonderfully.
Any suggestions on how I might achieve this as I cannot for the life of me see how !
http://www.pygtk.org/pygtk2reference/gobject-functions.html#function-gobject--timeout-add