summaryrefslogtreecommitdiffstats
path: root/Samples/CommonSrc/Platform/Linux_Gamepad.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Samples/CommonSrc/Platform/Linux_Gamepad.cpp')
-rw-r--r--Samples/CommonSrc/Platform/Linux_Gamepad.cpp415
1 files changed, 410 insertions, 5 deletions
diff --git a/Samples/CommonSrc/Platform/Linux_Gamepad.cpp b/Samples/CommonSrc/Platform/Linux_Gamepad.cpp
index 9370120..7bca5c5 100644
--- a/Samples/CommonSrc/Platform/Linux_Gamepad.cpp
+++ b/Samples/CommonSrc/Platform/Linux_Gamepad.cpp
@@ -3,7 +3,7 @@
Filename : Linux_Gamepad.cpp
Content : Linux implementation of Platform app infrastructure
Created : May 6, 2013
-Authors : Lee Cooper
+Authors : Lee Cooper, Simon Hallam
Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
@@ -21,18 +21,34 @@ limitations under the License.
************************************************************************************/
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <glob.h>
+#include <linux/joystick.h>
#include "Linux_Gamepad.h"
+
namespace OVR { namespace Platform { namespace Linux {
-GamepadManager::GamepadManager()
-{
+const char* pNameXbox360Wireless = "Xbox 360";
+const char* pNameXbox360Wired = "Microsoft X-Box 360";
+
+GamepadManager::GamepadManager() :
+ pDevice(NULL)
+{
}
GamepadManager::~GamepadManager()
{
-
+ // if we have an open device, close it
+ if (pDevice)
+ {
+ pDevice->Close();
+ pDevice = NULL;
+ }
}
UInt32 GamepadManager::GetGamepadCount()
@@ -40,9 +56,398 @@ UInt32 GamepadManager::GetGamepadCount()
return 1;
}
-bool GamepadManager::GetGamepadState(UInt32 index, GamepadState* pState)
+bool GamepadManager::GetGamepadState(UInt32 index, GamepadState *pState)
+{
+ if (!pDevice)
+ {
+ // get a list of paths to all the connected joystick devices
+ glob_t joystickGlobBuffer;
+ glob("/dev/input/js*", 0, NULL, &joystickGlobBuffer);
+
+ // open each joystick device, until we find one that will work for our needs
+ for (UInt32 i = 0; i < joystickGlobBuffer.gl_pathc; i++)
+ {
+ pDevice = new Gamepad();
+ if (pDevice->Open(joystickGlobBuffer.gl_pathv[i]))
+ {
+
+ if (pDevice->IsSupportedType())
+ {
+ break;
+ }
+ }
+
+ // we don't know why the device was not useable, make sure it gets closed cleanly
+ pDevice->Close();
+ pDevice = NULL;
+ }
+
+ }
+
+ if (pDevice)
+ {
+ // we have a device, so update it
+ pDevice->UpdateState();
+
+ // copy the device state into the struct param
+ memcpy(pState, pDevice->GetState(), sizeof(GamepadState));
+
+ // TODO: is the device still active/connected? if not, we should close it
+ // and clear pDevice, so that another device can take over
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+Gamepad::Gamepad() :
+ IsInitialized(false),
+ Name(String("Undefined")),
+ Type(UNDEFINED)
+{
+}
+
+Gamepad::~Gamepad()
+{
+ this->Close();
+}
+
+bool Gamepad::Open(const String& devicePathName)
{
+ Name = "Undefined";
+ Type = UNDEFINED;
+
+ FileDescriptor = ::open(devicePathName.ToCStr(), O_RDONLY | O_NONBLOCK);
+ if (FileDescriptor == -1)
+ {
+ return false;
+ }
+
+ // get the device name
+ char name[128];
+ if (ioctl(FileDescriptor, JSIOCGNAME(sizeof(name)), name) < 0)
+ {
+ return false;
+ }
+
+ Name = name;
+
+ // see if device name matches one of our supported devices
+ static const UInt32 Wireless360Len = String(pNameXbox360Wireless).GetLength();
+ static const UInt32 Wired360Len = String(pNameXbox360Wired).GetLength();
+ if (Name.Substring(0, Wireless360Len) == pNameXbox360Wireless)
+ {
+ Type = XBOX360GAMEPADWIRELESS;
+ return true;
+ }
+ else if(Name.Substring(0, Wired360Len) == pNameXbox360Wired)
+ {
+ Type = XBOX360GAMEPADWIRED;
+ return true;
+ }
+
return false;
}
+bool Gamepad::Close()
+{
+ IsInitialized = false;
+ Name = "Undefined";
+ Type = UNDEFINED;
+ return !::close(FileDescriptor);
+}
+
+void Gamepad::UpdateState()
+{
+ GamepadState *pState = &State;
+ js_event gamepadEvent;
+
+ // read the latest batch of events
+ while (read(FileDescriptor, &gamepadEvent, sizeof(struct js_event)) != -1)
+ {
+ switch (gamepadEvent.type)
+ {
+ case JS_EVENT_BUTTON:
+ IsInitialized = true;
+ SetStateButton(pState, gamepadEvent.number, gamepadEvent.value);
+ break;
+
+ case JS_EVENT_AXIS:
+ IsInitialized = true;
+ SetStateAxis(pState, gamepadEvent.number, gamepadEvent.value);
+ break;
+
+ case JS_EVENT_BUTTON | JS_EVENT_INIT:
+ if (IsInitialized) // skip the fake values during device event initialization
+ {
+ SetStateButton(pState, gamepadEvent.number, gamepadEvent.value);
+ }
+ break;
+
+ case JS_EVENT_AXIS | JS_EVENT_INIT:
+ if (IsInitialized) // skip the fake values during device event initialization
+ {
+ SetStateAxis(pState, gamepadEvent.number, gamepadEvent.value);
+ }
+ break;
+
+ default:
+ LogText("OVR::Linux::UpdateState unknown event type\n");
+ }
+ }
+}
+
+const GamepadState* Gamepad::GetState()
+{
+ return &State;
+}
+
+
+bool Gamepad::IsSupportedType()
+{
+ return Type != UNDEFINED;
+}
+
+const String& Gamepad::GetIdentifier()
+{
+ return Name;
+}
+
+static inline float NormalizeGamepadStickXbox360(SInt32 in)
+{
+ float v;
+ if (abs(in) < 9000) return 0;
+ else if (in > 9000) v = (float)in - 9000;
+ else v = (float)in + 9000;
+ return v / (32767 - 9000);
+}
+
+static inline float NormalizeGamepadTriggerXbox360(SInt32 in,
+ SInt32 offset,
+ SInt32 deadBand,
+ float divisor)
+{
+ in += offset;
+
+ if (in < deadBand)
+ {
+ return 0;
+ }
+ else
+ {
+ return float(in - deadBand) / divisor;
+ }
+}
+
+static inline void UpdateButtonMaskAndBitfield(GamepadState *pState,
+ SInt32 value,
+ UInt32 buttonBitfield)
+{
+ if (value)
+ {
+ pState->Buttons |= buttonBitfield;
+ }
+ else
+ {
+ pState->Buttons = pState->Buttons & (0xFFFFFFFF ^ buttonBitfield);
+ }
+}
+
+void Gamepad::SetStateAxis(GamepadState *pState, UInt32 axis, SInt32 value)
+{
+ // some pads/sticks have lots in common with one another,
+ // handle those shared cases first
+ switch (Type)
+ {
+ case XBOX360GAMEPADWIRELESS:
+ case XBOX360GAMEPADWIRED:
+ switch (axis)
+ {
+ case 0:
+ pState->LX = NormalizeGamepadStickXbox360(value);
+ break;
+
+ case 1:
+ pState->LY = -NormalizeGamepadStickXbox360(value);
+ break;
+
+ case 3:
+ pState->RX = NormalizeGamepadStickXbox360(value);
+ break;
+
+ case 4:
+ pState->RY = -NormalizeGamepadStickXbox360(value);
+ break;
+ }
+ break;
+
+ case UNDEFINED:
+ default:
+ break;
+ }
+
+ // handle the special cases, or pads/sticks which are unique
+ switch (Type)
+ {
+ case XBOX360GAMEPADWIRELESS:
+ switch (axis)
+ {
+ case 2:
+ pState->LT = NormalizeGamepadTriggerXbox360(value, 0, 500, 32267);
+ break;
+
+ case 5:
+ pState->RT = NormalizeGamepadTriggerXbox360(value, 0, 500, 32267);
+ break;
+ }
+ break;
+
+ case XBOX360GAMEPADWIRED:
+ switch (axis)
+ {
+ case 2:
+ pState->LT = NormalizeGamepadTriggerXbox360(value, 32767, 1000, 64535);
+ break;
+
+ case 5:
+ pState->RT = NormalizeGamepadTriggerXbox360(value, 32767, 1000, 64535);
+ break;
+
+ case 6:
+ if (value == 0)
+ {
+ UpdateButtonMaskAndBitfield(pState, 0, Gamepad_Left);
+ UpdateButtonMaskAndBitfield(pState, 0, Gamepad_Right);
+ }
+ else if (value < 0)
+ {
+ UpdateButtonMaskAndBitfield(pState, 1, Gamepad_Left);
+ }
+ else if (value > 0)
+ {
+ UpdateButtonMaskAndBitfield(pState, 1, Gamepad_Right);
+ }
+ break;
+
+ case 7:
+ if (value == 0)
+ {
+ UpdateButtonMaskAndBitfield(pState, 0, Gamepad_Up);
+ UpdateButtonMaskAndBitfield(pState, 0, Gamepad_Down);
+ }
+ else if (value < 0)
+ {
+ UpdateButtonMaskAndBitfield(pState, 1, Gamepad_Up);
+ }
+ else if (value > 0)
+ {
+ UpdateButtonMaskAndBitfield(pState, 1, Gamepad_Down);
+ }
+ break;
+ }
+ break;
+
+ case UNDEFINED:
+ default:
+ break;
+ }
+}
+
+void Gamepad::SetStateButton(GamepadState *pState, UInt32 button, SInt32 value)
+{
+ // some pads/sticks have lots in common with one another,
+ // handle those shared cases first
+ switch (Type)
+ {
+ case XBOX360GAMEPADWIRELESS:
+ case XBOX360GAMEPADWIRED:
+ switch (button)
+ {
+ case 0:
+ UpdateButtonMaskAndBitfield(pState, value, Gamepad_A);
+ break;
+
+ case 1:
+ UpdateButtonMaskAndBitfield(pState, value, Gamepad_B);
+ break;
+
+ case 2:
+ UpdateButtonMaskAndBitfield(pState, value, Gamepad_X);
+ break;
+
+ case 3:
+ UpdateButtonMaskAndBitfield(pState, value, Gamepad_Y);
+ break;
+
+ case 4:
+ UpdateButtonMaskAndBitfield(pState, value, Gamepad_L1);
+ break;
+
+ case 5:
+ UpdateButtonMaskAndBitfield(pState, value, Gamepad_R1);
+ break;
+
+ case 6:
+ UpdateButtonMaskAndBitfield(pState, value, Gamepad_Back);
+ break;
+
+ case 7:
+ UpdateButtonMaskAndBitfield(pState, value, Gamepad_Start);
+ break;
+
+ case 8:
+ // we have no value defined for the Xbox/power button
+ break;
+
+ case 9:
+ UpdateButtonMaskAndBitfield(pState, value, Gamepad_LStick);
+ break;
+
+ case 10:
+ UpdateButtonMaskAndBitfield(pState, value, Gamepad_RStick);
+ break;
+ }
+ break;
+
+ case UNDEFINED:
+ default:
+ break;
+ }
+
+ // handle the special cases, or pads/sticks which are unique
+ switch (Type)
+ {
+ case XBOX360GAMEPADWIRELESS:
+ switch (button)
+ {
+ case 11:
+ UpdateButtonMaskAndBitfield(pState, value, Gamepad_Left);
+ break;
+
+ case 12:
+ UpdateButtonMaskAndBitfield(pState, value, Gamepad_Right);
+ break;
+
+ case 13:
+ UpdateButtonMaskAndBitfield(pState, value, Gamepad_Up);
+ break;
+
+ case 14:
+ UpdateButtonMaskAndBitfield(pState, value, Gamepad_Down);
+ break;
+ }
+
+ case XBOX360GAMEPADWIRED:
+ break;
+
+ case UNDEFINED:
+ default:
+ break;
+ }
+}
+
}}} // OVR::Platform::Linux
+