Commit f3f5e27d authored by Matt Reynolds's avatar Matt Reynolds Committed by Commit Bot

Allow Chrome on Mac to recognize multiple MFi gamepads

Chrome for Mac recognizes "Made for iOS" (MFi) gamepads enumerated
by the GameController framework. When multiple such devices are
connected at once, Chrome fails to properly distinguish them.

GCController exposes a playerIndex field that defaults to the value
GCControllerPlayerIndexUnset (-1). The application may set this field
to a value between 0 and 3 to signal which LEDs should be lit on the
gamepad. Chrome also uses this field to distinguish gamepads, but does
not set the index to a unique value. This causes the first-connected
gamepad to shadow any other connected gamepads.

This CL ensures each connected MFi gamepad is assigned a unique player
index up to the OS-defined limit of four.

BUG=775270

Change-Id: Ieb852cadc5ff36f94aa1003de3f2e13538114661
Reviewed-on: https://chromium-review.googlesource.com/723852Reviewed-by: default avatarBrandon Jones <bajones@chromium.org>
Commit-Queue: Matt Reynolds <mattreynolds@chromium.org>
Cr-Commit-Position: refs/heads/master@{#509533}
parent 15a799c7
...@@ -30,7 +30,11 @@ class GameControllerDataFetcherMac : public GamepadDataFetcher { ...@@ -30,7 +30,11 @@ class GameControllerDataFetcherMac : public GamepadDataFetcher {
void GetGamepadData(bool devices_changed_hint) override; void GetGamepadData(bool devices_changed_hint) override;
private: private:
int NextUnusedPlayerIndex();
DISALLOW_COPY_AND_ASSIGN(GameControllerDataFetcherMac); DISALLOW_COPY_AND_ASSIGN(GameControllerDataFetcherMac);
bool connected_[Gamepads::kItemsLengthCap];
}; };
} // namespace device } // namespace device
......
...@@ -18,6 +18,8 @@ namespace device { ...@@ -18,6 +18,8 @@ namespace device {
namespace { namespace {
const int kGCControllerPlayerIndexCount = 4;
void CopyNSStringAsUTF16LittleEndian(NSString* src, void CopyNSStringAsUTF16LittleEndian(NSString* src,
UChar* dest, UChar* dest,
size_t dest_len) { size_t dest_len) {
...@@ -39,15 +41,41 @@ GamepadSource GameControllerDataFetcherMac::source() { ...@@ -39,15 +41,41 @@ GamepadSource GameControllerDataFetcherMac::source() {
void GameControllerDataFetcherMac::GetGamepadData(bool) { void GameControllerDataFetcherMac::GetGamepadData(bool) {
NSArray* controllers = [GCController controllers]; NSArray* controllers = [GCController controllers];
// In the first pass, record which player indices are still in use so unused
// indices can be assigned to newly connected gamepads.
bool player_indices[Gamepads::kItemsLengthCap];
std::fill(player_indices, player_indices + Gamepads::kItemsLengthCap, false);
for (GCController* controller in controllers) { for (GCController* controller in controllers) {
auto extended_gamepad = [controller extendedGamepad];
// We only support the extendedGamepad profile, the basic gamepad profile // We only support the extendedGamepad profile, the basic gamepad profile
// appears to only be for iOS devices. // appears to only be for iOS devices.
if (![controller extendedGamepad])
continue;
int player_index = [controller playerIndex];
if (player_index != GCControllerPlayerIndexUnset)
player_indices[player_index] = true;
}
for (size_t i = 0; i < Gamepads::kItemsLengthCap; ++i) {
if (connected_[i] && !player_indices[i])
connected_[i] = false;
}
// In the second pass, assign indices to newly connected gamepads and fetch
// the gamepad state.
for (GCController* controller in controllers) {
auto extended_gamepad = [controller extendedGamepad];
if (!extended_gamepad) if (!extended_gamepad)
continue; continue;
int player_index = [controller playerIndex]; int player_index = [controller playerIndex];
if (player_index == GCControllerPlayerIndexUnset) {
player_index = NextUnusedPlayerIndex();
if (player_index == GCControllerPlayerIndexUnset)
continue;
}
PadState* state = GetPadState(player_index); PadState* state = GetPadState(player_index);
if (!state) if (!state)
continue; continue;
...@@ -70,6 +98,9 @@ void GameControllerDataFetcherMac::GetGamepadData(bool) { ...@@ -70,6 +98,9 @@ void GameControllerDataFetcherMac::GetGamepadData(bool) {
pad.axes_length = AXIS_INDEX_COUNT; pad.axes_length = AXIS_INDEX_COUNT;
pad.buttons_length = BUTTON_INDEX_COUNT - 1; pad.buttons_length = BUTTON_INDEX_COUNT - 1;
pad.connected = true; pad.connected = true;
connected_[player_index] = true;
[controller
setPlayerIndex:static_cast<GCControllerPlayerIndex>(player_index)];
} }
pad.timestamp = base::TimeTicks::Now().ToInternalValue(); pad.timestamp = base::TimeTicks::Now().ToInternalValue();
...@@ -107,4 +138,12 @@ void GameControllerDataFetcherMac::GetGamepadData(bool) { ...@@ -107,4 +138,12 @@ void GameControllerDataFetcherMac::GetGamepadData(bool) {
} }
} }
int GameControllerDataFetcherMac::NextUnusedPlayerIndex() {
for (int i = 0; i < kGCControllerPlayerIndexCount; ++i) {
if (!connected_[i])
return i;
}
return GCControllerPlayerIndexUnset;
}
} // namespace device } // namespace device
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