summaryrefslogtreecommitdiff
path: root/dom/gamepad
diff options
context:
space:
mode:
Diffstat (limited to 'dom/gamepad')
-rw-r--r--dom/gamepad/cocoa/CocoaGamepad.cpp590
-rw-r--r--dom/gamepad/moz.build4
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'