| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870 |
- //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
- //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
- #include "Input/BsInput.h"
- #include "MacOS/BsMacOSInput.h"
- #include "Input/BsMouse.h"
- #include "Input/BsKeyboard.h"
- #include "Input/BsGamepad.h"
- namespace bs
- {
- /**
- * Helper method that creates a dictionary that is used for matching a specific set of devices (matching the provided
- * page and usage values, as USB HID values), used for initializing a HIDManager.
- */
- static CFDictionaryRef createHIDDeviceMatchDictionary(UINT32 page, UINT32 usage)
- {
- CFDictionaryRef output = nullptr;
- CFNumberRef pageNumRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &page);
- CFNumberRef usageNumRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage);
- const void* keys[2] = { (void*) CFSTR(kIOHIDDeviceUsagePageKey), (void*) CFSTR(kIOHIDDeviceUsageKey) };
- const void* values[2] = { (void*) pageNumRef, (void*) usageNumRef };
- if (pageNumRef && usageNumRef)
- {
- output = CFDictionaryCreate(kCFAllocatorDefault, keys, values, 2, &kCFTypeDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks);
- }
- if (pageNumRef)
- CFRelease(pageNumRef);
- if (usageNumRef)
- CFRelease(usageNumRef);
- return output;
- }
- /** Returns the name of the run loop used for processing events for the specified category of input devices. */
- static CFStringRef getRunLoopMode(HIDType type)
- {
- static CFStringRef KeyboardMode = CFSTR("BSKeyboard");
- static CFStringRef MouseMode = CFSTR("BSMouse");
- static CFStringRef GamepadMode = CFSTR("BSGamepad");
- switch(type)
- {
- case HIDType::Keyboard:
- return KeyboardMode;
- case HIDType::Mouse:
- return MouseMode;
- case HIDType::Gamepad:
- return GamepadMode;
- }
- return nullptr;
- }
- static void HIDAddElements(CFArrayRef array, HIDDevice* device);
- /**
- * Callback called when enumerating an array of HID elements. Each element's information is parsed and stored in the
- * owner HIDDevice (passed through @p passthrough parameter).
- *
- * @param[in] value IOHIDElementRef of the current element.
- * @param[in] passthrough Pointer to element's parent HIDDevice.
- */
- static void HIDAddElement(const void* value, void* passthrough)
- {
- auto device = (HIDDevice*)passthrough;
- auto elemRef = (IOHIDElementRef) value;
- if(!elemRef)
- return;
- CFTypeID typeID = CFGetTypeID(elemRef);
- if(typeID != IOHIDElementGetTypeID())
- return;
- IOHIDElementType type = IOHIDElementGetType(elemRef);
- switch (type)
- {
- case kIOHIDElementTypeInput_Button:
- case kIOHIDElementTypeInput_Axis:
- case kIOHIDElementTypeInput_Misc:
- case kIOHIDElementTypeInput_ScanCodes:
- break;
- case kIOHIDElementTypeCollection:
- {
- CFArrayRef array = IOHIDElementGetChildren(elemRef);
- if(array)
- HIDAddElements(array, device);
- }
- return;
- default:
- return;
- }
- UINT32 usagePage = IOHIDElementGetUsagePage(elemRef);
- UINT32 usage = IOHIDElementGetUsage(elemRef);
- enum ElemState { IsUnknown, IsButton, IsAxis, IsHat };
- ElemState state = IsUnknown;
- switch(usagePage)
- {
- case kHIDPage_Button:
- case kHIDPage_KeyboardOrKeypad:
- state = IsButton;
- break;
- case kHIDPage_GenericDesktop:
- switch(usage)
- {
- case kHIDUsage_GD_Start:
- case kHIDUsage_GD_Select:
- case kHIDUsage_GD_SystemMainMenu:
- case kHIDUsage_GD_DPadUp:
- case kHIDUsage_GD_DPadDown:
- case kHIDUsage_GD_DPadRight:
- case kHIDUsage_GD_DPadLeft:
- state = IsButton;
- break;
- case kHIDUsage_GD_X:
- case kHIDUsage_GD_Y:
- case kHIDUsage_GD_Z:
- case kHIDUsage_GD_Rx:
- case kHIDUsage_GD_Ry:
- case kHIDUsage_GD_Rz:
- case kHIDUsage_GD_Slider:
- case kHIDUsage_GD_Dial:
- case kHIDUsage_GD_Wheel:
- state = IsAxis;
- break;
- case kHIDUsage_GD_Hatswitch:
- state = IsHat;
- break;
- default:
- break;
- };
- break;
- case kHIDPage_Simulation:
- switch(usage)
- {
- case kHIDUsage_Sim_Rudder:
- case kHIDUsage_Sim_Throttle:
- case kHIDUsage_Sim_Accelerator:
- case kHIDUsage_Sim_Brake:
- state = IsAxis;
- default:
- break;
- }
- break;
- default:
- break;
- };
- Vector<HIDElement>* elements = nullptr;
- switch(state)
- {
- case IsButton:
- elements = &device->buttons;
- break;
- case IsAxis:
- elements = &device->axes;
- break;
- case IsHat:
- elements = &device->hats;
- break;
- default:
- break;
- }
- if(elements != nullptr)
- {
- HIDElement element;
- element.usage = usage;
- element.ref = elemRef;
- element.cookie = IOHIDElementGetCookie(elemRef);
- element.min = element.detectedMin = (INT32)IOHIDElementGetLogicalMin(elemRef);
- element.max = element.detectedMax = (INT32)IOHIDElementGetLogicalMax(elemRef);
- auto iterFind = std::find_if(elements->begin(), elements->end(),
- [&element](const HIDElement& v)
- {
- return v.cookie == element.cookie;
- });
- if(iterFind == elements->end())
- elements->push_back(element);
- }
- }
- /** Parses information about and registers all HID elements in @p array with the @p device. */
- void HIDAddElements(CFArrayRef array, HIDDevice* device)
- {
- CFRange range = { 0, CFArrayGetCount(array) };
- CFArrayApplyFunction(array, range, HIDAddElement, device);
- }
- /**
- * Callback triggered when a HID manager detects a new device. Also called for existing devices when HID manager is
- * first initialized.
- */
- static void HIDDeviceAddedCallback(void* context, IOReturn result, void* sender, IOHIDDeviceRef device)
- {
- auto data = (HIDData*)context;
- for(auto& entry : data->devices)
- {
- if(entry.ref == device)
- return; // Duplicate
- }
- HIDDevice newDevice;
- newDevice.ref = device;
- // Parse device name
- CFTypeRef propertyRef = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey));
- if(!propertyRef)
- propertyRef = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDManufacturerKey));
- if(propertyRef)
- {
- char buffer[256];
- if(CFStringGetCString((CFStringRef)propertyRef, buffer, sizeof(buffer), kCFStringEncodingUTF8))
- newDevice.name = String(buffer);
- }
- // Parse device elements
- CFArrayRef elements = IOHIDDeviceCopyMatchingElements(device, nullptr, kIOHIDOptionsTypeNone);
- if(elements)
- {
- HIDAddElements(elements, &newDevice);
- CFRelease(elements);
- }
- // Create a queue
- newDevice.queueRef = IOHIDQueueCreate(kCFAllocatorDefault, device, 128, kIOHIDOptionsTypeNone);
- for(auto& button : newDevice.buttons)
- IOHIDQueueAddElement(newDevice.queueRef, button.ref);
- for(auto& hat : newDevice.hats)
- IOHIDQueueAddElement(newDevice.queueRef, hat.ref);
- IOHIDQueueStart(newDevice.queueRef);
- // Assign a device ID
- if(data->type == HIDType::Gamepad)
- {
- auto freeId = (UINT32)-1;
- auto numDevices = (UINT32)data->devices.size();
- for(UINT32 i = 0; i < numDevices; i++)
- {
- bool validId = true;
- for(auto& entry : data->devices)
- {
- if(entry.id == i)
- {
- validId = false;
- break;
- }
- }
- if(validId)
- {
- freeId = i;
- break;
- }
- }
- if(freeId == (UINT32)-1)
- freeId = numDevices;
- newDevice.id = freeId;
- }
- else // All keyboard/mouse devices are coalesced into a single device
- newDevice.id = 0;
- data->devices.push_back(newDevice);
- // Register the gamepad device with Input manager
- if(data->type == HIDType::Gamepad)
- {
- InputPrivateData* pvtData = data->owner->_getPrivateData();
- GamepadInfo gamepadInfo;
- gamepadInfo.name = newDevice.name;
- gamepadInfo.id = newDevice.id;
- gamepadInfo.deviceRef = newDevice.ref;
- gamepadInfo.hid = nullptr;
- pvtData->gamepadInfos.push_back(gamepadInfo);
- }
- }
- /** Callback triggered when an input device is removed. */
- static void HIDDeviceRemovedCallback(void* context, IOReturn result, void* sender, IOHIDDeviceRef device)
- {
- auto data = (HIDData*)context;
- auto iterFind = std::find_if(data->devices.begin(), data->devices.end(),
- [&device](const HIDDevice& v)
- {
- return v.ref == device;
- });
- if(iterFind != data->devices.end())
- {
- IOHIDQueueStop(iterFind->queueRef);
- CFRelease(iterFind->queueRef);
- // Unregister the gamepad device from the Input manager
- if(data->type == HIDType::Gamepad)
- {
- InputPrivateData* pvtData = data->owner->_getPrivateData();
- UINT32 deviceId = iterFind->id;
- auto iterFind2 = std::find_if(
- pvtData->gamepadInfos.begin(),
- pvtData->gamepadInfos.end(),
- [deviceId](const GamepadInfo& info)
- {
- return info.id == deviceId;
- });
- if(iterFind2 != pvtData->gamepadInfos.end())
- pvtData->gamepadInfos.erase(iterFind2);
- }
- data->devices.erase(iterFind);
- }
- }
- /** Reads the current value of a particular HID element (e.g. button, axis). */
- static INT32 HIDGetElementValue(const HIDDevice &device, const HIDElement &element)
- {
- IOHIDValueRef valueRef;
- if(IOHIDDeviceGetValue(device.ref, element.ref, &valueRef) != kIOReturnSuccess)
- return 0;
- auto value = (INT32) IOHIDValueGetIntegerValue(valueRef);
- if(value < element.detectedMin)
- element.detectedMin = value;
- if(value > element.detectedMax)
- element.detectedMax = value;
- return value;
- }
- /**
- * Reads the current value of a particular HID element (e.g. button, axis) and converts the value so it fits
- * the provided [min, max] range.
- */
- static INT32 HIDGetElementValueScaled(const HIDDevice &device, const HIDElement &element, INT32 min, INT32 max)
- {
- INT32 value = HIDGetElementValue(device, element);
- float deviceRange = element.detectedMax - element.detectedMin;
- if(deviceRange == 0.0f)
- return value;
- float normalizedRange = (value - element.detectedMin) / deviceRange;
- float targetRange = max - min;
- return (INT32)(normalizedRange * targetRange) + min;
- }
- /** Converts a keyboard scan key (as reported by the HID manager) into engine's ButtonCode. */
- static ButtonCode scanCodeToKeyCode(UINT32 scanCode)
- {
- switch(scanCode)
- {
- case 0x04: return BC_A;
- case 0x05: return BC_B;
- case 0x06: return BC_C;
- case 0x07: return BC_D;
- case 0x08: return BC_E;
- case 0x09: return BC_F;
- case 0x0a: return BC_G;
- case 0x0b: return BC_H;
- case 0x0c: return BC_I;
- case 0x0d: return BC_J;
- case 0x0e: return BC_K;
- case 0x0f: return BC_L;
- case 0x10: return BC_M;
- case 0x11: return BC_N;
- case 0x12: return BC_O;
- case 0x13: return BC_P;
- case 0x14: return BC_Q;
- case 0x15: return BC_R;
- case 0x16: return BC_S;
- case 0x17: return BC_T;
- case 0x18: return BC_U;
- case 0x19: return BC_V;
- case 0x1a: return BC_W;
- case 0x1b: return BC_X;
- case 0x1c: return BC_Y;
- case 0x1d: return BC_Z;
- case 0x1e: return BC_1;
- case 0x1f: return BC_2;
- case 0x20: return BC_3;
- case 0x21: return BC_4;
- case 0x22: return BC_5;
- case 0x23: return BC_6;
- case 0x24: return BC_7;
- case 0x25: return BC_8;
- case 0x26: return BC_9;
- case 0x27: return BC_0;
- case 0x28: return BC_RETURN;
- case 0x29: return BC_ESCAPE;
- case 0x2a: return BC_BACK;
- case 0x2b: return BC_TAB;
- case 0x2c: return BC_SPACE;
- case 0x2d: return BC_MINUS;
- case 0x2e: return BC_EQUALS;
- case 0x2f: return BC_LBRACKET;
- case 0x30: return BC_RBRACKET;
- case 0x31: return BC_BACKSLASH;
- case 0x32: return BC_GRAVE;
- case 0x33: return BC_SEMICOLON;
- case 0x34: return BC_APOSTROPHE;
- case 0x35: return BC_GRAVE;
- case 0x36: return BC_COMMA;
- case 0x37: return BC_PERIOD;
- case 0x38: return BC_SLASH;
- case 0x39: return BC_CAPITAL;
- case 0x3a: return BC_F1;
- case 0x3b: return BC_F2;
- case 0x3c: return BC_F3;
- case 0x3d: return BC_F4;
- case 0x3e: return BC_F5;
- case 0x3f: return BC_F6;
- case 0x40: return BC_F7;
- case 0x41: return BC_F8;
- case 0x42: return BC_F9;
- case 0x43: return BC_F10;
- case 0x44: return BC_F11;
- case 0x45: return BC_F12;
- case 0x46: return BC_SYSRQ;
- case 0x47: return BC_SCROLL;
- case 0x48: return BC_PAUSE;
- case 0x49: return BC_INSERT;
- case 0x4a: return BC_HOME;
- case 0x4b: return BC_PGUP;
- case 0x4c: return BC_DELETE;
- case 0x4d: return BC_END;
- case 0x4e: return BC_PGDOWN;
- case 0x4f: return BC_RIGHT;
- case 0x50: return BC_LEFT;
- case 0x51: return BC_DOWN;
- case 0x52: return BC_UP;
- case 0x53: return BC_NUMLOCK;
- case 0x54: return BC_DIVIDE;
- case 0x55: return BC_MULTIPLY;
- case 0x56: return BC_SUBTRACT;
- case 0x57: return BC_ADD;
- case 0x58: return BC_NUMPADENTER;
- case 0x59: return BC_NUMPAD1;
- case 0x5a: return BC_NUMPAD2;
- case 0x5b: return BC_NUMPAD3;
- case 0x5c: return BC_NUMPAD4;
- case 0x5d: return BC_NUMPAD5;
- case 0x5e: return BC_NUMPAD6;
- case 0x5f: return BC_NUMPAD7;
- case 0x60: return BC_NUMPAD8;
- case 0x61: return BC_NUMPAD9;
- case 0x62: return BC_NUMPAD0;
- case 0x63: return BC_NUMPADCOMMA;
- case 0x64: return BC_OEM_102;
- case 0x66: return BC_POWER;
- case 0x67: return BC_NUMPADEQUALS;
- case 0x68: return BC_F13;
- case 0x69: return BC_F14;
- case 0x6a: return BC_F15;
- case 0x78: return BC_STOP;
- case 0x7f: return BC_MUTE;
- case 0x80: return BC_VOLUMEUP;
- case 0x81: return BC_VOLUMEDOWN;
- case 0x85: return BC_NUMPADCOMMA;
- case 0x86: return BC_NUMPADEQUALS;
- case 0x89: return BC_YEN;
- case 0xe0: return BC_LCONTROL;
- case 0xe1: return BC_LSHIFT;
- case 0xe2: return BC_LMENU;
- case 0xe3: return BC_LWIN;
- case 0xe4: return BC_RCONTROL;
- case 0xe5: return BC_RSHIFT;
- case 0xe6: return BC_RMENU;
- case 0xe7: return BC_RWIN;
- case 0xe8: return BC_PLAYPAUSE;
- case 0xe9: return BC_MEDIASTOP;
- case 0xea: return BC_PREVTRACK;
- case 0xeb: return BC_NEXTTRACK;
- case 0xed: return BC_VOLUMEUP;
- case 0xee: return BC_VOLUMEDOWN;
- case 0xef: return BC_MUTE;
- case 0xf0: return BC_WEBSEARCH;
- case 0xf1: return BC_WEBBACK;
- case 0xf2: return BC_WEBFORWARD;
- case 0xf3: return BC_WEBSTOP;
- case 0xf4: return BC_WEBSEARCH;
- case 0xf8: return BC_SLEEP;
- case 0xf9: return BC_WAKE;
- case 0xfb: return BC_CALCULATOR;
- default:
- return BC_UNASSIGNED;
- }
- }
- HIDManager::HIDManager(HIDType type, Input* input)
- {
- mData.type = type;
- mData.owner = input;
- mHIDManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDManagerOptionNone);
- if(mHIDManager == nullptr)
- return;
- if(IOHIDManagerOpen(mHIDManager, kIOHIDOptionsTypeNone) != kIOReturnSuccess)
- return;
- UINT32 numEntries = 0;
- const void* entries[3];
- switch (type)
- {
- case HIDType::Keyboard:
- entries[0] = createHIDDeviceMatchDictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_Keyboard);
- numEntries = 1;
- break;
- case HIDType::Mouse:
- entries[0] = createHIDDeviceMatchDictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_Mouse);
- numEntries = 1;
- break;
- case HIDType::Gamepad:
- entries[0] = createHIDDeviceMatchDictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick);
- entries[1] = createHIDDeviceMatchDictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad);
- entries[2] = createHIDDeviceMatchDictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_MultiAxisController);
- numEntries = 3;
- break;
- }
- CFArrayRef entryArray = CFArrayCreate(kCFAllocatorDefault, entries, numEntries, &kCFTypeArrayCallBacks);
- IOHIDManagerSetDeviceMatchingMultiple(mHIDManager, entryArray);
- IOHIDManagerRegisterDeviceMatchingCallback(mHIDManager, HIDDeviceAddedCallback, &mData);
- IOHIDManagerRegisterDeviceRemovalCallback(mHIDManager, HIDDeviceRemovedCallback, &mData);
- CFStringRef runLoopMode = getRunLoopMode(type);
- IOHIDManagerScheduleWithRunLoop(mHIDManager, CFRunLoopGetCurrent(), runLoopMode);
- while(CFRunLoopRunInMode(runLoopMode, 0, TRUE) == kCFRunLoopRunHandledSource)
- { /* Do nothing */ }
- for (UINT32 i = 0; i < numEntries; i++)
- {
- if (entries[i])
- CFRelease((CFTypeRef) entries[i]);
- }
- CFRelease(entryArray);
- }
- HIDManager::~HIDManager()
- {
- for(auto& device : mData.devices)
- {
- IOHIDQueueStop(device.queueRef);
- CFRelease(device.queueRef);
- }
- CFStringRef runLoopMode = getRunLoopMode(mData.type);
- IOHIDManagerUnscheduleFromRunLoop(mHIDManager, CFRunLoopGetCurrent(), runLoopMode);
- IOHIDManagerClose(mHIDManager, kIOHIDOptionsTypeNone);
- CFRelease(mHIDManager);
- }
- void HIDManager::capture(IOHIDDeviceRef device, bool ignoreEvents)
- {
- // First trigger any callbacks
- CFStringRef runLoopMode = getRunLoopMode(mData.type);
- while(CFRunLoopRunInMode(runLoopMode, 0, TRUE) == kCFRunLoopRunHandledSource)
- { /* Do nothing */ }
- for(auto& entry : mData.devices)
- {
- if(device != nullptr && entry.ref != device)
- continue;
- // Read non-queued elements
- if(!ignoreEvents)
- {
- INT32 relX, relY, relZ;
- relX = relY = relZ = 0;
- struct AxisState
- {
- bool moved;
- INT32 value;
- };
- AxisState axisValues[24];
- bs_zero_out(axisValues);
- for (auto& axis : entry.axes)
- {
- auto axisType = (InputAxis) -1;
- if (mData.type == HIDType::Gamepad)
- {
- INT32 axisValue = HIDGetElementValueScaled(entry, axis, Gamepad::MIN_AXIS, Gamepad::MAX_AXIS);
- INT32 lastInputAxis = (INT32) InputAxis::RightTrigger + 1;
- switch (axis.usage)
- {
- case kHIDUsage_GD_X:
- axisType = InputAxis::LeftStickX;
- break;
- case kHIDUsage_GD_Y:
- axisType = InputAxis::LeftStickY;
- break;
- case kHIDUsage_GD_Rx:
- axisType = InputAxis::RightStickX;
- break;
- case kHIDUsage_GD_Ry:
- axisType = InputAxis::RightStickY;
- break;
- case kHIDUsage_GD_Z:
- axisType = InputAxis::LeftTrigger;
- break;
- case kHIDUsage_GD_Rz:
- axisType = InputAxis::RightTrigger;
- break;
- case kHIDUsage_GD_Slider:
- axisType = (InputAxis) (lastInputAxis + 1);
- break;
- case kHIDUsage_GD_Dial:
- axisType = (InputAxis) (lastInputAxis + 2);
- break;
- case kHIDUsage_GD_Wheel:
- axisType = (InputAxis) (lastInputAxis + 3);
- break;
- case kHIDUsage_Sim_Rudder:
- axisType = (InputAxis) (lastInputAxis + 4);
- break;
- case kHIDUsage_Sim_Throttle:
- axisType = (InputAxis) (lastInputAxis + 5);
- break;
- case kHIDUsage_Sim_Accelerator:
- axisType = (InputAxis) (lastInputAxis + 6);
- break;
- case kHIDUsage_Sim_Brake:
- axisType = (InputAxis) (lastInputAxis + 7);
- break;
- default:
- break;
- }
- if((INT32)axisType < 24)
- {
- axisValues[(INT32)axisType].moved = true;
- axisValues[(INT32)axisType].value = axisValue;
- }
- }
- else if (mData.type == HIDType::Mouse)
- {
- INT32 axisValue = HIDGetElementValue(entry, axis);
- switch (axis.usage)
- {
- case kHIDUsage_GD_X:
- axisType = InputAxis::MouseX;
- relX += axisValue;
- break;
- case kHIDUsage_GD_Y:
- axisType = InputAxis::MouseY;
- relY += axisValue;
- break;
- case kHIDUsage_GD_Z:
- axisType = InputAxis::MouseZ;
- relZ += axisValue;
- break;
- default:
- break;
- }
- }
- }
- if(relX != 0 || relY != 0 || relZ != 0)
- mData.owner->_notifyMouseMoved(relX, relY, relZ);
- for(UINT32 i = 0; i < 24; i++)
- {
- if(axisValues[i].moved)
- mData.owner->_notifyAxisMoved(entry.id, (UINT32)i, axisValues[i].value);
- }
- }
- // Read queued elements
- while(true)
- {
- IOHIDValueRef valueRef = IOHIDQueueCopyNextValueWithTimeout(entry.queueRef, 0);
- if(!valueRef)
- break;
- if(ignoreEvents)
- continue;
- IOHIDElementRef elemRef = IOHIDValueGetElement(valueRef);
- auto value = (INT32) IOHIDValueGetIntegerValue(valueRef); // For buttons this is 1 when pressed, 0 when released
- UINT64 timestamp = IOHIDValueGetTimeStamp(valueRef);
- UINT32 usage = IOHIDElementGetUsage(elemRef);
- UINT32 usagePage = IOHIDElementGetUsagePage(elemRef);
- ButtonCode button = BC_UNASSIGNED;
- if(usagePage == kHIDPage_GenericDesktop)
- {
- if (usage == kHIDUsage_GD_Hatswitch)
- {
- switch (value)
- {
- case 0:
- button = BC_GAMEPAD_DPAD_UP;
- break;
- case 1:
- button = BC_GAMEPAD_DPAD_UPRIGHT;
- break;
- case 2:
- button = BC_GAMEPAD_DPAD_RIGHT;
- break;
- case 3:
- button = BC_GAMEPAD_DPAD_DOWNRIGHT;
- break;
- case 4:
- button = BC_GAMEPAD_DPAD_DOWN;
- break;
- case 5:
- button = BC_GAMEPAD_DPAD_DOWNLEFT;
- break;
- case 6:
- button = BC_GAMEPAD_DPAD_LEFT;
- break;
- case 7:
- button = BC_GAMEPAD_DPAD_UPLEFT;
- break;
- default:
- break;
- }
- }
- }
- else if(usagePage == kHIDPage_Button)
- {
- if(mData.type == HIDType::Mouse)
- {
- if (usage > 0 && usage <= BC_NumMouse)
- button = (ButtonCode) ((UINT32) BC_MOUSE_LEFT + usage - 1);
- }
- else if(mData.type == HIDType::Gamepad)
- {
- // These are based on the xbox controller:
- switch(usage)
- {
- case 0: break;
- case 1: button = BC_GAMEPAD_A; break;
- case 2: button = BC_GAMEPAD_B; break;
- case 3: button = BC_GAMEPAD_X; break;
- case 4: button = BC_GAMEPAD_Y; break;
- case 5: button = BC_GAMEPAD_LB; break;
- case 6: button = BC_GAMEPAD_RB; break;
- case 7: button = BC_GAMEPAD_LS; break;
- case 8: button = BC_GAMEPAD_RS; break;
- case 9: button = BC_GAMEPAD_START; break;
- case 10: button = BC_GAMEPAD_BACK; break;
- case 11: button = BC_GAMEPAD_BTN1; break;
- case 12: button = BC_GAMEPAD_DPAD_UP; break;
- case 13: button = BC_GAMEPAD_DPAD_DOWN; break;
- case 14: button = BC_GAMEPAD_DPAD_LEFT; break;
- case 15: button = BC_GAMEPAD_DPAD_RIGHT; break;
- default:
- {
- INT32 buttonIdx = usage - 16;
- if(buttonIdx < 19)
- button = (ButtonCode)((INT32)(BC_GAMEPAD_BTN2 + buttonIdx));
- }
- break;
- }
- }
- }
- else if(usagePage == kHIDPage_KeyboardOrKeypad)
- {
- // Usage -1 and 1 are special signals that happen along with every button press/release and should be
- // ignored
- if(usage != -1 && usage != 1)
- button = scanCodeToKeyCode((UINT32)value);
- }
- if(button != BC_UNASSIGNED)
- {
- if(value != 0)
- mData.owner->_notifyButtonPressed(entry.id, button, timestamp);
- else
- mData.owner->_notifyButtonReleased(entry.id, button, timestamp);
- }
- CFRelease(valueRef);
- }
- }
- }
- void Input::initRawInput()
- {
- mPlatformData = bs_new<InputPrivateData>();
- mKeyboard = bs_new<Keyboard>("Keyboard", this);
- mMouse = bs_new<Mouse>("Mouse", this);
- mPlatformData->gamepadHIDManager = bs_new<HIDManager>(HIDType::Gamepad, this);
- for(auto& entry : mPlatformData->gamepadInfos)
- {
- entry.hid = mPlatformData->gamepadHIDManager;
- mGamepads.push_back(bs_new<Gamepad>(entry.name, entry, this));
- }
- }
- void Input::cleanUpRawInput()
- {
- if (mMouse != nullptr)
- bs_delete(mMouse);
- if (mKeyboard != nullptr)
- bs_delete(mKeyboard);
- for (auto& gamepad : mGamepads)
- bs_delete(gamepad);
- bs_delete(mPlatformData->gamepadHIDManager);
- bs_delete(mPlatformData);
- }
- UINT32 Input::getDeviceCount(InputDevice device) const
- {
- switch(device)
- {
- case InputDevice::Keyboard: return 1;
- case InputDevice::Mouse: return 1;
- case InputDevice::Gamepad: return (UINT32)mPlatformData->gamepadInfos.size();
- case InputDevice::Count: return 0;
- }
- return 0;
- }
- }
|