BGE Joystick Sensor

- Raised limit of 2 axis to 4 axis pairs (4==8 joysticks axis pairs)
- Added a new Joystick Sensor type "Single Axis", so you can detect horizontal or vertical movement, rather then just Up/Down/Left/Right
- added Python attribute "axisSingle" so you can get the value from the selected axis (rather then getting it out of the axis list)
- renamed Py attribute "axisPosition" to "axisValues" (was never in a release)

If we need to increase the axis limit again just change JOYAXIS_MAX and the button limits.
This commit is contained in:
Campbell Barton 2009-04-07 06:23:45 +00:00
parent 816a9f3acb
commit 885fa49aa4
10 changed files with 172 additions and 170 deletions

@ -166,7 +166,8 @@ typedef struct bJoystickSensor {
char type;
char joyindex;
short flag;
int axis;
short axis;
short axis_single;
int axisf;
int button;
int hat;
@ -255,20 +256,22 @@ typedef struct bJoystickSensor {
#define SENS_JOY_ANY_EVENT 1
#define SENS_JOY_BUTTON 0
#define SENS_JOY_BUTTON 0 /* axis type */
#define SENS_JOY_BUTTON_PRESSED 0
#define SENS_JOY_BUTTON_RELEASED 1
#define SENS_JOY_AXIS 1
#define SENS_JOY_AXIS 1 /* axis type */
#define SENS_JOY_X_AXIS 0
#define SENS_JOY_Y_AXIS 1
#define SENS_JOY_NEG_X_AXIS 2
#define SENS_JOY_NEG_Y_AXIS 3
#define SENS_JOY_PRECISION 4
#define SENS_JOY_HAT 2
#define SENS_JOY_HAT 2 /* axis type */
#define SENS_JOY_HAT_DIR 0
#define SENS_JOY_AXIS_SINGLE 3 /* axis type */
#define SENS_DELAY_REPEAT 1
// should match JOYINDEX_MAX in SCA_JoystickDefines.h */

@ -1457,32 +1457,33 @@ static short draw_sensorbuttons(bSensor *sens, uiBlock *block, short xco, short
&joy->joyindex, 0, SENS_JOY_MAXINDEX-1, 100, 0,
"Specify which joystick to use");
str= "Type %t|Button %x0|Axis %x1|Hat%x2";
str= "Type %t|Button %x0|Axis %x1|Single Axis %x3|Hat%x2";
uiDefButC(block, MENU, B_REDR, str, xco+87, yco-44, 0.26 * (width-20), 19,
&joy->type, 0, 31, 0, 0,
"The type of event this joystick sensor is triggered on.");
if (joy->flag & SENS_JOY_ANY_EVENT) {
switch (joy->type) {
case SENS_JOY_AXIS:
str = "All Axis Events";
break;
case SENS_JOY_BUTTON:
str = "All Button Events";
break;
default:
str = "All Hat Events";
break;
if (joy->type != SENS_JOY_AXIS_SINGLE) {
if (joy->flag & SENS_JOY_ANY_EVENT) {
switch (joy->type) {
case SENS_JOY_AXIS:
str = "All Axis Events";
break;
case SENS_JOY_BUTTON:
str = "All Button Events";
break;
default:
str = "All Hat Events";
break;
}
} else {
str = "All";
}
} else {
str = "All";
uiDefButBitS(block, TOG, SENS_JOY_ANY_EVENT, B_REDR, str,
xco+10 + 0.475 * (width-20), yco-68, ((joy->flag & SENS_JOY_ANY_EVENT) ? 0.525 : 0.12) * (width-20), 19,
&joy->flag, 0, 0, 0, 0,
"Triggered by all events on this joysticks current type (axis/button/hat)");
}
uiDefButBitS(block, TOG, SENS_JOY_ANY_EVENT, B_REDR, str,
xco+10 + 0.475 * (width-20), yco-68, ((joy->flag & SENS_JOY_ANY_EVENT) ? 0.525 : 0.12) * (width-20), 19,
&joy->flag, 0, 0, 0, 0,
"Triggered by all events on this joysticks current type (axis/button/hat)");
if(joy->type == SENS_JOY_BUTTON)
{
if ((joy->flag & SENS_JOY_ANY_EVENT)==0) {
@ -1493,8 +1494,8 @@ static short draw_sensorbuttons(bSensor *sens, uiBlock *block, short xco, short
}
else if(joy->type == SENS_JOY_AXIS)
{
uiDefButI(block, NUM, 1, "Number:", xco+10, yco-68, 0.46 * (width-20), 19,
&joy->axis, 1, 2.0, 100, 0,
uiDefButS(block, NUM, 1, "Number:", xco+10, yco-68, 0.46 * (width-20), 19,
&joy->axis, 1, 4.0, 100, 0,
"Specify which axis pair to use, 1 is useually the main direction input.");
uiDefButI(block, NUM, 1, "Threshold:", xco+10 + 0.6 * (width-20),yco-44, 0.4 * (width-20), 19,
@ -1508,7 +1509,7 @@ static short draw_sensorbuttons(bSensor *sens, uiBlock *block, short xco, short
"The direction of the axis, use 'All Events' to recieve events on any direction");
}
}
else
else if (joy->type == SENS_JOY_HAT)
{
uiDefButI(block, NUM, 1, "Number:", xco+10, yco-68, 0.46 * (width-20), 19,
&joy->hat, 1, 2.0, 100, 0,
@ -1520,6 +1521,15 @@ static short draw_sensorbuttons(bSensor *sens, uiBlock *block, short xco, short
"Specify hat direction");
}
}
else { /* (joy->type == SENS_JOY_AXIS_SINGLE)*/
uiDefButS(block, NUM, 1, "Number:", xco+10, yco-68, 0.46 * (width-20), 19,
&joy->axis_single, 1, 8.0, 100, 0,
"Specify a single axis (verticle/horizontal/other) to detect");
uiDefButI(block, NUM, 1, "Threshold:", xco+10 + 0.6 * (width-20),yco-44, 0.4 * (width-20), 19,
&joy->precision, 0, 32768.0, 100, 0,
"Specify the precision of the axis");
}
yco-= ysize;
break;
}

@ -708,6 +708,11 @@ void BL_ConvertSensors(struct Object* blenderobject,
hatf = bjoy->hatf;
joysticktype = SCA_JoystickSensor::KX_JOYSENSORMODE_HAT;
break;
case SENS_JOY_AXIS_SINGLE:
axis = bjoy->axis_single;
prec = bjoy->precision;
joysticktype = SCA_JoystickSensor::KX_JOYSENSORMODE_AXIS_SINGLE;
break;
default:
printf("Error: bad case statement\n");
break;

@ -36,21 +36,19 @@
SCA_Joystick::SCA_Joystick(short int index)
:
m_joyindex(index),
m_axis10(0),
m_axis11(0),
m_axis20(0),
m_axis21(0),
m_prec(3200),
m_buttonnum(-2),
m_axismax(-1),
m_hatdir(-2),
m_buttonmax(-1),
m_hatmax(-1),
m_hatdir(-2),
m_isinit(0),
m_istrig_axis(0),
m_istrig_button(0),
m_istrig_hat(0)
{
for(int i=0; i<JOYAXIS_MAX; i++)
m_axis_array[i]= 0;
#ifndef DISABLE_SDL
m_private = new PrivateData();
#endif
@ -125,47 +123,30 @@ void SCA_Joystick::cSetPrecision(int val)
}
bool SCA_Joystick::aAnyAxisIsPositive(int axis)
bool SCA_Joystick::aAxisPairIsPositive(int axis)
{
bool result;
int res = pAxisTest(axis);
res > m_prec? result = true: result = false;
return result;
return (pAxisTest(axis) > m_prec) ? true:false;
}
bool SCA_Joystick::aRightAxisIsPositive(int axis)
bool SCA_Joystick::aAxisPairDirectionIsPositive(int axis, int dir)
{
bool result;
int res = pGetAxis(axis,1);
res > m_prec? result = true: result = false;
return result;
int res;
if (dir==JOYAXIS_UP || dir==JOYAXIS_DOWN)
res = pGetAxis(axis, 1);
else /* JOYAXIS_LEFT || JOYAXIS_RIGHT */
res = pGetAxis(axis, 0);
if (dir==JOYAXIS_DOWN || dir==JOYAXIS_RIGHT)
return (res > m_prec) ? true : false;
else /* JOYAXIS_UP || JOYAXIS_LEFT */
return (res < -m_prec) ? true : false;
}
bool SCA_Joystick::aUpAxisIsPositive(int axis)
bool SCA_Joystick::aAxisIsPositive(int axis_single)
{
bool result;
int res = pGetAxis(axis,0);
res < -m_prec? result = true : result = false;
return result;
}
bool SCA_Joystick::aLeftAxisIsPositive(int axis)
{
bool result;
int res = pGetAxis(axis,1);
res < -m_prec ? result = true : result = false;
return result;
}
bool SCA_Joystick::aDownAxisIsPositive(int axis)
{
bool result;
int res = pGetAxis(axis,0);
res > m_prec ? result = true:result = false;
return result;
return abs(m_axis_array[axis_single]) > m_prec ? true:false;
}
bool SCA_Joystick::aAnyButtonPressIsPositive(void)
@ -255,8 +236,12 @@ bool SCA_Joystick::CreateJoystickDevice(void)
/* must run after being initialized */
m_axismax = SDL_JoystickNumAxes(m_private->m_joystick);
if (m_axismax > JOYAXIS_MAX) m_axismax= JOYAXIS_MAX; /* very unlikely */
m_buttonmax = SDL_JoystickNumButtons(m_private->m_joystick);
m_hatmax = SDL_JoystickNumHats(m_private->m_joystick);
}
return true;
#endif
@ -288,17 +273,8 @@ int SCA_Joystick::Connected(void)
void SCA_Joystick::pFillAxes()
{
#ifndef DISABLE_SDL
if(m_axismax == 1){
m_axis10 = SDL_JoystickGetAxis(m_private->m_joystick, 0);
m_axis11 = SDL_JoystickGetAxis(m_private->m_joystick, 1);
}else if(m_axismax > 1){
m_axis10 = SDL_JoystickGetAxis(m_private->m_joystick, 0);
m_axis11 = SDL_JoystickGetAxis(m_private->m_joystick, 1);
m_axis20 = SDL_JoystickGetAxis(m_private->m_joystick, 2);
m_axis21 = SDL_JoystickGetAxis(m_private->m_joystick, 3);
}else{
m_axis10 = m_axis11 = m_axis20 = m_axis21 = 0;
}
for(int i=0; i<m_axismax; i++)
m_axis_array[i]= SDL_JoystickGetAxis(m_private->m_joystick, i);
#endif
}
@ -306,10 +282,7 @@ void SCA_Joystick::pFillAxes()
int SCA_Joystick::pGetAxis(int axisnum, int udlr)
{
#ifndef DISABLE_SDL
if(axisnum == 1 && udlr == 1)return m_axis10; //u/d
if(axisnum == 1 && udlr == 0)return m_axis11; //l/r
if(axisnum == 2 && udlr == 0)return m_axis20; //...
if(axisnum == 2 && udlr == 1)return m_axis21;
return m_axis_array[(axisnum*2)+udlr];
#endif
return 0;
}
@ -317,13 +290,9 @@ int SCA_Joystick::pGetAxis(int axisnum, int udlr)
int SCA_Joystick::pAxisTest(int axisnum)
{
#ifndef DISABLE_SDL
short i1,i2;
if(axisnum == 1) {
i1 = m_axis10; i2 = m_axis11;
}
else if(axisnum == 2) {
i1 = m_axis20; i2 = m_axis21;
}
short i1= m_axis_array[(axisnum*2)];
short i2= m_axis_array[(axisnum*2)+1];
/* long winded way to do
* return MAX2(abs(i1), abs(i2))
* avoid abs from math.h */
@ -335,4 +304,3 @@ int SCA_Joystick::pAxisTest(int axisnum)
return 0;
#endif
}

@ -55,10 +55,8 @@ class SCA_Joystick
/*
*support for 2 axes
*/
int m_axis10,m_axis11;
int m_axis20,m_axis21;
int m_axis_array[JOYAXIS_MAX];
/*
* Precision or range of the axes
*/
@ -120,7 +118,10 @@ class SCA_Joystick
void OnButtonUp(SDL_Event *sdl_event);
void OnButtonDown(SDL_Event *sdl_event);
void OnNothing(SDL_Event *sdl_event);
#if 0 /* not used yet */
void OnBallMotion(SDL_Event *sdl_event){}
#endif
#endif
/*
* Open the joystick
@ -139,12 +140,12 @@ class SCA_Joystick
void pFillButtons(void);
/*
* returns m_axis10,m_axis11...
* returns m_axis_array
*/
int pAxisTest(int axisnum);
/*
* returns m_axis10,m_axis11...
* returns m_axis_array
*/
int pGetAxis(int axisnum, int udlr);
@ -166,11 +167,9 @@ public:
/*
*/
bool aAnyAxisIsPositive(int axis);
bool aUpAxisIsPositive(int axis);
bool aDownAxisIsPositive(int axis);
bool aLeftAxisIsPositive(int axis);
bool aRightAxisIsPositive(int axis);
bool aAxisPairIsPositive(int axis);
bool aAxisPairDirectionIsPositive(int axis, int dir); /* function assumes joysticks are in axis pairs */
bool aAxisIsPositive(int axis_single); /* check a single axis only */
bool aAnyButtonPressIsPositive(void);
bool aAnyButtonReleaseIsPositive(void);
@ -184,24 +183,10 @@ public:
void cSetPrecision(int val);
int GetAxis10(void){
return m_axis10;
int GetAxisPosition(int index){
return m_axis_array[index];
}
int GetAxis11(void){
return m_axis11;
}
int GetAxis20(void){
return m_axis20;
}
int GetAxis21(void){
return m_axis21;
}
int GetButton(void){
return m_buttonnum;
}

@ -39,5 +39,11 @@
#endif
#define JOYINDEX_MAX 8
#define JOYAXIS_MAX 8
#define JOYAXIS_RIGHT 0
#define JOYAXIS_UP 1
#define JOYAXIS_DOWN 3
#define JOYAXIS_LEFT 2
#endif

@ -68,7 +68,7 @@ void SCA_Joystick::OnButtonUp(SDL_Event* sdl_event)
void SCA_Joystick::OnButtonDown(SDL_Event* sdl_event)
{
if(sdl_event->jbutton.button >= 0 || sdl_event->jbutton.button <= m_buttonmax)
if(sdl_event->jbutton.button <= m_buttonmax) /* unsigned int so always above 0 */
{
m_istrig_button = 1;
m_buttonnum = sdl_event->jbutton.button;
@ -111,9 +111,11 @@ void SCA_Joystick::HandleEvents(void)
case SDL_JOYBUTTONDOWN:
SCA_Joystick::m_instance[sdl_event.jbutton.which]->OnButtonDown(&sdl_event);
break;
#if 0 /* Not used yet */
case SDL_JOYBALLMOTION:
SCA_Joystick::m_instance[sdl_event.jball.which]->OnBallMotion(&sdl_event);
break;
#endif
default:
printf("SCA_Joystick::HandleEvents, Unknown SDL event, this should not happen\n");
break;

@ -117,11 +117,15 @@ bool SCA_JoystickSensor::Evaluate(CValue* event)
case KX_JOYSENSORMODE_AXIS:
{
/* what is what!
m_axisf == 0 == right
m_axisf == JOYAXIS_RIGHT, JOYAXIS_UP, JOYAXIS_DOWN, JOYAXIS_LEFT
m_axisf == 1 == up
m_axisf == 2 == left
m_axisf == 3 == down
numberof== m_axis -- max 2
numberof== m_axis (1-4), range is half of JOYAXIS_MAX since
it assumes the axis joysticks are axis parirs (0,1), (2,3), etc
also note that this starts at 1 where functions its used
with expect a zero index.
*/
if (!js->IsTrigAxis() && !reset) /* No events from SDL? - dont bother */
@ -129,7 +133,7 @@ bool SCA_JoystickSensor::Evaluate(CValue* event)
js->cSetPrecision(m_precision);
if (m_bAllEvents) {
if(js->aAnyAxisIsPositive(m_axis)){
if(js->aAxisPairIsPositive(m_axis-1)){ /* use zero based axis index internally */
m_istrig = 1;
result = true;
}else{
@ -139,41 +143,8 @@ bool SCA_JoystickSensor::Evaluate(CValue* event)
}
}
}
else if(m_axisf == 1){
if(js->aUpAxisIsPositive(m_axis)){
m_istrig = 1;
result = true;
}else{
if(m_istrig){
m_istrig = 0;
result = true;
}
}
}
else if(m_axisf == 3){
if(js->aDownAxisIsPositive(m_axis)){
m_istrig = 1;
result = true;
}else{
if(m_istrig){
m_istrig = 0;
result = true;
}
}
}
else if(m_axisf == 2){
if(js->aLeftAxisIsPositive(m_axis)){
m_istrig = 1;
result = true;
}else{
if(m_istrig){
m_istrig = 0;
result = true;
}
}
}
else if(m_axisf == 0){
if(js->aRightAxisIsPositive(m_axis)){
else {
if(js->aAxisPairDirectionIsPositive(m_axis-1, m_axisf)){ /* use zero based axis index internally */
m_istrig = 1;
result = true;
}else{
@ -185,6 +156,26 @@ bool SCA_JoystickSensor::Evaluate(CValue* event)
}
break;
}
case KX_JOYSENSORMODE_AXIS_SINGLE:
{
/* Like KX_JOYSENSORMODE_AXIS but dont pair up axis */
if (!js->IsTrigAxis() && !reset) /* No events from SDL? - dont bother */
return false;
/* No need for 'm_bAllEvents' check here since were only checking 1 axis */
js->cSetPrecision(m_precision);
if(js->aAxisIsPositive(m_axis-1)){ /* use zero based axis index internally */
m_istrig = 1;
result = true;
}else{
if(m_istrig){
m_istrig = 0;
result = true;
}
}
break;
}
case KX_JOYSENSORMODE_BUTTON:
{
/* what is what!
@ -333,13 +324,13 @@ PyAttributeDef SCA_JoystickSensor::Attributes[] = {
KX_PYATTRIBUTE_INT_RW("button",0,100,false,SCA_JoystickSensor,m_button),
KX_PYATTRIBUTE_INT_LIST_RW_CHECK("axis",0,3,true,SCA_JoystickSensor,m_axis,2,CheckAxis),
KX_PYATTRIBUTE_INT_LIST_RW_CHECK("hat",0,12,true,SCA_JoystickSensor,m_hat,2,CheckHat),
KX_PYATTRIBUTE_RO_FUNCTION("axisPosition", SCA_JoystickSensor, pyattr_get_axis_position),
KX_PYATTRIBUTE_RO_FUNCTION("axisValues", SCA_JoystickSensor, pyattr_get_axis_values),
KX_PYATTRIBUTE_RO_FUNCTION("axisSingle", SCA_JoystickSensor, pyattr_get_axis_single),
KX_PYATTRIBUTE_RO_FUNCTION("numAxis", SCA_JoystickSensor, pyattr_get_num_axis),
KX_PYATTRIBUTE_RO_FUNCTION("numButtons", SCA_JoystickSensor, pyattr_get_num_buttons),
KX_PYATTRIBUTE_RO_FUNCTION("numHats", SCA_JoystickSensor, pyattr_get_num_hats),
KX_PYATTRIBUTE_RO_FUNCTION("connected", SCA_JoystickSensor, pyattr_get_connected),
{ NULL } //Sentinel
};
@ -420,10 +411,15 @@ const char SCA_JoystickSensor::GetAxisValue_doc[] =
PyObject* SCA_JoystickSensor::PyGetAxisValue( PyObject* self) {
ShowDeprecationWarning("getAxisValue()", "the axisPosition property");
SCA_Joystick *joy = m_pJoystickMgr->GetJoystickDevice(m_joyindex);
if(joy)
return Py_BuildValue("[iiii]", joy->GetAxis10(), joy->GetAxis11(), joy->GetAxis20(), joy->GetAxis21());
else
return Py_BuildValue("[iiii]", 0, 0, 0, 0);
int axis_index= joy->GetNumberOfAxes();
PyObject *list= PyList_New(axis_index);
while(axis_index--) {
PyList_SET_ITEM(list, axis_index, PyInt_FromLong(joy->GetAxisPosition(axis_index)));
}
return list;
}
@ -590,13 +586,32 @@ PyObject* SCA_JoystickSensor::PyConnected( PyObject* self ) {
}
PyObject* SCA_JoystickSensor::pyattr_get_axis_position(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
PyObject* SCA_JoystickSensor::pyattr_get_axis_values(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
SCA_JoystickSensor* self= static_cast<SCA_JoystickSensor*>(self_v);
SCA_Joystick *joy = self->m_pJoystickMgr->GetJoystickDevice(self->m_joyindex);
if(joy) return Py_BuildValue("[iiii]", joy->GetAxis10(), joy->GetAxis11(), joy->GetAxis20(), joy->GetAxis21());
else return Py_BuildValue("[iiii]", 0, 0, 0, 0);
int axis_index= joy->GetNumberOfAxes();
PyObject *list= PyList_New(axis_index);
while(axis_index--) {
PyList_SET_ITEM(list, axis_index, PyInt_FromLong(joy->GetAxisPosition(axis_index)));
}
return list;
}
PyObject* SCA_JoystickSensor::pyattr_get_axis_single(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
SCA_JoystickSensor* self= static_cast<SCA_JoystickSensor*>(self_v);
SCA_Joystick *joy = self->m_pJoystickMgr->GetJoystickDevice(self->m_joyindex);
if(self->m_joymode != KX_JOYSENSORMODE_AXIS_SINGLE) {
PyErr_SetString(PyExc_TypeError, "joystick sensor is not an 'Single Axis' type");
return NULL;
}
return PyInt_FromLong(joy->GetAxisPosition(self->m_axis));
}
PyObject* SCA_JoystickSensor::pyattr_get_num_axis(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)

@ -93,6 +93,7 @@ class SCA_JoystickSensor :public SCA_ISensor
KX_JOYSENSORMODE_AXIS,
KX_JOYSENSORMODE_BUTTON,
KX_JOYSENSORMODE_HAT,
KX_JOYSENSORMODE_AXIS_SINGLE,
KX_JOYSENSORMODE_MAX
};
bool isValid(KX_JOYSENSORMODE);
@ -148,7 +149,8 @@ public:
KX_PYMETHOD_DOC_NOARGS(SCA_JoystickSensor,NumberOfHats);
KX_PYMETHOD_DOC_NOARGS(SCA_JoystickSensor,Connected);
static PyObject* pyattr_get_axis_position(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
static PyObject* pyattr_get_axis_values(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
static PyObject* pyattr_get_axis_single(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
static PyObject* pyattr_get_num_axis(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
static PyObject* pyattr_get_num_buttons(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
static PyObject* pyattr_get_num_hats(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);

@ -8,10 +8,16 @@ class SCA_JoystickSensor(SCA_ISensor):
Properties:
@ivar axisPosition: (read-only) The state of the joysticks axis as a list of 4 values, each spesifying the value of an axis between -32767 and 32767 depending on how far the axis is pushed, 0 for nothing.
The first 2 values are used by most joysticks and gamepads for directional control. 3rd and 4th values are only on some joysticks and can be used for arbitary controls.
left:[-32767, 0, ...], right:[32767, 0, ...], up:[0, -32767, ...], down:[0, 32767, ...]
@type axisPosition: [integer, integer, integer, integer]
@ivar axisValues: (read-only) The state of the joysticks axis as a list of values L{numAxis} long.
each spesifying the value of an axis between -32767 and 32767 depending on how far the axis is pushed, 0 for nothing.
The first 2 values are used by most joysticks and gamepads for directional control. 3rd and 4th values are only on some joysticks and can be used for arbitary controls.
left:[-32767, 0, ...], right:[32767, 0, ...], up:[0, -32767, ...], down:[0, 32767, ...]
@type axisValues: list of ints
@ivar axisSingle: (read-only) like L{axisValues} but returns a single axis value that is set by the sensor.
Only use this for "Single Axis" type sensors otherwise it will raise an error.
@type axisSingle: int
@ivar numAxis: (read-only) The number of axes for the joystick at this index.
@type numAxis: integer
@ivar numButtons: (read-only) The number of buttons for the joystick at this index.