Joystick in Windows

I had a question about a C extension I once have written, for wrapping up joystick input under Windows
(https://discourse.panda3d.org/viewtopic.php?t=2270).

I still can provide a compiled version for Python 2.5 if anybody is interested, but there is another way to get joystick input: using the ctypes module. Advantage: no need to compile any C/C++ code.

enn0x

test.py

import joystick
import time

print 'num joysticks:', joystick.Joystick.getNumJosticks( )

j = joystick.Joystick( 0 )

print 'j num axes:', j.numAxes( )
print 'j num buttons:', j.numButtons( )
print 'j name:', ( j.name( ), )

while 1:
  time.sleep( 0.2 )

  j.update( )

  x = j.getX( )
  y = j.getY( )
  z = j.getZ( )
  r = j.getR( )

  pov = j.getPOV( )

  b0 = j.getButton( 0 )
  b1 = j.getButton( 1 )
  b2 = j.getButton( 2 )
  b3 = j.getButton( 3 )

  print x, y, z, r, pov, b0, b1, b2, b3

  #print [ j.getButton( i ) for i in range( j.numButtons( ) ) ]

joystick.py

from ctypes import *

winmm = windll.winmm

class JOYINFOEX( Structure ):
  _pack_ = 1
  _fields_ = [ ( 'dwSize', c_long ),
               ( 'dwFlags', c_long ),
               ( 'dwXpos', c_long ),
               ( 'dwYpos', c_long ),
               ( 'dwZpos', c_long ),
               ( 'dwRpos', c_long ),
               ( 'dwUpos', c_long ),
               ( 'dwVpos', c_long ),
               ( 'dwButtons', c_long ),
               ( 'dwButtonNumber', c_long ),
               ( 'dwPOV', c_long ),
               ( 'dwReserved1', c_long ),
               ( 'dwReserved2', c_long ),
             ]

class JOYCAPSA( Structure ):
  _pack_ = 1
  _fields_ = [ ( 'wMid', c_short ),
               ( 'wPid', c_short ),
               ( 'szPname', c_char * 32 ),
               ( 'wXmin', c_uint ),
               ( 'wXmax', c_uint ),
               ( 'wYmin', c_uint ),
               ( 'wYmax', c_uint ),
               ( 'wZmin', c_uint ),
               ( 'wZmax', c_uint ),
               ( 'wNumButtons', c_uint ),
               ( 'wPeriodMin', c_uint ),
               ( 'wPeriodMax', c_uint ),
               ( 'wRmin', c_uint ),
               ( 'wRmax', c_uint ),
               ( 'wUmin', c_uint ),
               ( 'wUmax', c_uint ),
               ( 'wVmin', c_uint ),
               ( 'wVmax', c_uint ),
               ( 'wCaps', c_uint ),
               ( 'wMaxAxes', c_uint ),
               ( 'wNumAxes', c_uint ),
               ( 'wMaxButtons', c_uint ),
               ( 'szRegKey', c_char * 32 ),
               ( 'szOEMVxD', c_char * 260 ),
             ]

class Joystick:

  def __init__( self, id ):
    self.jid = c_uint( id )

    self.info = JOYINFOEX( )
    self.info.dwFlags = c_long( 255 )
    self.info.dwSize = sizeof( self.info ) * 8

  @staticmethod
  def getNumJosticks( ):
    nmax = winmm.joyGetNumDevs( );
    n = 0

    for i in range( nmax ):
      result = winmm.joyGetPos( c_uint( i ), byref( JOYINFOEX( ) ) )
      if result == 0:
        n += 1

    return n

  @staticmethod
  def parametric( x ):
    if x < 32767: x -= 32768
    else:         x -= 32767
    return float( x ) / 32768.0

  def update( self ):
    winmm.joyGetPosEx( self.jid, byref( self.info ) )

  def getX( self ):
    return self.parametric( self.info.dwXpos )

  def getY( self ):
    return self.parametric( self.info.dwYpos )

  def getZ( self ):
    return self.parametric( self.info.dwZpos )

  def getR( self ):
    return self.parametric( self.info.dwRpos )

  def getU( self ):
    return self.parametric( self.info.dwUpos )

  def getV( self ):
    return self.parametric( self.info.dwVpos )

  def getPOV( self ):
    return self.info.dwPOV / 100

  def getButton( self, btn ):
    state = self.info.dwButtons & ( 1 << btn )
    return state and True or False

  def caps( self ):
    caps = JOYCAPSA( )
    capssize = c_uint( sizeof( caps ) * 8 )
    capssize = c_uint( 404 )
    result = winmm.joyGetDevCapsA( self.jid, byref( caps ), capssize )
    return caps

  def numAxes( self ):
    return self.caps( ).wNumAxes

  def numButtons( self ):
    return self.caps( ).wNumButtons

  def name( self ):
    return self.caps( ).szPname

Thank you very much. This is a much easier solution that depending on your C++ module :smiley: