Commit 1e500465 authored by James Hollyer's avatar James Hollyer Committed by Commit Bot

Prioritize recognized gamepads

If there is a device that we see as a gamepad it takes up one of the 4
slots for gamepads on a machine.  This causes a large problem when users
need all 4 slots especially if that device is built into the machine.
This CL replaces unrecognized gamepads with recognized ones if we have
more than 4 gamepads.

Bug: 991842
Change-Id: I8964294fd50a4a4b941454fc76ee389859859a29
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1759339
Commit-Queue: James Hollyer <jameshollyer@chromium.org>
Reviewed-by: default avatarMatt Reynolds <mattreynolds@chromium.org>
Cr-Commit-Position: refs/heads/master@{#701391}
parent 100a68cd
......@@ -51,6 +51,10 @@ void GamepadDataFetcher::ResetVibration(
mojom::GamepadHapticsResult::GamepadHapticsResultError);
}
bool GamepadDataFetcher::DisconnectUnrecognizedGamepad(int source_id) {
return false;
}
// static
int64_t GamepadDataFetcher::TimeInMicroseconds(base::TimeTicks update_time) {
return update_time.since_origin().InMicroseconds();
......
......@@ -18,7 +18,7 @@ class Connector;
namespace device {
// Abstract interface for imlementing platform- (and test-) specific behavior
// Abstract interface for implementing platform- (and test-) specific behavior
// for getting the gamepad data.
class DEVICE_GAMEPAD_EXPORT GamepadDataFetcher {
public:
......@@ -38,16 +38,24 @@ class DEVICE_GAMEPAD_EXPORT GamepadDataFetcher {
scoped_refptr<base::SequencedTaskRunner>);
virtual GamepadSource source() = 0;
// Shuts down the gamepad with given |source_id| and removes it from the data
// fetchers list of devices. Default implementation used on data fetchers for
// recognized gamepads because it should never be called on those gamepads.
// Returns a boolean that is true if the gamepad was successfully
// disconnected.
virtual bool DisconnectUnrecognizedGamepad(int source_id);
GamepadPadStateProvider* provider() { return provider_; }
service_manager::Connector* connector() const {
return service_manager_connector_;
}
PadState* GetPadState(int source_id) {
PadState* GetPadState(int source_id, bool new_pad_recognized = true) {
if (!provider_)
return nullptr;
return provider_->GetPadState(source(), source_id);
return provider_->GetPadState(source(), source_id, new_pad_recognized);
}
// Returns the current time value in microseconds. Data fetchers should use
......
......@@ -17,6 +17,9 @@ const float kMinAxisResetValue = 0.1f;
} // namespace
PadState::PadState() = default;
PadState::~PadState() = default;
GamepadPadStateProvider::GamepadPadStateProvider() {
pad_states_.reset(new PadState[Gamepads::kItemsLengthCap]);
......@@ -27,9 +30,11 @@ GamepadPadStateProvider::GamepadPadStateProvider() {
GamepadPadStateProvider::~GamepadPadStateProvider() = default;
PadState* GamepadPadStateProvider::GetPadState(GamepadSource source,
int source_id) {
int source_id,
bool new_gamepad_recognized) {
// Check to see if the device already has a reserved slot
PadState* empty_slot = nullptr;
PadState* unrecognized_slot = nullptr;
for (size_t i = 0; i < Gamepads::kItemsLengthCap; ++i) {
PadState& state = pad_states_.get()[i];
if (state.source == source && state.source_id == source_id) {
......@@ -39,6 +44,14 @@ PadState* GamepadPadStateProvider::GetPadState(GamepadSource source,
}
if (!empty_slot && state.source == GAMEPAD_SOURCE_NONE)
empty_slot = &state;
if (!state.is_recognized)
unrecognized_slot = &state;
}
if (!empty_slot && unrecognized_slot && new_gamepad_recognized) {
DisconnectUnrecognizedGamepad(unrecognized_slot->source,
unrecognized_slot->source_id);
empty_slot = unrecognized_slot;
}
if (empty_slot) {
empty_slot->source = source;
......@@ -46,6 +59,7 @@ PadState* GamepadPadStateProvider::GetPadState(GamepadSource source,
empty_slot->is_active = true;
empty_slot->is_newly_active = true;
empty_slot->is_initialized = false;
empty_slot->is_recognized = new_gamepad_recognized;
}
return empty_slot;
}
......
......@@ -46,6 +46,9 @@ enum GamepadSource {
};
struct PadState {
PadState();
~PadState();
// Which data fetcher provided this gamepad's data.
GamepadSource source;
// Data fetcher-specific identifier for this gamepad.
......@@ -64,6 +67,11 @@ struct PadState {
// gamepad has been completed.
bool is_initialized;
// Set by the data fetcher to indicate whether this gamepad's ids are
// recognized as a specific gamepad. It is then used to prioritize recognized
// gamepads when finding an empty slot for any new gamepads when activated.
bool is_recognized;
// Gamepad data, unmapped.
Gamepad data;
......@@ -96,8 +104,12 @@ class DEVICE_GAMEPAD_EXPORT GamepadPadStateProvider {
// Gets a PadState object for the given source and id. If the device hasn't
// been encountered before one of the remaining slots will be reserved for it.
// If no slots are available will return NULL.
PadState* GetPadState(GamepadSource source, int source_id);
// If no slots are available this returns nullptr. However, if one of those
// slots contains an unrecognized gamepad and |new_gamepad_recognized| is true
// that slot will be reset and returned.
PadState* GetPadState(GamepadSource source,
int source_id,
bool new_gamepad_recognized);
// Gets a PadState object for a connected gamepad by specifying its index in
// the pad_states_ array. Returns NULL if there is no connected gamepad at
......@@ -117,6 +129,13 @@ class DEVICE_GAMEPAD_EXPORT GamepadPadStateProvider {
// Tracks the state of each gamepad slot.
std::unique_ptr<PadState[]> pad_states_;
private:
// Calls the DisconnectUnrecognizedGamepad method on the data fetcher
// associated with the given |source|. The actual implementation is always
// in the |gamepad_provider|.
virtual void DisconnectUnrecognizedGamepad(GamepadSource source,
int source_id) = 0;
};
} // namespace device
......
......@@ -106,7 +106,7 @@ void GamepadPlatformDataFetcherLinux::RefreshDevice(udev_device* dev) {
if (pad_info.type == UdevGamepadLinux::Type::JOYDEV) {
// If |syspath_prefix| is empty, the device was already disconnected.
if (pad_info.syspath_prefix.empty())
RemoveDeviceAtIndex(pad_info.index);
DisconnectUnrecognizedGamepad(pad_info.index);
else
RefreshJoydevDevice(dev, pad_info);
} else if (pad_info.type == UdevGamepadLinux::Type::EVDEV) {
......@@ -138,15 +138,16 @@ void GamepadPlatformDataFetcherLinux::RemoveDevice(GamepadDeviceLinux* device) {
}
}
void GamepadPlatformDataFetcherLinux::RemoveDeviceAtIndex(int index) {
bool GamepadPlatformDataFetcherLinux::DisconnectUnrecognizedGamepad(int index) {
for (auto it = devices_.begin(); it != devices_.end(); ++it) {
const auto& device = *it;
if (device->GetJoydevIndex() == index) {
device->Shutdown();
devices_.erase(it);
return;
return true;
}
}
return false;
}
GamepadDeviceLinux* GamepadPlatformDataFetcherLinux::GetOrCreateMatchingDevice(
......@@ -195,7 +196,10 @@ void GamepadPlatformDataFetcherLinux::RefreshJoydevDevice(
return;
}
PadState* state = GetPadState(joydev_index);
bool is_recognized = GamepadIdList::Get().GetGamepadId(
vendor_id, product_id) != GamepadId::kUnknownGamepad;
PadState* state = GetPadState(joydev_index, is_recognized);
if (!state) {
// No slot available for device, don't use.
device->CloseJoydevNode();
......@@ -217,12 +221,10 @@ void GamepadPlatformDataFetcherLinux::RefreshJoydevDevice(
return;
}
// Joydev uses its own internal list of device IDs to identify known gamepads.
// If the device is on our list, record it by ID. If the device is unknown,
// record that an unknown gamepad was enumerated.
GamepadId gamepad_id =
GamepadIdList::Get().GetGamepadId(vendor_id, product_id);
if (gamepad_id == GamepadId::kUnknownGamepad)
if (is_recognized)
RecordUnknownGamepad(source());
else
RecordConnectedGamepad(vendor_id, product_id);
......
......@@ -48,6 +48,7 @@ class DEVICE_GAMEPAD_EXPORT GamepadPlatformDataFetcherLinux
// GamepadDataFetcher implementation.
void GetGamepadData(bool devices_changed_hint) override;
bool DisconnectUnrecognizedGamepad(int source_id) override;
void PlayEffect(int pad_index,
mojom::GamepadHapticEffectType,
......@@ -75,7 +76,6 @@ class DEVICE_GAMEPAD_EXPORT GamepadPlatformDataFetcherLinux
GamepadDeviceLinux* GetOrCreateMatchingDevice(
const UdevGamepadLinux& pad_info);
void RemoveDevice(GamepadDeviceLinux* device);
void RemoveDeviceAtIndex(int index);
// UdevWatcher::Observer overrides
void OnDeviceAdded(ScopedUdevDevicePtr device) override;
......
......@@ -66,18 +66,9 @@ class GamepadPlatformDataFetcherMac : public GamepadDataFetcher {
// GamepadDataFetcher private implementation.
void OnAddedToProvider() override;
// Returns the index of the first empty slot, or Gamepads::kItemsLengthCap if
// there are no empty slots.
size_t GetEmptySlot();
// Returns the index of the slot allocated for this device, or the first empty
// slot if none is yet allocated. If there is no allocated or empty slots,
// returns Gamepads::kItemsLengthCap.
size_t GetSlotForDevice(IOHIDDeviceRef device);
// Returns the index of the slot allocated for the device with the specified
// |location_id|, or Gamepads::kItemsLengthCap if none is yet allocated.
size_t GetSlotForLocation(int location_id);
// Returns the GamepadDeviceMac from |devices_| that has the given device
// reference. Returns nullptr if the device is not in |devices_|.
GamepadDeviceMac* GetGamepadFromHidDevice(IOHIDDeviceRef device);
// Query device info for |device| and add it to |devices_| if it is a
// gamepad.
......@@ -96,11 +87,14 @@ class GamepadPlatformDataFetcherMac : public GamepadDataFetcher {
// Unregister from connection events and value change notifications.
void UnregisterFromNotifications();
bool DisconnectUnrecognizedGamepad(int source_id) override;
bool enabled_ = false;
bool paused_ = false;
base::ScopedCFTypeRef<IOHIDManagerRef> hid_manager_ref_;
std::unique_ptr<GamepadDeviceMac> devices_[Gamepads::kItemsLengthCap];
// A map of all devices using this data fetcher with the source_id as the key.
std::unordered_map<int, std::unique_ptr<GamepadDeviceMac>> devices_;
DISALLOW_COPY_AND_ASSIGN(GamepadPlatformDataFetcherMac);
};
......
......@@ -102,9 +102,8 @@ void GamepadPlatformDataFetcherMac::PauseHint(bool pause) {
GamepadPlatformDataFetcherMac::~GamepadPlatformDataFetcherMac() {
UnregisterFromNotifications();
for (size_t slot = 0; slot < Gamepads::kItemsLengthCap; ++slot) {
if (devices_[slot] != nullptr)
devices_[slot]->Shutdown();
for (auto& iter : devices_) {
iter.second->Shutdown();
}
}
......@@ -134,31 +133,15 @@ void GamepadPlatformDataFetcherMac::ValueChangedCallback(void* context,
InstanceFromContext(context)->ValueChanged(ref);
}
size_t GamepadPlatformDataFetcherMac::GetEmptySlot() {
// Find a free slot for this device.
for (size_t slot = 0; slot < Gamepads::kItemsLengthCap; ++slot) {
if (devices_[slot] == nullptr)
return slot;
GamepadDeviceMac* GamepadPlatformDataFetcherMac::GetGamepadFromHidDevice(
IOHIDDeviceRef device) {
for (auto& iter : devices_) {
if (iter.second->IsSameDevice(device)) {
return iter.second.get();
}
}
return Gamepads::kItemsLengthCap;
}
size_t GamepadPlatformDataFetcherMac::GetSlotForDevice(IOHIDDeviceRef device) {
for (size_t slot = 0; slot < Gamepads::kItemsLengthCap; ++slot) {
// If we already have this device, and it's already connected, don't do
// anything now.
if (devices_[slot] != nullptr && devices_[slot]->IsSameDevice(device))
return Gamepads::kItemsLengthCap;
}
return GetEmptySlot();
}
size_t GamepadPlatformDataFetcherMac::GetSlotForLocation(int location_id) {
for (size_t slot = 0; slot < Gamepads::kItemsLengthCap; ++slot) {
if (devices_[slot] && devices_[slot]->GetLocationId() == location_id)
return slot;
}
return Gamepads::kItemsLengthCap;
return nullptr;
}
void GamepadPlatformDataFetcherMac::DeviceAdd(IOHIDDeviceRef device) {
......@@ -172,9 +155,6 @@ void GamepadPlatformDataFetcherMac::DeviceAdd(IOHIDDeviceRef device) {
IOHIDDeviceGetProperty(device, CFSTR(kIOHIDLocationIDKey))));
int location_int = [location_id intValue];
// Find an index for this device.
size_t slot = GetSlotForDevice(device);
NSNumber* vendor_id = CFToNSCast(CFCastStrict<CFNumberRef>(
IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVendorIDKey))));
NSNumber* product_id = CFToNSCast(CFCastStrict<CFNumberRef>(
......@@ -201,21 +181,23 @@ void GamepadPlatformDataFetcherMac::DeviceAdd(IOHIDDeviceRef device) {
const auto& gamepad_id_list = GamepadIdList::Get();
DCHECK_EQ(kXInputTypeNone,
gamepad_id_list.GetXInputType(vendor_int, product_int));
RecordConnectedGamepad(vendor_int, product_int);
// We can't handle this many connected devices.
if (slot == Gamepads::kItemsLengthCap)
if (devices_.find(location_int) != devices_.end())
return;
RecordConnectedGamepad(vendor_int, product_int);
// The SteelSeries Nimbus and other Made for iOS gamepads should be handled
// through the GameController interface. Blacklist it here so it doesn't
// take up an additional gamepad slot.
// through the GameController interface.
if (gamepad_id_list.GetGamepadId(vendor_int, product_int) ==
GamepadId::kSteelSeriesProduct1420) {
return;
}
PadState* state = GetPadState(location_int);
bool is_recognized = gamepad_id_list.GetGamepadId(vendor_int, product_int) !=
GamepadId::kUnknownGamepad;
PadState* state = GetPadState(location_int, is_recognized);
if (!state)
return; // No available slot for this device
......@@ -232,34 +214,42 @@ void GamepadPlatformDataFetcherMac::DeviceAdd(IOHIDDeviceRef device) {
state->data.mapping =
state->mapper ? GamepadMapping::kStandard : GamepadMapping::kNone;
devices_[slot] = std::make_unique<GamepadDeviceMac>(location_int, device,
vendor_int, product_int);
if (!devices_[slot]->AddButtonsAndAxes(&state->data)) {
devices_[slot]->Shutdown();
devices_[slot] = nullptr;
auto new_device = std::make_unique<GamepadDeviceMac>(location_int, device,
vendor_int, product_int);
if (!new_device->AddButtonsAndAxes(&state->data)) {
new_device->Shutdown();
return;
}
state->data.vibration_actuator.type = GamepadHapticActuatorType::kDualRumble;
state->data.vibration_actuator.not_null = devices_[slot]->SupportsVibration();
state->data.vibration_actuator.not_null = new_device->SupportsVibration();
state->data.connected = true;
devices_.emplace(location_int, std::move(new_device));
}
bool GamepadPlatformDataFetcherMac::DisconnectUnrecognizedGamepad(
int source_id) {
auto gamepad_iter = devices_.find(source_id);
if (gamepad_iter == devices_.end())
return false;
gamepad_iter->second->Shutdown();
devices_.erase(gamepad_iter);
return true;
}
void GamepadPlatformDataFetcherMac::DeviceRemove(IOHIDDeviceRef device) {
if (!enabled_)
return;
// Find the index for this device.
size_t slot;
for (slot = 0; slot < Gamepads::kItemsLengthCap; ++slot) {
if (devices_[slot] != nullptr && devices_[slot]->IsSameDevice(device))
break;
}
if (slot < Gamepads::kItemsLengthCap) {
devices_[slot]->Shutdown();
devices_[slot] = nullptr;
}
GamepadDeviceMac* gamepad_device = GetGamepadFromHidDevice(device);
if (!gamepad_device)
return;
gamepad_device->Shutdown();
devices_.erase(gamepad_device->GetLocationId());
}
void GamepadPlatformDataFetcherMac::ValueChanged(IOHIDValueRef value) {
......@@ -269,20 +259,16 @@ void GamepadPlatformDataFetcherMac::ValueChanged(IOHIDValueRef value) {
IOHIDElementRef element = IOHIDValueGetElement(value);
IOHIDDeviceRef device = IOHIDElementGetDevice(element);
// Find device slot.
size_t slot;
for (slot = 0; slot < Gamepads::kItemsLengthCap; ++slot) {
if (devices_[slot] != nullptr && devices_[slot]->IsSameDevice(device))
break;
}
if (slot == Gamepads::kItemsLengthCap)
GamepadDeviceMac* gamepad_device = GetGamepadFromHidDevice(device);
if (!gamepad_device)
return;
PadState* state = GetPadState(devices_[slot]->GetLocationId());
PadState* state = GetPadState(gamepad_device->GetLocationId());
if (!state)
return;
devices_[slot]->UpdateGamepadForValue(value, &state->data);
gamepad_device->UpdateGamepadForValue(value, &state->data);
}
void GamepadPlatformDataFetcherMac::GetGamepadData(bool) {
......@@ -290,9 +276,8 @@ void GamepadPlatformDataFetcherMac::GetGamepadData(bool) {
return;
// Loop through and GetPadState to indicate the devices are still connected.
for (size_t slot = 0; slot < Gamepads::kItemsLengthCap; ++slot) {
if (devices_[slot])
GetPadState(devices_[slot]->GetLocationId());
for (const auto& iter : devices_) {
GetPadState(iter.first);
}
}
......@@ -302,8 +287,8 @@ void GamepadPlatformDataFetcherMac::PlayEffect(
mojom::GamepadEffectParametersPtr params,
mojom::GamepadHapticsManager::PlayVibrationEffectOnceCallback callback,
scoped_refptr<base::SequencedTaskRunner> callback_runner) {
size_t slot = GetSlotForLocation(source_id);
if (slot == Gamepads::kItemsLengthCap) {
auto device_iter = devices_.find(source_id);
if (device_iter == devices_.end()) {
// No connected gamepad with this location. Probably the effect was issued
// while the gamepad was still connected, so handle this as if it were
// preempted by a disconnect.
......@@ -312,16 +297,16 @@ void GamepadPlatformDataFetcherMac::PlayEffect(
mojom::GamepadHapticsResult::GamepadHapticsResultPreempted);
return;
}
devices_[slot]->PlayEffect(type, std::move(params), std::move(callback),
std::move(callback_runner));
device_iter->second->PlayEffect(type, std::move(params), std::move(callback),
std::move(callback_runner));
}
void GamepadPlatformDataFetcherMac::ResetVibration(
int source_id,
mojom::GamepadHapticsManager::ResetVibrationActuatorCallback callback,
scoped_refptr<base::SequencedTaskRunner> callback_runner) {
size_t slot = GetSlotForLocation(source_id);
if (slot == Gamepads::kItemsLengthCap) {
auto device_iter = devices_.find(source_id);
if (device_iter == devices_.end()) {
// No connected gamepad with this location. Since the gamepad is already
// disconnected, allow the reset to report success.
RunVibrationCallback(
......@@ -329,8 +314,8 @@ void GamepadPlatformDataFetcherMac::ResetVibration(
mojom::GamepadHapticsResult::GamepadHapticsResultComplete);
return;
}
devices_[slot]->ResetVibration(std::move(callback),
std::move(callback_runner));
device_iter->second->ResetVibration(std::move(callback),
std::move(callback_runner));
}
} // namespace device
......@@ -171,7 +171,7 @@ void GamepadPlatformDataFetcherWin::GetGamepadData(bool devices_changed_hint) {
}
void GamepadPlatformDataFetcherWin::GetXInputPadData(int i) {
PadState* pad_state = provider()->GetPadState(GAMEPAD_SOURCE_WIN_XINPUT, i);
PadState* pad_state = GetPadState(i);
if (!pad_state)
return;
......
......@@ -43,12 +43,7 @@ GamepadProvider::ClosureAndThread::~ClosureAndThread() = default;
GamepadProvider::GamepadProvider(
GamepadConnectionChangeClient* connection_change_client,
std::unique_ptr<service_manager::Connector> service_manager_connector)
: is_paused_(true),
have_scheduled_do_poll_(false),
devices_changed_(true),
ever_had_user_gesture_(false),
sanitize_(true),
gamepad_shared_buffer_(std::make_unique<GamepadSharedBuffer>()),
: gamepad_shared_buffer_(std::make_unique<GamepadSharedBuffer>()),
connection_change_client_(connection_change_client),
service_manager_connector_(std::move(service_manager_connector)) {
Initialize(std::unique_ptr<GamepadDataFetcher>());
......@@ -59,12 +54,7 @@ GamepadProvider::GamepadProvider(
std::unique_ptr<service_manager::Connector> service_manager_connector,
std::unique_ptr<GamepadDataFetcher> fetcher,
std::unique_ptr<base::Thread> polling_thread)
: is_paused_(true),
have_scheduled_do_poll_(false),
devices_changed_(true),
ever_had_user_gesture_(false),
sanitize_(true),
gamepad_shared_buffer_(std::make_unique<GamepadSharedBuffer>()),
: gamepad_shared_buffer_(std::make_unique<GamepadSharedBuffer>()),
polling_thread_(std::move(polling_thread)),
connection_change_client_(connection_change_client),
service_manager_connector_(std::move(service_manager_connector)) {
......@@ -395,6 +385,17 @@ void GamepadProvider::DoPoll() {
ScheduleDoPoll();
}
void GamepadProvider::DisconnectUnrecognizedGamepad(GamepadSource source,
int source_id) {
for (auto& fetcher : data_fetchers_) {
if (fetcher->source() == source) {
bool disconnected = fetcher->DisconnectUnrecognizedGamepad(source_id);
DCHECK(disconnected);
return;
}
}
}
void GamepadProvider::ScheduleDoPoll() {
DCHECK(polling_thread_->task_runner()->BelongsToCurrentThread());
if (have_scheduled_do_poll_)
......
......@@ -122,6 +122,10 @@ class DEVICE_GAMEPAD_EXPORT GamepadProvider
// true if any user gesture observers were notified.
bool CheckForUserGesture();
// GamepadPadStateProvider implementation.
void DisconnectUnrecognizedGamepad(GamepadSource source,
int source_id) override;
void PlayEffectOnPollingThread(
uint32_t pad_index,
mojom::GamepadHapticEffectType,
......@@ -140,12 +144,12 @@ class DEVICE_GAMEPAD_EXPORT GamepadProvider
// Keeps track of when the background thread is paused. Access to is_paused_
// must be guarded by is_paused_lock_.
base::Lock is_paused_lock_;
bool is_paused_;
bool is_paused_ = true;
// Keep track of when a polling task is schedlued, so as to prevent us from
// accidentally scheduling more than one at any time, when rapidly toggling
// |is_paused_|.
bool have_scheduled_do_poll_;
bool have_scheduled_do_poll_ = false;
// Lists all observers registered for user gestures, and the thread which
// to issue the callbacks on. Since we always issue the callback on the
......@@ -171,10 +175,10 @@ class DEVICE_GAMEPAD_EXPORT GamepadProvider
// tests. Access to devices_changed_ must be guarded by
// devices_changed_lock_.
base::Lock devices_changed_lock_;
bool devices_changed_;
bool devices_changed_ = true;
bool ever_had_user_gesture_;
bool sanitize_;
bool ever_had_user_gesture_ = false;
bool sanitize_ = true;
// Only used on the polling thread.
using GamepadFetcherVector = std::vector<std::unique_ptr<GamepadDataFetcher>>;
......
......@@ -107,6 +107,17 @@ void RawInputDataFetcher::StopMonitor() {
window_.reset();
}
bool RawInputDataFetcher::DisconnectUnrecognizedGamepad(int source_id) {
for (auto it = controllers_.begin(); it != controllers_.end(); ++it) {
if (it->second->GetSourceId() == source_id) {
it->second->Shutdown();
controllers_.erase(it);
return true;
}
}
return false;
}
void RawInputDataFetcher::ClearControllers() {
for (const auto& entry : controllers_)
entry.second->Shutdown();
......@@ -179,6 +190,10 @@ void RawInputDataFetcher::EnumerateDevices() {
continue;
}
bool is_recognized =
GamepadId::kUnknownGamepad !=
GamepadIdList::Get().GetGamepadId(vendor_int, product_int);
// Record gamepad metrics before excluding XInput devices. This allows
// us to recognize XInput devices even though the XInput API masks
// the vendor and product IDs.
......@@ -194,7 +209,7 @@ void RawInputDataFetcher::EnumerateDevices() {
continue;
}
PadState* state = GetPadState(source_id);
PadState* state = GetPadState(source_id, is_recognized);
if (!state) {
new_device->Shutdown();
continue; // No slot available for this gamepad.
......
......@@ -49,6 +49,8 @@ class RawInputDataFetcher : public GamepadDataFetcher,
mojom::GamepadHapticsManager::ResetVibrationActuatorCallback,
scoped_refptr<base::SequencedTaskRunner>) override;
bool DisconnectUnrecognizedGamepad(int source_id) override;
private:
void OnAddedToProvider() override;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment