Under Linux OIS drops joystick events! This is especially annoying when a button press event is evaluated, but the respective release is dropped, in which case that button gets stuck. But it also makes axis input sluggish.
The bug is that OIS doesn't follow the described practice from the Linux documentation, which demands that the input buffer
always gets fully emptied, which is signaled by return value -1 from read(). Increasing the input buffer doesn't hurt either. The kernel's input buffer has room for 64 events ATM, and that's only 1536 bytes in a 64 bit system.
The buffer should really get allocated in the constructor to avoid needless memory fragmentation. I left that as it is because getting patches in seems next to impossible already now, and the shorter the better. (Is OIS even still maintained?! It sure doesn't look like it!)
Index: includes/linux/LinuxPrereqs.h
===================================================================
--- includes/linux/LinuxPrereqs.h (revision 13)
+++ includes/linux/LinuxPrereqs.h (working copy)
@@ -31,7 +31,7 @@
#include "OISPrereqs.h"
//! Max number of elements to collect from buffered input
-#define JOY_BUFFERSIZE 10
+#define JOY_BUFFERSIZE 64
namespace OIS
{
The following patch is
not to be committed. It was done with
diff -uw to ignore all white-space changes, so that you can see it's really trivial. See below for the actual patch.
Index: src/linux/LinuxJoyStickEvents.cpp
===================================================================
--- src/linux/LinuxJoyStickEvents.cpp (revision 13)
+++ src/linux/LinuxJoyStickEvents.cpp (working copy)
@@ -95,9 +95,10 @@
//We are in non blocking mode - we just read once, and try to fill up buffer
input_event js[JOY_BUFFERSIZE];
+ while(1) {
int ret = read(mJoyStick, &js, sizeof(struct input_event) * JOY_BUFFERSIZE);
- if( ret <= 0 )
- return;
+ if( ret < 0 )
+ break;
//Determine how many whole events re read up
ret /= sizeof(struct input_event);
@@ -197,6 +198,7 @@
default: break;
}
}
+ }
//All axes and POVs are combined into one movement per pair per captured frame
if( mBuffered && mListener )
Here's the full patch. It's only big because of the changed indentation.
Index: includes/linux/LinuxPrereqs.h
===================================================================
--- includes/linux/LinuxPrereqs.h (revision 13)
+++ includes/linux/LinuxPrereqs.h (working copy)
@@ -31,7 +31,7 @@
#include "OISPrereqs.h"
//! Max number of elements to collect from buffered input
-#define JOY_BUFFERSIZE 10
+#define JOY_BUFFERSIZE 64
namespace OIS
{
Index: src/linux/LinuxJoyStickEvents.cpp
===================================================================
--- src/linux/LinuxJoyStickEvents.cpp (revision 13)
+++ src/linux/LinuxJoyStickEvents.cpp (working copy)
@@ -95,107 +95,109 @@
//We are in non blocking mode - we just read once, and try to fill up buffer
input_event js[JOY_BUFFERSIZE];
- int ret = read(mJoyStick, &js, sizeof(struct input_event) * JOY_BUFFERSIZE);
- if( ret <= 0 )
- return;
+ while(1) {
+ int ret = read(mJoyStick, &js, sizeof(struct input_event) * JOY_BUFFERSIZE);
+ if( ret < 0 )
+ break;
- //Determine how many whole events re read up
- ret /= sizeof(struct input_event);
- for(int i = 0; i < ret; ++i)
- {
- switch(js[i].type)
+ //Determine how many whole events re read up
+ ret /= sizeof(struct input_event);
+ for(int i = 0; i < ret; ++i)
{
- case EV_KEY: //Button
- {
- int button = mButtonMap[js[i].code];
-
- #ifdef OIS_LINUX_JOY_DEBUG
- cout << "\nButton Code: " << js[i].code << ", OIS Value: " << button << endl;
- #endif
-
- //Check to see whether push or released event...
- if(js[i].value)
+ switch(js[i].type)
{
- mState.mButtons[button] = true;
- if( mBuffered && mListener )
- if(!mListener->buttonPressed(JoyStickEvent(this,mState), button)) return;
- }
- else
+ case EV_KEY: //Button
{
- mState.mButtons[button] = false;
- if( mBuffered && mListener )
- if(!mListener->buttonReleased(JoyStickEvent(this,mState), button)) return;
- }
- break;
- }
+ int button = mButtonMap[js[i].code];
- case EV_ABS: //Absolute Axis
- {
- //A Stick (BrakeDefine is the highest possible Axis)
- if( js[i].code <= ABS_BRAKE )
- {
- int axis = mAxisMap[js[i].code];
- assert( axis < 32 && "Too many axes (Max supported is 32). Report this to OIS forums!" );
+ #ifdef OIS_LINUX_JOY_DEBUG
+ cout << "\nButton Code: " << js[i].code << ", OIS Value: " << button << endl;
+ #endif
- axisMoved[axis] = true;
-
- //check for rescaling:
- if( mRanges[axis].min == JoyStick::MIN_AXIS && mRanges[axis].max != JoyStick::MAX_AXIS )
- { //Scale is perfect
- mState.mAxes[axis].abs = js[i].value;
+ //Check to see whether push or released event...
+ if(js[i].value)
+ {
+ mState.mButtons[button] = true;
+ if( mBuffered && mListener )
+ if(!mListener->buttonPressed(JoyStickEvent(this,mState), button)) return;
}
else
- { //Rescale
- float proportion = (float)(js[i].value-mRanges[axis].max)/(float)(mRanges[axis].min-mRanges[axis].max);
- mState.mAxes[axis].abs = (int)(32767.0f - (65535.0f * proportion));
+ {
+ mState.mButtons[button] = false;
+ if( mBuffered && mListener )
+ if(!mListener->buttonReleased(JoyStickEvent(this,mState), button)) return;
}
+ break;
}
- else if( js[i].code <= ABS_HAT3Y ) //A POV - Max four POVs allowed
+
+ case EV_ABS: //Absolute Axis
{
- //Normalise the POV to between 0-7
- //Even is X Axis, Odd is Y Axis
- unsigned char LinuxPovNumber = js[i].code - 16;
- short OIS_POVIndex = POV_MASK[LinuxPovNumber];
+ //A Stick (BrakeDefine is the highest possible Axis)
+ if( js[i].code <= ABS_BRAKE )
+ {
+ int axis = mAxisMap[js[i].code];
+ assert( axis < 32 && "Too many axes (Max supported is 32). Report this to OIS forums!" );
- //Handle X Axis first (Even) (left right)
- if((LinuxPovNumber & 0x0001) == 0)
- {
- //Why do this? Because, we use a bit field, and when this axis is east,
- //it can't possibly be west too. So clear out the two X axes, then refil
- //it in with the new direction bit.
- //Clear the East/West Bit Flags first
- mState.mPOV[OIS_POVIndex].direction &= 0x11110011;
- if( js[i].value == -1 ) //Left
- mState.mPOV[OIS_POVIndex].direction |= Pov::West;
- else if( js[i].value == 1 ) //Right
- mState.mPOV[OIS_POVIndex].direction |= Pov::East;
+ axisMoved[axis] = true;
+
+ //check for rescaling:
+ if( mRanges[axis].min == JoyStick::MIN_AXIS && mRanges[axis].max != JoyStick::MAX_AXIS )
+ { //Scale is perfect
+ mState.mAxes[axis].abs = js[i].value;
+ }
+ else
+ { //Rescale
+ float proportion = (float)(js[i].value-mRanges[axis].max)/(float)(mRanges[axis].min-mRanges[axis].max);
+ mState.mAxes[axis].abs = (int)(32767.0f - (65535.0f * proportion));
+ }
}
- //Handle Y Axis (Odd) (up down)
- else
+ else if( js[i].code <= ABS_HAT3Y ) //A POV - Max four POVs allowed
{
- //Clear the North/South Bit Flags first
- mState.mPOV[OIS_POVIndex].direction &= 0x11111100;
- if( js[i].value == -1 ) //Up
- mState.mPOV[OIS_POVIndex].direction |= Pov::North;
- else if( js[i].value == 1 ) //Down
- mState.mPOV[OIS_POVIndex].direction |= Pov::South;
+ //Normalise the POV to between 0-7
+ //Even is X Axis, Odd is Y Axis
+ unsigned char LinuxPovNumber = js[i].code - 16;
+ short OIS_POVIndex = POV_MASK[LinuxPovNumber];
+
+ //Handle X Axis first (Even) (left right)
+ if((LinuxPovNumber & 0x0001) == 0)
+ {
+ //Why do this? Because, we use a bit field, and when this axis is east,
+ //it can't possibly be west too. So clear out the two X axes, then refil
+ //it in with the new direction bit.
+ //Clear the East/West Bit Flags first
+ mState.mPOV[OIS_POVIndex].direction &= 0x11110011;
+ if( js[i].value == -1 ) //Left
+ mState.mPOV[OIS_POVIndex].direction |= Pov::West;
+ else if( js[i].value == 1 ) //Right
+ mState.mPOV[OIS_POVIndex].direction |= Pov::East;
+ }
+ //Handle Y Axis (Odd) (up down)
+ else
+ {
+ //Clear the North/South Bit Flags first
+ mState.mPOV[OIS_POVIndex].direction &= 0x11111100;
+ if( js[i].value == -1 ) //Up
+ mState.mPOV[OIS_POVIndex].direction |= Pov::North;
+ else if( js[i].value == 1 ) //Down
+ mState.mPOV[OIS_POVIndex].direction |= Pov::South;
+ }
+
+ if( mBuffered && mListener )
+ if( mListener->povMoved( JoyStickEvent(this,mState), OIS_POVIndex) == false )
+ return;
}
+ break;
+ }
- if( mBuffered && mListener )
- if( mListener->povMoved( JoyStickEvent(this,mState), OIS_POVIndex) == false )
- return;
+
+ case EV_REL: //Relative Axes (Do any joystick actually have a relative axis?)
+ #ifdef OIS_LINUX_JOY_DEBUG
+ cout << "\nWarning: Relatives axes not supported yet" << endl;
+ #endif
+ break;
+ default: break;
}
- break;
}
-
-
- case EV_REL: //Relative Axes (Do any joystick actually have a relative axis?)
-#ifdef OIS_LINUX_JOY_DEBUG
- cout << "\nWarning: Relatives axes not supported yet" << endl;
-#endif
- break;
- default: break;
- }
}
//All axes and POVs are combined into one movement per pair per captured frame