Commit 81f233c1 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: Iaf038a910df8dc7eb2cee99d4d671a6c9ff6dba0
Reviewed-on: https://chromium-review.googlesource.com/724233
Commit-Queue: Matt Reynolds <mattreynolds@chromium.org>
Reviewed-by: default avatarBrandon Jones <bajones@chromium.org>
Cr-Commit-Position: refs/heads/master@{#509612}
parent 737ab673
......@@ -30,7 +30,11 @@ class GameControllerDataFetcherMac : public GamepadDataFetcher {
void GetGamepadData(bool devices_changed_hint) override;
private:
int NextUnusedPlayerIndex();
DISALLOW_COPY_AND_ASSIGN(GameControllerDataFetcherMac);
bool connected_[Gamepads::kItemsLengthCap];
};
} // namespace device
......
......@@ -18,6 +18,8 @@ namespace device {
namespace {
const int kGCControllerPlayerIndexCount = 4;
void CopyNSStringAsUTF16LittleEndian(NSString* src,
UChar* dest,
size_t dest_len) {
......@@ -39,15 +41,41 @@ GamepadSource GameControllerDataFetcherMac::source() {
void GameControllerDataFetcherMac::GetGamepadData(bool) {
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) {
auto extended_gamepad = [controller extendedGamepad];
// We only support the extendedGamepad profile, the basic gamepad profile
// 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)
continue;
int player_index = [controller playerIndex];
if (player_index == GCControllerPlayerIndexUnset) {
player_index = NextUnusedPlayerIndex();
if (player_index == GCControllerPlayerIndexUnset)
continue;
}
PadState* state = GetPadState(player_index);
if (!state)
continue;
......@@ -70,6 +98,18 @@ void GameControllerDataFetcherMac::GetGamepadData(bool) {
pad.axes_length = AXIS_INDEX_COUNT;
pad.buttons_length = BUTTON_INDEX_COUNT - 1;
pad.connected = true;
connected_[player_index] = true;
// In OS X 10.11, the type of the GCController playerIndex member was
// changed from NSInteger to a GCControllerPlayerIndex enum. Once Chrome
// no longer supports OSX 10.10, the integer version can be removed.
#if !defined(MAC_OS_X_VERSION_10_11) || \
MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_11
[controller setPlayerIndex:player_index];
#else
[controller
setPlayerIndex:static_cast<GCControllerPlayerIndex>(player_index)];
#endif
}
pad.timestamp = base::TimeTicks::Now().ToInternalValue();
......@@ -107,4 +147,12 @@ void GameControllerDataFetcherMac::GetGamepadData(bool) {
}
}
int GameControllerDataFetcherMac::NextUnusedPlayerIndex() {
for (int i = 0; i < kGCControllerPlayerIndexCount; ++i) {
if (!connected_[i])
return i;
}
return GCControllerPlayerIndexUnset;
}
} // 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