/* * Copyright (C) 2020 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "MultiGamepadProvider.h" #if ENABLE(GAMEPAD) && HAVE(MULTIGAMEPADPROVIDER_SUPPORT) #import "GameControllerGamepadProvider.h" #import "HIDGamepadProvider.h" #import "Logging.h" #import "PlatformGamepad.h" #import namespace WebCore { static size_t numberOfGamepadProviders = 2; MultiGamepadProvider& MultiGamepadProvider::singleton() { static NeverDestroyed sharedProvider; return sharedProvider; } void MultiGamepadProvider::startMonitoringGamepads(GamepadProviderClient& client) { bool monitorOtherProviders = m_clients.isEmpty(); ASSERT(!m_clients.contains(&client)); m_clients.add(&client); if (!m_usesOnlyHIDProvider) { HIDGamepadProvider::singleton().ignoreGameControllerFrameworkDevices(); GameControllerGamepadProvider::singleton().prewarmGameControllerDevicesIfNecessary(); } if (monitorOtherProviders) { HIDGamepadProvider::singleton().startMonitoringGamepads(*this); if (!m_usesOnlyHIDProvider) GameControllerGamepadProvider::singleton().startMonitoringGamepads(*this); } } void MultiGamepadProvider::stopMonitoringGamepads(GamepadProviderClient& client) { ASSERT(m_clients.contains(&client)); bool shouldStopMonitoringOtherProviders = m_clients.remove(&client) && m_clients.isEmpty(); if (shouldStopMonitoringOtherProviders) { HIDGamepadProvider::singleton().stopMonitoringGamepads(*this); if (!m_usesOnlyHIDProvider) GameControllerGamepadProvider::singleton().stopMonitoringGamepads(*this); } } unsigned MultiGamepadProvider::indexForNewlyConnectedDevice() { unsigned index = 0; while (index < m_gamepadVector.size() && m_gamepadVector[index]) ++index; ASSERT(index <= m_gamepadVector.size()); if (index == m_gamepadVector.size()) m_gamepadVector.resize(index + 1); return index; } void MultiGamepadProvider::platformGamepadConnected(PlatformGamepad& gamepad, EventMakesGamepadsVisible eventVisibility) { auto index = indexForNewlyConnectedDevice(); LOG(Gamepad, "MultiGamepadProvider adding new platform gamepad to index %i from a %s source", index, gamepad.source()); ASSERT(m_gamepadVector.size() > index); auto addResult = m_gamepadMap.set(&gamepad, WTF::makeUnique(index, &gamepad)); ASSERT(addResult.isNewEntry); m_gamepadVector[index] = addResult.iterator->value.get(); for (auto& client : m_clients) client->platformGamepadConnected(*m_gamepadVector[index], eventVisibility); } void MultiGamepadProvider::platformGamepadDisconnected(PlatformGamepad& gamepad) { LOG(Gamepad, "MultiGamepadProvider disconnecting gamepad from a %s source", gamepad.source()); auto gamepadWrapper = m_gamepadMap.take(&gamepad); ASSERT(gamepadWrapper); ASSERT(gamepadWrapper->index() < m_gamepadVector.size()); ASSERT(m_gamepadVector[gamepadWrapper->index()] == gamepadWrapper.get()); m_gamepadVector[gamepadWrapper->index()] = nullptr; for (auto& client : m_clients) client->platformGamepadDisconnected(*gamepadWrapper); } void MultiGamepadProvider::platformGamepadInputActivity(EventMakesGamepadsVisible eventVisibility) { if (eventVisibility == EventMakesGamepadsVisible::Yes) GameControllerGamepadProvider::singleton().makeInvisibleGamepadsVisible(); for (auto& client : m_clients) client->platformGamepadInputActivity(eventVisibility); } } // namespace WebCore #endif // ENABLE(GAMEPAD) && HAVE(MULTIGAMEPADPROVIDER_SUPPORT)