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