Play-/Source/ui_macosx/PH_HidMacOSX.cpp
2015-05-06 01:27:59 -04:00

188 lines
6.2 KiB
C++

#include "PH_HidMacOSX.h"
#include <stdexcept>
CPH_HidMacOSX::CPH_HidMacOSX()
{
m_bindings[PS2::CControllerInfo::ANALOG_LEFT_X] = std::make_shared<CSimulatedAxisBinding>(kHIDUsage_KeyboardD, kHIDUsage_KeyboardG);
m_bindings[PS2::CControllerInfo::ANALOG_LEFT_Y] = std::make_shared<CSimulatedAxisBinding>(kHIDUsage_KeyboardR, kHIDUsage_KeyboardF);
m_bindings[PS2::CControllerInfo::ANALOG_RIGHT_X] = std::make_shared<CSimulatedAxisBinding>(kHIDUsage_KeyboardH, kHIDUsage_KeyboardK);
m_bindings[PS2::CControllerInfo::ANALOG_RIGHT_Y] = std::make_shared<CSimulatedAxisBinding>(kHIDUsage_KeyboardU, kHIDUsage_KeyboardJ);
m_bindings[PS2::CControllerInfo::START] = std::make_shared<CSimpleBinding>(kHIDUsage_KeyboardReturnOrEnter);
m_bindings[PS2::CControllerInfo::SELECT] = std::make_shared<CSimpleBinding>(kHIDUsage_KeyboardRightShift);
m_bindings[PS2::CControllerInfo::DPAD_LEFT] = std::make_shared<CSimpleBinding>(kHIDUsage_KeyboardLeftArrow);
m_bindings[PS2::CControllerInfo::DPAD_RIGHT] = std::make_shared<CSimpleBinding>(kHIDUsage_KeyboardRightArrow);
m_bindings[PS2::CControllerInfo::DPAD_UP] = std::make_shared<CSimpleBinding>(kHIDUsage_KeyboardUpArrow);
m_bindings[PS2::CControllerInfo::DPAD_DOWN] = std::make_shared<CSimpleBinding>(kHIDUsage_KeyboardDownArrow);
m_bindings[PS2::CControllerInfo::SQUARE] = std::make_shared<CSimpleBinding>(kHIDUsage_KeyboardA);
m_bindings[PS2::CControllerInfo::CROSS] = std::make_shared<CSimpleBinding>(kHIDUsage_KeyboardZ);
m_bindings[PS2::CControllerInfo::TRIANGLE] = std::make_shared<CSimpleBinding>(kHIDUsage_KeyboardS);
m_bindings[PS2::CControllerInfo::CIRCLE] = std::make_shared<CSimpleBinding>(kHIDUsage_KeyboardX);
m_hidManager = IOHIDManagerCreate(kCFAllocatorDefault, 0);
{
CFDictionaryRef matchingDict = CreateDeviceMatchingDictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_Keyboard);
IOHIDManagerSetDeviceMatching(m_hidManager, matchingDict);
CFRelease(matchingDict);
}
IOHIDManagerScheduleWithRunLoop(m_hidManager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
IOHIDManagerOpen(m_hidManager, kIOHIDOptionsTypeNone);
IOHIDManagerRegisterInputValueCallback(m_hidManager, InputValueCallbackStub, this);
}
CPH_HidMacOSX::~CPH_HidMacOSX()
{
IOHIDManagerClose(m_hidManager, 0);
}
void CPH_HidMacOSX::Update(uint8* ram)
{
for(auto listenerIterator(std::begin(m_listeners));
listenerIterator != std::end(m_listeners); listenerIterator++)
{
auto* listener(*listenerIterator);
for(unsigned int i = 0; i < PS2::CControllerInfo::MAX_BUTTONS; i++)
{
const auto& binding = m_bindings[i];
if(!binding) continue;
uint32 value = binding->GetValue();
auto currentButtonId = static_cast<PS2::CControllerInfo::BUTTON>(i);
if(PS2::CControllerInfo::IsAxis(currentButtonId))
{
listener->SetAxisState(0, currentButtonId, value & 0xFF, ram);
}
else
{
listener->SetButtonState(0, currentButtonId, value != 0, ram);
}
}
}
}
CPadHandler::FactoryFunction CPH_HidMacOSX::GetFactoryFunction()
{
//Needs to be created in the same thread as UI
return std::bind(&CPH_HidMacOSX::PadHandlerFactory, new CPH_HidMacOSX());
}
CPadHandler* CPH_HidMacOSX::PadHandlerFactory(CPH_HidMacOSX* handler)
{
return handler;
}
CFMutableDictionaryRef CPH_HidMacOSX::CreateDeviceMatchingDictionary(uint32 usagePage, uint32 usage)
{
CFMutableDictionaryRef result = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
if(result == NULL) throw std::runtime_error("CFDictionaryCreateMutable failed.");
if(usagePage != 0)
{
// Add key for device type to refine the matching dictionary.
CFNumberRef pageCFNumberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usagePage);
if(pageCFNumberRef == NULL) throw std::runtime_error("CFNumberCreate failed.");
CFDictionarySetValue(result, CFSTR(kIOHIDDeviceUsagePageKey), pageCFNumberRef);
CFRelease(pageCFNumberRef);
// note: the usage is only valid if the usage page is also defined
if(usage != 0)
{
CFNumberRef usageCFNumberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage);
if(usageCFNumberRef == NULL) throw std::runtime_error("CFNumberCreate failed.");
CFDictionarySetValue(result, CFSTR(kIOHIDDeviceUsageKey), usageCFNumberRef);
CFRelease(usageCFNumberRef);
}
}
return result;
}
void CPH_HidMacOSX::InputValueCallbackStub(void* context, IOReturn result, void* sender, IOHIDValueRef valueRef)
{
reinterpret_cast<CPH_HidMacOSX*>(context)->InputValueCallback(valueRef);
}
void CPH_HidMacOSX::InputValueCallback(IOHIDValueRef valueRef)
{
IOHIDElementRef elementRef = IOHIDValueGetElement(valueRef);
uint32 usage = IOHIDElementGetUsage(elementRef);
uint32 usagePage = IOHIDElementGetUsagePage(elementRef);
CFIndex state = IOHIDValueGetIntegerValue(valueRef);
if(usagePage != kHIDPage_KeyboardOrKeypad) return;
for(auto bindingIterator(std::begin(m_bindings));
bindingIterator != std::end(m_bindings); bindingIterator++)
{
const auto& binding = (*bindingIterator);
if(!binding) continue;
binding->ProcessEvent(usage, state);
}
}
//---------------------------------------------------------------------------------
CPH_HidMacOSX::CSimpleBinding::CSimpleBinding(uint32 keyCode)
: m_keyCode(keyCode)
, m_state(0)
{
}
CPH_HidMacOSX::CSimpleBinding::~CSimpleBinding()
{
}
void CPH_HidMacOSX::CSimpleBinding::ProcessEvent(uint32 keyCode, uint32 state)
{
if(keyCode != m_keyCode) return;
m_state = state;
}
uint32 CPH_HidMacOSX::CSimpleBinding::GetValue() const
{
return m_state;
}
//---------------------------------------------------------------------------------
CPH_HidMacOSX::CSimulatedAxisBinding::CSimulatedAxisBinding(uint32 negativeKeyCode, uint32 positiveKeyCode)
: m_negativeKeyCode(negativeKeyCode)
, m_positiveKeyCode(positiveKeyCode)
, m_negativeState(0)
, m_positiveState(0)
{
}
CPH_HidMacOSX::CSimulatedAxisBinding::~CSimulatedAxisBinding()
{
}
void CPH_HidMacOSX::CSimulatedAxisBinding::ProcessEvent(uint32 keyCode, uint32 state)
{
if(keyCode == m_negativeKeyCode)
{
m_negativeState = state;
}
if(keyCode == m_positiveKeyCode)
{
m_positiveState = state;
}
}
uint32 CPH_HidMacOSX::CSimulatedAxisBinding::GetValue() const
{
uint32 value = 0x7F;
if(m_negativeState)
{
value -= 0x7F;
}
if(m_positiveState)
{
value += 0x7F;
}
return value;
}