diff options
Diffstat (limited to 'dom/gamepad')
-rw-r--r-- | dom/gamepad/cocoa/CocoaGamepad.cpp | 590 | ||||
-rw-r--r-- | dom/gamepad/moz.build | 4 |
2 files changed, 0 insertions, 594 deletions
diff --git a/dom/gamepad/cocoa/CocoaGamepad.cpp b/dom/gamepad/cocoa/CocoaGamepad.cpp deleted file mode 100644 index eb6eda9a17..0000000000 --- a/dom/gamepad/cocoa/CocoaGamepad.cpp +++ /dev/null @@ -1,590 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -// mostly derived from the Allegro source code at: -// http://alleg.svn.sourceforge.net/viewvc/alleg/allegro/branches/4.9/src/macosx/hidjoy.m?revision=13760&view=markup - -#include "mozilla/dom/Gamepad.h" -#include "mozilla/dom/GamepadPlatformService.h" -#include "mozilla/ArrayUtils.h" -#include "mozilla/Unused.h" -#include "nsThreadUtils.h" -#include <CoreFoundation/CoreFoundation.h> -#include <IOKit/hid/IOHIDBase.h> -#include <IOKit/hid/IOHIDKeys.h> -#include <IOKit/hid/IOHIDManager.h> - -#include <stdio.h> -#include <vector> - -namespace { - -using namespace mozilla; -using namespace mozilla::dom; -using std::vector; - -struct Button { - int id; - bool analog; - IOHIDElementRef element; - CFIndex min; - CFIndex max; - - Button(int aId, IOHIDElementRef aElement, CFIndex aMin, CFIndex aMax) : - id(aId), - analog((aMax - aMin) > 1), - element(aElement), - min(aMin), - max(aMax) {} -}; - -struct Axis { - int id; - IOHIDElementRef element; - uint32_t usagePage; - uint32_t usage; - CFIndex min; - CFIndex max; -}; - -typedef bool dpad_buttons[4]; - -// These values can be found in the USB HID Usage Tables: -// http://www.usb.org/developers/hidpage -const unsigned kDesktopUsagePage = 0x01; -const unsigned kSimUsagePage = 0x02; -const unsigned kAcceleratorUsage = 0xC4; -const unsigned kBrakeUsage = 0xC5; -const unsigned kJoystickUsage = 0x04; -const unsigned kGamepadUsage = 0x05; -const unsigned kAxisUsageMin = 0x30; -const unsigned kAxisUsageMax = 0x35; -const unsigned kDpadUsage = 0x39; -const unsigned kButtonUsagePage = 0x09; -const unsigned kConsumerPage = 0x0C; -const unsigned kHomeUsage = 0x223; -const unsigned kBackUsage = 0x224; - - -class Gamepad { - private: - IOHIDDeviceRef mDevice; - nsTArray<Button> buttons; - nsTArray<Axis> axes; - IOHIDElementRef mDpad; - dpad_buttons mDpadState; - - public: - Gamepad() : mDevice(nullptr), mDpad(nullptr), mSuperIndex(-1) {} - bool operator==(IOHIDDeviceRef device) const { return mDevice == device; } - bool empty() const { return mDevice == nullptr; } - void clear() - { - mDevice = nullptr; - buttons.Clear(); - axes.Clear(); - mDpad = nullptr; - mSuperIndex = -1; - } - void init(IOHIDDeviceRef device); - size_t numButtons() { return buttons.Length() + (mDpad ? 4 : 0); } - size_t numAxes() { return axes.Length(); } - - // Index given by our superclass. - uint32_t mSuperIndex; - - bool isDpad(IOHIDElementRef element) const - { - return element == mDpad; - } - - const dpad_buttons& getDpadState() const - { - return mDpadState; - } - - void setDpadState(const dpad_buttons& dpadState) - { - for (unsigned i = 0; i < ArrayLength(mDpadState); i++) { - mDpadState[i] = dpadState[i]; - } - } - - const Button* lookupButton(IOHIDElementRef element) const - { - for (unsigned i = 0; i < buttons.Length(); i++) { - if (buttons[i].element == element) - return &buttons[i]; - } - return nullptr; - } - - const Axis* lookupAxis(IOHIDElementRef element) const - { - for (unsigned i = 0; i < axes.Length(); i++) { - if (axes[i].element == element) - return &axes[i]; - } - return nullptr; - } -}; - -class AxisComparator { -public: - bool Equals(const Axis& a1, const Axis& a2) const - { - return a1.usagePage == a2.usagePage && a1.usage == a2.usage; - } - bool LessThan(const Axis& a1, const Axis& a2) const - { - if (a1.usagePage == a2.usagePage) { - return a1.usage < a2.usage; - } - return a1.usagePage < a2.usagePage; - } -}; - -void Gamepad::init(IOHIDDeviceRef device) -{ - clear(); - mDevice = device; - - CFArrayRef elements = IOHIDDeviceCopyMatchingElements(device, - nullptr, - kIOHIDOptionsTypeNone); - CFIndex n = CFArrayGetCount(elements); - for (CFIndex i = 0; i < n; i++) { - IOHIDElementRef element = (IOHIDElementRef)CFArrayGetValueAtIndex(elements, - i); - uint32_t usagePage = IOHIDElementGetUsagePage(element); - uint32_t usage = IOHIDElementGetUsage(element); - - if (usagePage == kDesktopUsagePage && - usage >= kAxisUsageMin && - usage <= kAxisUsageMax) - { - Axis axis = { int(axes.Length()), - element, - usagePage, - usage, - IOHIDElementGetLogicalMin(element), - IOHIDElementGetLogicalMax(element) }; - axes.AppendElement(axis); - } else if (usagePage == kDesktopUsagePage && usage == kDpadUsage && - // Don't know how to handle d-pads that return weird values. - IOHIDElementGetLogicalMax(element) - IOHIDElementGetLogicalMin(element) == 7) { - mDpad = element; - } else if ((usagePage == kSimUsagePage && - (usage == kAcceleratorUsage || - usage == kBrakeUsage)) || - (usagePage == kButtonUsagePage) || - (usagePage == kConsumerPage && - (usage == kHomeUsage || - usage == kBackUsage))) { - Button button(int(buttons.Length()), element, IOHIDElementGetLogicalMin(element), IOHIDElementGetLogicalMax(element)); - buttons.AppendElement(button); - } else { - //TODO: handle other usage pages - } - } - - AxisComparator comparator; - axes.Sort(comparator); - for (unsigned i = 0; i < axes.Length(); i++) { - axes[i].id = i; - } -} - -class DarwinGamepadService { - private: - IOHIDManagerRef mManager; - vector<Gamepad> mGamepads; - - //Workaround to support running in background thread - CFRunLoopRef mMonitorRunLoop; - nsCOMPtr<nsIThread> mMonitorThread; - - static void DeviceAddedCallback(void* data, IOReturn result, - void* sender, IOHIDDeviceRef device); - static void DeviceRemovedCallback(void* data, IOReturn result, - void* sender, IOHIDDeviceRef device); - static void InputValueChangedCallback(void* data, IOReturn result, - void* sender, IOHIDValueRef newValue); - - void DeviceAdded(IOHIDDeviceRef device); - void DeviceRemoved(IOHIDDeviceRef device); - void InputValueChanged(IOHIDValueRef value); - void StartupInternal(); - - public: - DarwinGamepadService(); - ~DarwinGamepadService(); - void Startup(); - void Shutdown(); - friend class DarwinGamepadServiceStartupRunnable; -}; - -class DarwinGamepadServiceStartupRunnable final : public Runnable -{ - private: - ~DarwinGamepadServiceStartupRunnable() {} - // This Runnable schedules startup of DarwinGamepadService - // in a new thread, pointer to DarwinGamepadService is only - // used by this Runnable within its thread. - DarwinGamepadService MOZ_NON_OWNING_REF *mService; - public: - explicit DarwinGamepadServiceStartupRunnable(DarwinGamepadService *service) - : mService(service) {} - NS_IMETHOD Run() override - { - MOZ_ASSERT(mService); - mService->StartupInternal(); - return NS_OK; - } -}; - -void -DarwinGamepadService::DeviceAdded(IOHIDDeviceRef device) -{ - RefPtr<GamepadPlatformService> service = - GamepadPlatformService::GetParentService(); - if (!service) { - return; - } - - size_t slot = size_t(-1); - for (size_t i = 0; i < mGamepads.size(); i++) { - if (mGamepads[i] == device) - return; - if (slot == size_t(-1) && mGamepads[i].empty()) - slot = i; - } - - if (slot == size_t(-1)) { - slot = mGamepads.size(); - mGamepads.push_back(Gamepad()); - } - mGamepads[slot].init(device); - - // Gather some identifying information - CFNumberRef vendorIdRef = - (CFNumberRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVendorIDKey)); - CFNumberRef productIdRef = - (CFNumberRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductIDKey)); - CFStringRef productRef = - (CFStringRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey)); - int vendorId, productId; - CFNumberGetValue(vendorIdRef, kCFNumberIntType, &vendorId); - CFNumberGetValue(productIdRef, kCFNumberIntType, &productId); - char product_name[128]; - CFStringGetCString(productRef, product_name, - sizeof(product_name), kCFStringEncodingASCII); - char buffer[256]; - sprintf(buffer, "%x-%x-%s", vendorId, productId, product_name); - uint32_t index = service->AddGamepad(buffer, - mozilla::dom::GamepadMappingType::_empty, - (int)mGamepads[slot].numButtons(), - (int)mGamepads[slot].numAxes()); - mGamepads[slot].mSuperIndex = index; -} - -void -DarwinGamepadService::DeviceRemoved(IOHIDDeviceRef device) -{ - RefPtr<GamepadPlatformService> service = - GamepadPlatformService::GetParentService(); - if (!service) { - return; - } - for (size_t i = 0; i < mGamepads.size(); i++) { - if (mGamepads[i] == device) { - service->RemoveGamepad(mGamepads[i].mSuperIndex); - mGamepads[i].clear(); - return; - } - } -} - -/* - * Given a value from a d-pad (POV hat in USB HID terminology), - * represent it as 4 buttons, one for each cardinal direction. - */ -static void -UnpackDpad(int dpad_value, int min, int max, dpad_buttons& buttons) -{ - const unsigned kUp = 0; - const unsigned kDown = 1; - const unsigned kLeft = 2; - const unsigned kRight = 3; - - // Different controllers have different ways of representing - // "nothing is pressed", but they're all outside the range of values. - if (dpad_value < min || dpad_value > max) { - // Nothing is pressed. - return; - } - - // Normalize value to start at 0. - int value = dpad_value - min; - - // Value will be in the range 0-7. The value represents the - // position of the d-pad around a circle, with 0 being straight up, - // 2 being right, 4 being straight down, and 6 being left. - if (value < 2 || value > 6) { - buttons[kUp] = true; - } - if (value > 2 && value < 6) { - buttons[kDown] = true; - } - if (value > 4) { - buttons[kLeft] = true; - } - if (value > 0 && value < 4) { - buttons[kRight] = true; - } -} - -void -DarwinGamepadService::InputValueChanged(IOHIDValueRef value) -{ - RefPtr<GamepadPlatformService> service = - GamepadPlatformService::GetParentService(); - if (!service) { - return; - } - - uint32_t value_length = IOHIDValueGetLength(value); - if (value_length > 4) { - // Workaround for bizarre issue with PS3 controllers that try to return - // massive (30+ byte) values and crash IOHIDValueGetIntegerValue - return; - } - IOHIDElementRef element = IOHIDValueGetElement(value); - IOHIDDeviceRef device = IOHIDElementGetDevice(element); - - for (unsigned i = 0; i < mGamepads.size(); i++) { - Gamepad &gamepad = mGamepads[i]; - if (gamepad == device) { - if (gamepad.isDpad(element)) { - const dpad_buttons& oldState = gamepad.getDpadState(); - dpad_buttons newState = { false, false, false, false }; - UnpackDpad(IOHIDValueGetIntegerValue(value), - IOHIDElementGetLogicalMin(element), - IOHIDElementGetLogicalMax(element), - newState); - const int numButtons = gamepad.numButtons(); - for (unsigned b = 0; b < ArrayLength(newState); b++) { - if (newState[b] != oldState[b]) { - service->NewButtonEvent(gamepad.mSuperIndex, - numButtons - 4 + b, - newState[b]); - } - } - gamepad.setDpadState(newState); - } else if (const Axis* axis = gamepad.lookupAxis(element)) { - double d = IOHIDValueGetIntegerValue(value); - double v = 2.0f * (d - axis->min) / - (double)(axis->max - axis->min) - 1.0f; - service->NewAxisMoveEvent(gamepad.mSuperIndex, axis->id, v); - } else if (const Button* button = gamepad.lookupButton(element)) { - int iv = IOHIDValueGetIntegerValue(value); - bool pressed = iv != 0; - double v = 0; - if (button->analog) { - double dv = iv; - v = (dv - button->min) / (double)(button->max - button->min); - } else { - v = pressed ? 1.0 : 0.0; - } - service->NewButtonEvent(gamepad.mSuperIndex, button->id, pressed, v); - } - return; - } - } -} - -void -DarwinGamepadService::DeviceAddedCallback(void* data, IOReturn result, - void* sender, IOHIDDeviceRef device) -{ - DarwinGamepadService* service = (DarwinGamepadService*)data; - service->DeviceAdded(device); -} - -void -DarwinGamepadService::DeviceRemovedCallback(void* data, IOReturn result, - void* sender, IOHIDDeviceRef device) -{ - DarwinGamepadService* service = (DarwinGamepadService*)data; - service->DeviceRemoved(device); -} - -void -DarwinGamepadService::InputValueChangedCallback(void* data, - IOReturn result, - void* sender, - IOHIDValueRef newValue) -{ - DarwinGamepadService* service = (DarwinGamepadService*)data; - service->InputValueChanged(newValue); -} - -static CFMutableDictionaryRef -MatchingDictionary(UInt32 inUsagePage, UInt32 inUsage) -{ - CFMutableDictionaryRef dict = - CFDictionaryCreateMutable(kCFAllocatorDefault, - 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - if (!dict) - return nullptr; - CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, - kCFNumberIntType, - &inUsagePage); - if (!number) { - CFRelease(dict); - return nullptr; - } - CFDictionarySetValue(dict, CFSTR(kIOHIDDeviceUsagePageKey), number); - CFRelease(number); - - number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &inUsage); - if (!number) { - CFRelease(dict); - return nullptr; - } - CFDictionarySetValue(dict, CFSTR(kIOHIDDeviceUsageKey), number); - CFRelease(number); - - return dict; -} - -DarwinGamepadService::DarwinGamepadService() : mManager(nullptr) {} - -DarwinGamepadService::~DarwinGamepadService() -{ - if (mManager != nullptr) - CFRelease(mManager); -} - -void -DarwinGamepadService::StartupInternal() -{ - if (mManager != nullptr) - return; - - IOHIDManagerRef manager = IOHIDManagerCreate(kCFAllocatorDefault, - kIOHIDOptionsTypeNone); - - CFMutableDictionaryRef criteria_arr[2]; - criteria_arr[0] = MatchingDictionary(kDesktopUsagePage, - kJoystickUsage); - if (!criteria_arr[0]) { - CFRelease(manager); - return; - } - - criteria_arr[1] = MatchingDictionary(kDesktopUsagePage, - kGamepadUsage); - if (!criteria_arr[1]) { - CFRelease(criteria_arr[0]); - CFRelease(manager); - return; - } - - CFArrayRef criteria = - CFArrayCreate(kCFAllocatorDefault, (const void**)criteria_arr, 2, nullptr); - if (!criteria) { - CFRelease(criteria_arr[1]); - CFRelease(criteria_arr[0]); - CFRelease(manager); - return; - } - - IOHIDManagerSetDeviceMatchingMultiple(manager, criteria); - CFRelease(criteria); - CFRelease(criteria_arr[1]); - CFRelease(criteria_arr[0]); - - IOHIDManagerRegisterDeviceMatchingCallback(manager, - DeviceAddedCallback, - this); - IOHIDManagerRegisterDeviceRemovalCallback(manager, - DeviceRemovedCallback, - this); - IOHIDManagerRegisterInputValueCallback(manager, - InputValueChangedCallback, - this); - IOHIDManagerScheduleWithRunLoop(manager, - CFRunLoopGetCurrent(), - kCFRunLoopDefaultMode); - IOReturn rv = IOHIDManagerOpen(manager, kIOHIDOptionsTypeNone); - if (rv != kIOReturnSuccess) { - CFRelease(manager); - return; - } - - mManager = manager; - - // We held the handle of the CFRunLoop to make sure we - // can shut it down explicitly by CFRunLoopStop in another - // thread. - mMonitorRunLoop = CFRunLoopGetCurrent(); - - // CFRunLoopRun() is a blocking message loop when it's called in - // non-main thread so this thread cannot receive any other runnables - // and nsITimer timeout events after it's called. - CFRunLoopRun(); -} - -void DarwinGamepadService::Startup() -{ - Unused << NS_NewThread(getter_AddRefs(mMonitorThread), - new DarwinGamepadServiceStartupRunnable(this)); -} - -void DarwinGamepadService::Shutdown() -{ - IOHIDManagerRef manager = (IOHIDManagerRef)mManager; - CFRunLoopStop(mMonitorRunLoop); - if (manager) { - IOHIDManagerClose(manager, 0); - CFRelease(manager); - mManager = nullptr; - } - mMonitorThread->Shutdown(); -} - -} // namespace - -namespace mozilla { -namespace dom { - -DarwinGamepadService* gService = nullptr; - -void StartGamepadMonitoring() -{ - if (gService) { - return; - } - - gService = new DarwinGamepadService(); - gService->Startup(); -} - -void StopGamepadMonitoring() -{ - if (!gService) { - return; - } - - gService->Shutdown(); - delete gService; - gService = nullptr; -} - -} // namespace dom -} // namespace mozilla diff --git a/dom/gamepad/moz.build b/dom/gamepad/moz.build index b8e3a855b2..15205e4c83 100644 --- a/dom/gamepad/moz.build +++ b/dom/gamepad/moz.build @@ -48,10 +48,6 @@ if CONFIG['MOZ_GAMEPAD']: SOURCES += [ 'fallback/FallbackGamepad.cpp' ] - elif CONFIG['MOZ_GAMEPAD_BACKEND'] == 'cocoa': - SOURCES += [ - 'cocoa/CocoaGamepad.cpp' - ] elif CONFIG['MOZ_GAMEPAD_BACKEND'] == 'windows': SOURCES += [ 'windows/WindowsGamepad.cpp' |