aboutsummaryrefslogtreecommitdiffstats
path: root/Samples/CommonSrc/Platform/OSX_Gamepad.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Samples/CommonSrc/Platform/OSX_Gamepad.cpp')
-rw-r--r--Samples/CommonSrc/Platform/OSX_Gamepad.cpp430
1 files changed, 430 insertions, 0 deletions
diff --git a/Samples/CommonSrc/Platform/OSX_Gamepad.cpp b/Samples/CommonSrc/Platform/OSX_Gamepad.cpp
new file mode 100644
index 0000000..36f8109
--- /dev/null
+++ b/Samples/CommonSrc/Platform/OSX_Gamepad.cpp
@@ -0,0 +1,430 @@
+/************************************************************************************
+
+Filename : OSX_Gamepad.cpp
+Content : OSX implementation of Gamepad functionality.
+Created : May 6, 2013
+Authors : Lee Cooper
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+************************************************************************************/
+
+#include "OSX_Gamepad.h"
+
+
+static const UInt32 Logitech_F710_VendorID = 0x046D;
+//static const UInt32 Logitech_F710_ProductID = 0xC219;
+
+static const UInt32 Sony_DualShock3_VendorID = 0x054C;
+//static const UInt32 Sony_DualShock3_ProductID = 0x0268;
+
+
+namespace OVR { namespace Platform { namespace OSX {
+
+
+GamepadManager::GamepadManager()
+ : bStateChanged(false)
+{
+
+ HidManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
+ IOHIDManagerOpen(HidManager, kIOHIDOptionsTypeNone);
+ IOHIDManagerScheduleWithRunLoop(HidManager,
+ CFRunLoopGetCurrent(),
+ kCFRunLoopDefaultMode);
+
+
+ // Setup device matching.
+ CFStringRef keys[] = { CFSTR(kIOHIDDeviceUsagePageKey),
+ CFSTR(kIOHIDDeviceUsageKey)};
+
+ int value;
+ CFNumberRef values[2];
+ CFDictionaryRef dictionaries[2];
+
+ // Match joysticks.
+ value = kHIDPage_GenericDesktop;
+ values[0] = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &value);
+
+ value = kHIDUsage_GD_Joystick;
+ values[1] = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &value);
+
+ dictionaries[0] = CFDictionaryCreate(kCFAllocatorDefault,
+ (const void **) keys,
+ (const void **) values,
+ 2,
+ &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ CFRelease(values[0]);
+ CFRelease(values[1]);
+
+ // Match gamepads.
+ value = kHIDPage_GenericDesktop;
+ values[0] = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &value);
+
+ value = kHIDUsage_GD_GamePad;
+ values[1] = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &value);
+
+ dictionaries[1] = CFDictionaryCreate(kCFAllocatorDefault,
+ (const void **) keys,
+ (const void **) values,
+ 2,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ CFRelease(values[0]);
+ CFRelease(values[1]);
+
+ CFArrayRef array = CFArrayCreate( kCFAllocatorDefault,
+ (const void **) dictionaries,
+ 2,
+ &kCFTypeArrayCallBacks);
+ CFRelease(dictionaries[0]);
+ CFRelease(dictionaries[1]);
+
+ IOHIDManagerSetDeviceMatchingMultiple(HidManager, array);
+
+ CFRelease(array);
+
+
+ IOHIDManagerRegisterDeviceMatchingCallback(HidManager, staticOnDeviceMatched, this);
+ IOHIDManagerRegisterDeviceRemovalCallback(HidManager, staticOnDeviceRemoved, this);
+
+}
+
+GamepadManager::~GamepadManager()
+{
+ CFRelease(HidManager);
+}
+
+UInt32 GamepadManager::GetGamepadCount()
+{
+ return 1;
+}
+
+bool GamepadManager::GetGamepadState(UInt32 index, GamepadState* pState)
+{
+ // For now we just support one gamepad.
+ OVR_UNUSED(index);
+
+ if (!bStateChanged)
+ {
+ return false;
+ }
+
+ bStateChanged = false;
+// State.Debug();
+
+ *pState = State;
+ return true;
+}
+
+int GamepadManager::getIntDeviceProperty(IOHIDDeviceRef device, CFStringRef key)
+{
+ CFTypeRef type = IOHIDDeviceGetProperty(device, key);
+ OVR_ASSERT(type != NULL && CFGetTypeID(type) == CFNumberGetTypeID());
+
+ int value;
+ CFNumberGetValue((CFNumberRef) type, kCFNumberSInt32Type, &value);
+
+ return value;
+}
+
+void GamepadManager::staticOnDeviceMatched(void* context, IOReturn result, void* sender, IOHIDDeviceRef device)
+{
+ OVR_UNUSED(result);
+ OVR_UNUSED(sender);
+ GamepadManager* pManager = (GamepadManager*) context;
+ pManager->onDeviceMatched(device);
+}
+
+void GamepadManager::onDeviceMatched(IOHIDDeviceRef device)
+{
+ IOHIDDeviceRegisterInputValueCallback(device, staticOnDeviceValueChanged, this);
+}
+
+void GamepadManager::staticOnDeviceRemoved(void* context, IOReturn result, void* sender, IOHIDDeviceRef device)
+{
+ OVR_UNUSED(result);
+ OVR_UNUSED(sender);
+ GamepadManager* pManager = (GamepadManager*) context;
+ pManager->onDeviceRemoved(device);
+}
+
+void GamepadManager::onDeviceRemoved(IOHIDDeviceRef device)
+{
+ IOHIDDeviceRegisterInputValueCallback(device, NULL, NULL);
+}
+
+void GamepadManager::staticOnDeviceValueChanged(void* context, IOReturn result, void* sender, IOHIDValueRef value)
+{
+ OVR_UNUSED(result);
+ OVR_UNUSED(sender);
+ GamepadManager* pManager = (GamepadManager*) context;
+ pManager->onDeviceValueChanged(value);
+}
+
+float GamepadManager::mapAnalogAxis(IOHIDValueRef value, IOHIDElementRef element)
+{
+
+ CFIndex val = IOHIDValueGetIntegerValue(value);
+ CFIndex min = IOHIDElementGetLogicalMin(element);
+ CFIndex max = IOHIDElementGetLogicalMax(element);
+
+ float v = (float) (val - min) / (float) (max - min);
+ v = v * 2.0f - 1.0f;
+
+ // Dead zone.
+ if (v < 0.1f && v > -0.1f)
+ {
+ v = 0.0f;
+ }
+
+ return v;
+}
+
+bool GamepadManager::setStateIfDifferent(float& state, float newState)
+{
+ if (state == newState)
+ return false;
+
+ state = newState;
+
+ return true;
+}
+
+void GamepadManager::onDeviceValueChanged(IOHIDValueRef value)
+{
+
+ IOHIDElementRef element = IOHIDValueGetElement(value);
+ IOHIDDeviceRef device = IOHIDElementGetDevice(element);
+
+ unsigned int vendorID = (unsigned int)getIntDeviceProperty(device, CFSTR(kIOHIDVendorIDKey));
+ unsigned int productID = (unsigned int)getIntDeviceProperty(device, CFSTR(kIOHIDProductIDKey));
+ OVR_UNUSED(productID);
+
+ uint32_t usagePage = IOHIDElementGetUsagePage(element);
+ uint32_t usage = IOHIDElementGetUsage(element);
+
+ // The following controller mapping is based on the Logitech F710, however we use it for
+ // all Logitech devices on the assumption that they're likely to share the same mapping.
+ if (vendorID == Logitech_F710_VendorID)
+ {
+ // Logitech F710 mapping.
+ if (usagePage == kHIDPage_Button)
+ {
+ bool buttonState = IOHIDValueGetIntegerValue(value);
+
+ switch(usage)
+ {
+ case kHIDUsage_Button_1:
+ manipulateBitField(State.Buttons, Gamepad_X, buttonState);
+ break;
+ case kHIDUsage_Button_2:
+ manipulateBitField(State.Buttons, Gamepad_A, buttonState);
+ break;
+ case kHIDUsage_Button_3:
+ manipulateBitField(State.Buttons, Gamepad_B, buttonState);
+ break;
+ case kHIDUsage_Button_4:
+ manipulateBitField(State.Buttons, Gamepad_Y, buttonState);
+ break;
+ case 0x05:
+ manipulateBitField(State.Buttons, Gamepad_L1, buttonState);
+ break;
+ case 0x06:
+ manipulateBitField(State.Buttons, Gamepad_R1, buttonState);
+ break;
+ case 0x07:
+ State.LT = buttonState ? 1.0f:0.0f;
+ break;
+ case 0x08:
+ State.RT = buttonState ? 1.0f:0.0f;
+ break;
+ case 0x09:
+ manipulateBitField(State.Buttons, Gamepad_Back, buttonState);
+ break;
+ case 0x0A:
+ manipulateBitField(State.Buttons, Gamepad_Start, buttonState);
+ break;
+ case 0x0B:
+ manipulateBitField(State.Buttons, Gamepad_LStick, buttonState);
+ break;
+ case 0x0C:
+ manipulateBitField(State.Buttons, Gamepad_RStick, buttonState);
+ break;
+ default:
+ return;
+ }
+ }
+ else if (usagePage == kHIDPage_GenericDesktop)
+ {
+ float v;
+ switch(usage)
+ {
+ case kHIDUsage_GD_X:
+ v = mapAnalogAxis(value, element);
+ if (!setStateIfDifferent(State.LX, v))
+ return;
+ break;
+ case kHIDUsage_GD_Y:
+ v = mapAnalogAxis(value, element);
+ if (!setStateIfDifferent(State.LY, -v))
+ return;
+ break;
+ case kHIDUsage_GD_Z:
+ v = mapAnalogAxis(value, element);
+ if (!setStateIfDifferent(State.RX, v))
+ return;
+ break;
+ case kHIDUsage_GD_Rz:
+ v = mapAnalogAxis(value, element);
+ if (!setStateIfDifferent(State.RY, -v))
+ return;
+ break;
+ case kHIDUsage_GD_Hatswitch:
+ {
+ CFIndex integerValue = IOHIDValueGetIntegerValue(value);
+
+ manipulateBitField(State.Buttons,
+ Gamepad_Up,
+ integerValue == 7 || integerValue == 0 || integerValue == 1);
+ manipulateBitField(State.Buttons,
+ Gamepad_Down,
+ integerValue == 3 || integerValue == 4 || integerValue == 5);
+ manipulateBitField(State.Buttons,
+ Gamepad_Left,
+ integerValue == 5 || integerValue == 6 || integerValue == 7);
+ manipulateBitField(State.Buttons,
+ Gamepad_Right,
+ integerValue == 1 || integerValue == 2 || integerValue == 3);
+ }
+ break;
+ default:
+ return;
+ }
+ }
+ }
+ // The following controller mapping is based on the Sony DualShock3, however we use it for
+ // all Sony devices on the assumption that they're likely to share the same mapping.
+ else if (vendorID == Sony_DualShock3_VendorID)
+ {
+ // PS3 Controller.
+ if (usagePage == kHIDPage_Button)
+ {
+ bool buttonState = IOHIDValueGetIntegerValue(value);
+
+ switch(usage)
+ {
+ case kHIDUsage_Button_1:
+ manipulateBitField(State.Buttons, Gamepad_Back, buttonState);
+ break;
+ case kHIDUsage_Button_2:
+ manipulateBitField(State.Buttons, Gamepad_LStick, buttonState);
+ break;
+ case kHIDUsage_Button_3:
+ manipulateBitField(State.Buttons, Gamepad_RStick, buttonState);
+ break;
+ case kHIDUsage_Button_4:
+ manipulateBitField(State.Buttons, Gamepad_Start, buttonState);
+ break;
+ case 0x05:
+ manipulateBitField(State.Buttons, Gamepad_Up, buttonState);
+ break;
+ case 0x06:
+ manipulateBitField(State.Buttons, Gamepad_Right, buttonState);
+ break;
+ case 0x07:
+ manipulateBitField(State.Buttons, Gamepad_Down, buttonState);
+ break;
+ case 0x08:
+ manipulateBitField(State.Buttons, Gamepad_Left, buttonState);
+ break;
+ case 0x09:
+ State.LT = buttonState ? 1.0f:0.0f;
+ break;
+ case 0x0A:
+ State.RT = buttonState ? 1.0f:0.0f;
+ break;
+ case 0x0B:
+ manipulateBitField(State.Buttons, Gamepad_L1, buttonState);
+ break;
+ case 0x0C:
+ manipulateBitField(State.Buttons, Gamepad_R1, buttonState);
+ break;
+ case 0x0D:
+ // PS3 Triangle.
+ manipulateBitField(State.Buttons, Gamepad_TRIANGLE, buttonState);
+ break;
+ case 0x0E:
+ // PS3 Circle
+ manipulateBitField(State.Buttons, Gamepad_CIRCLE, buttonState);
+ break;
+ case 0x0F:
+ // PS3 Cross
+ manipulateBitField(State.Buttons, Gamepad_CROSS, buttonState);
+ break;
+ case 0x10:
+ // PS3 Square
+ manipulateBitField(State.Buttons, Gamepad_SQUARE, buttonState);
+ break;
+ default:
+ return;
+ }
+ }
+ else if (usagePage == kHIDPage_GenericDesktop)
+ {
+ float v;
+ switch(usage)
+ {
+ case kHIDUsage_GD_X:
+ v = mapAnalogAxis(value, element);
+ if (!setStateIfDifferent(State.LX, v))
+ return;
+ break;
+ case kHIDUsage_GD_Y:
+ v = mapAnalogAxis(value, element);
+ if (!setStateIfDifferent(State.LY, -v))
+ return;
+ break;
+ case kHIDUsage_GD_Z:
+ v = mapAnalogAxis(value, element);
+ if (!setStateIfDifferent(State.RX, v))
+ return;
+ break;
+ case kHIDUsage_GD_Rz:
+ v = mapAnalogAxis(value, element);
+ if (!setStateIfDifferent(State.RY, -v))
+ return;
+ break;
+ default:
+ return;
+ }
+ }
+ }
+
+ bStateChanged = true;
+}
+
+void GamepadManager::manipulateBitField(unsigned int& bitfield, unsigned int mask, bool val)
+{
+ if (val)
+ {
+ bitfield |= mask;
+ }
+ else
+ {
+ bitfield &= ~mask;
+ }
+}
+
+}}} // OVR::Platform::OSX