diff options
Diffstat (limited to 'chromium/device/gamepad')
-rw-r--r-- | chromium/device/gamepad/gamepad_device_linux.cc | 82 | ||||
-rw-r--r-- | chromium/device/gamepad/gamepad_device_linux.h | 12 | ||||
-rw-r--r-- | chromium/device/gamepad/gamepad_device_mac.mm | 4 | ||||
-rw-r--r-- | chromium/device/gamepad/gamepad_id_list.cc | 17 | ||||
-rw-r--r-- | chromium/device/gamepad/gamepad_id_list.h | 6 | ||||
-rw-r--r-- | chromium/device/gamepad/gamepad_platform_data_fetcher_android.cc | 8 | ||||
-rw-r--r-- | chromium/device/gamepad/gamepad_standard_mappings.cc | 30 | ||||
-rw-r--r-- | chromium/device/gamepad/gamepad_standard_mappings_linux.cc | 89 | ||||
-rw-r--r-- | chromium/device/gamepad/gamepad_standard_mappings_mac.mm | 68 | ||||
-rw-r--r-- | chromium/device/gamepad/gamepad_standard_mappings_win.cc | 78 | ||||
-rw-r--r-- | chromium/device/gamepad/nintendo_controller.cc | 70 | ||||
-rw-r--r-- | chromium/device/gamepad/public/cpp/gamepad.h | 22 | ||||
-rw-r--r-- | chromium/device/gamepad/raw_input_gamepad_device_win.cc | 28 | ||||
-rw-r--r-- | chromium/device/gamepad/raw_input_gamepad_device_win.h | 15 |
14 files changed, 395 insertions, 134 deletions
diff --git a/chromium/device/gamepad/gamepad_device_linux.cc b/chromium/device/gamepad/gamepad_device_linux.cc index f188c2a69e8..ea02ce18f51 100644 --- a/chromium/device/gamepad/gamepad_device_linux.cc +++ b/chromium/device/gamepad/gamepad_device_linux.cc @@ -197,6 +197,40 @@ uint16_t HexStringToUInt16WithDefault(base::StringPiece input, return static_cast<uint16_t>(out); } +#if defined(OS_CHROMEOS) +void OnOpenPathSuccess( + chromeos::PermissionBrokerClient::OpenPathCallback callback, + scoped_refptr<base::SequencedTaskRunner> polling_runner, + base::ScopedFD fd) { + polling_runner->PostTask(FROM_HERE, + base::BindOnce(std::move(callback), std::move(fd))); +} + +void OnOpenPathError( + chromeos::PermissionBrokerClient::OpenPathCallback callback, + scoped_refptr<base::SequencedTaskRunner> polling_runner, + const std::string& error_name, + const std::string& error_message) { + polling_runner->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), base::ScopedFD())); +} + +void OpenPathWithPermissionBroker( + const std::string& path, + chromeos::PermissionBrokerClient::OpenPathCallback callback, + scoped_refptr<base::SequencedTaskRunner> polling_runner) { + auto* client = chromeos::PermissionBrokerClient::Get(); + DCHECK(client) << "Could not get permission broker client."; + auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback)); + auto success_callback = + base::BindOnce(&OnOpenPathSuccess, copyable_callback, polling_runner); + auto error_callback = + base::BindOnce(&OnOpenPathError, copyable_callback, polling_runner); + client->OpenPath(path, std::move(success_callback), + std::move(error_callback)); +} +#endif // defined(OS_CHROMEOS) + } // namespace GamepadDeviceLinux::GamepadDeviceLinux( @@ -250,6 +284,12 @@ void GamepadDeviceLinux::ReadPadState(Gamepad* pad) { pad_updated = true; } + // Mark used buttons. + for (size_t button_index = 0; button_index < Gamepad::kButtonsLengthCap; + ++button_index) { + pad->buttons[button_index].used = button_indices_used_[button_index]; + } + if (pad_updated) pad->timestamp = GamepadDataFetcher::CurrentTimeInMicroseconds(); } @@ -272,6 +312,7 @@ bool GamepadDeviceLinux::ReadJoydevState(Gamepad* pad) { continue; pad->axes[item] = event.value / kMaxLinuxAxisValue; + pad->axes_used |= 1 << item; if (item >= pad->axes_length) pad->axes_length = item + 1; @@ -280,6 +321,7 @@ bool GamepadDeviceLinux::ReadJoydevState(Gamepad* pad) { if (item >= Gamepad::kButtonsLengthCap) continue; + pad->buttons[item].used = true; pad->buttons[item].pressed = event.value; pad->buttons[item].value = event.value ? 1.0 : 0.0; @@ -530,9 +572,8 @@ void GamepadDeviceLinux::OpenHidrawNode(const UdevGamepadLinux& pad_info, weak_factory_.GetWeakPtr(), std::move(callback)); dbus_runner_->PostTask( FROM_HERE, - base::BindOnce(&GamepadDeviceLinux::OpenPathWithPermissionBroker, - weak_factory_.GetWeakPtr(), pad_info.path, - std::move(open_path_callback))); + base::BindOnce(&OpenPathWithPermissionBroker, pad_info.path, + std::move(open_path_callback), polling_runner_)); return; } #endif // defined(OS_CHROMEOS) @@ -601,40 +642,6 @@ void GamepadDeviceLinux::CloseHidrawNode() { hidraw_fd_.reset(); } -#if defined(OS_CHROMEOS) -void GamepadDeviceLinux::OpenPathWithPermissionBroker( - const std::string& path, - OpenPathCallback callback) { - DCHECK(dbus_runner_->RunsTasksInCurrentSequence()); - auto* client = chromeos::PermissionBrokerClient::Get(); - DCHECK(client) << "Could not get permission broker client."; - auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback)); - auto success_callback = - base::BindOnce(&GamepadDeviceLinux::OnOpenPathSuccess, - weak_factory_.GetWeakPtr(), copyable_callback); - auto error_callback = - base::BindOnce(&GamepadDeviceLinux::OnOpenPathError, - weak_factory_.GetWeakPtr(), copyable_callback); - client->OpenPath(path, std::move(success_callback), - std::move(error_callback)); -} - -void GamepadDeviceLinux::OnOpenPathSuccess(OpenPathCallback callback, - base::ScopedFD fd) { - DCHECK(dbus_runner_->RunsTasksInCurrentSequence()); - polling_runner_->PostTask(FROM_HERE, - base::BindOnce(std::move(callback), std::move(fd))); -} - -void GamepadDeviceLinux::OnOpenPathError(OpenPathCallback callback, - const std::string& error_name, - const std::string& error_message) { - DCHECK(dbus_runner_->RunsTasksInCurrentSequence()); - polling_runner_->PostTask( - FROM_HERE, base::BindOnce(std::move(callback), base::ScopedFD())); -} -#endif - void GamepadDeviceLinux::SetVibration(double strong_magnitude, double weak_magnitude) { DCHECK(polling_runner_->RunsTasksInCurrentSequence()); @@ -696,6 +703,7 @@ void GamepadDeviceLinux::SetZeroVibration() { } base::WeakPtr<AbstractHapticGamepad> GamepadDeviceLinux::GetWeakPtr() { + DCHECK(polling_runner_->RunsTasksInCurrentSequence()); return weak_factory_.GetWeakPtr(); } diff --git a/chromium/device/gamepad/gamepad_device_linux.h b/chromium/device/gamepad/gamepad_device_linux.h index 7b4f25e4398..3ef9a0ccdea 100644 --- a/chromium/device/gamepad/gamepad_device_linux.h +++ b/chromium/device/gamepad/gamepad_device_linux.h @@ -99,8 +99,6 @@ class GamepadDeviceLinux final : public AbstractHapticGamepad { base::WeakPtr<AbstractHapticGamepad> GetWeakPtr() override; private: - using OpenPathCallback = base::OnceCallback<void(base::ScopedFD)>; - // AbstractHapticGamepad private implementation. void DoShutdown() override; @@ -108,15 +106,6 @@ class GamepadDeviceLinux final : public AbstractHapticGamepad { base::ScopedFD fd); void InitializeHidraw(base::ScopedFD fd); -#if defined(OS_CHROMEOS) - void OpenPathWithPermissionBroker(const std::string& path, - OpenPathCallback callback); - void OnOpenPathSuccess(OpenPathCallback callback, base::ScopedFD fd); - void OnOpenPathError(OpenPathCallback callback, - const std::string& error_name, - const std::string& error_message); -#endif - // The syspath prefix is used to identify device nodes that refer to the same // underlying gamepad through different interfaces. // @@ -206,6 +195,7 @@ class GamepadDeviceLinux final : public AbstractHapticGamepad { // Task runner to use for gamepad polling. scoped_refptr<base::SequencedTaskRunner> polling_runner_; + // Weak pointer factory for use only on the |polling_runner_| thread. base::WeakPtrFactory<GamepadDeviceLinux> weak_factory_{this}; }; diff --git a/chromium/device/gamepad/gamepad_device_mac.mm b/chromium/device/gamepad/gamepad_device_mac.mm index 90802da1eda..611a301ecc1 100644 --- a/chromium/device/gamepad/gamepad_device_mac.mm +++ b/chromium/device/gamepad/gamepad_device_mac.mm @@ -208,6 +208,7 @@ bool GamepadDeviceMac::AddButtons(Gamepad* gamepad) { continue; button_elements_[button_index] = element; + gamepad->buttons[button_index].used = true; button_count = std::max(button_count, button_index + 1); } else { // Check for common gamepad buttons that are not on the Button usage @@ -241,6 +242,7 @@ bool GamepadDeviceMac::AddButtons(Gamepad* gamepad) { break; button_elements_[button_index] = special_element[special_index]; + gamepad->buttons[button_index].used = true; button_count = std::max(button_count, button_index + 1); if (--unmapped_button_count == 0) @@ -351,6 +353,8 @@ bool GamepadDeviceMac::AddAxes(Gamepad* gamepad) { axis_minimums_[axis_index] = axis_min; axis_maximums_[axis_index] = axis_max; axis_report_sizes_[axis_index] = IOHIDElementGetReportSize(element); + + gamepad->axes_used |= 1 << axis_index; } } diff --git a/chromium/device/gamepad/gamepad_id_list.cc b/chromium/device/gamepad/gamepad_id_list.cc index 831bc8e40b9..14accc69dec 100644 --- a/chromium/device/gamepad/gamepad_id_list.cc +++ b/chromium/device/gamepad/gamepad_id_list.cc @@ -142,6 +142,9 @@ constexpr struct GamepadInfo { // Elecom Co., Ltd {0x056e, 0x2003, kXInputTypeNone}, {0x056e, 0x2004, kXInputTypeXbox360}, + {0x056e, 0x200f, kXInputTypeNone}, + {0x056e, 0x2010, kXInputTypeNone}, + {0x056e, 0x2013, kXInputTypeXbox360}, // Nintendo Co., Ltd {0x057e, 0x0306, kXInputTypeNone}, {0x057e, 0x0330, kXInputTypeNone}, @@ -371,6 +374,7 @@ constexpr struct GamepadInfo { {0x0f0d, 0x008a, kXInputTypeNone}, {0x0f0d, 0x008b, kXInputTypeNone}, {0x0f0d, 0x0090, kXInputTypeNone}, + {0x0f0d, 0x00c1, kXInputTypeNone}, {0x0f0d, 0x00ee, kXInputTypeNone}, // Jess Technology Co., Ltd {0x0f30, 0x010b, kXInputTypeXbox}, @@ -649,9 +653,16 @@ GamepadId GamepadIdList::GetGamepadId(base::StringPiece product_name, uint16_t vendor_id, uint16_t product_id) const { const auto* entry = GetGamepadInfo(vendor_id, product_id); - // The ID value combines the vendor and product IDs. - return entry ? static_cast<GamepadId>((vendor_id << 16) | product_id) - : GamepadId::kUnknownGamepad; + if (entry) { + // The ID value combines the vendor and product IDs. + return static_cast<GamepadId>((vendor_id << 16) | product_id); + } + // Special cases for devices which don't report a valid vendor ID. + if (vendor_id == 0x0 && product_id == 0x0 && + product_name == "Lic Pro Controller") { + return GamepadId::kPowerALicPro; + } + return GamepadId::kUnknownGamepad; } std::vector<std::tuple<uint16_t, uint16_t, XInputType>> diff --git a/chromium/device/gamepad/gamepad_id_list.h b/chromium/device/gamepad/gamepad_id_list.h index ca1ee7feba3..0bde5a720c9 100644 --- a/chromium/device/gamepad/gamepad_id_list.h +++ b/chromium/device/gamepad/gamepad_id_list.h @@ -33,15 +33,19 @@ enum XInputType { enum class GamepadId : uint32_t { // ID value representing an unknown gamepad or non-gamepad. kUnknownGamepad = 0, - + // Fake IDs for devices which report as 0x0000 0x0000 + kPowerALicPro = 0x0000ff00, // ID values for supported devices. kAsusTekProduct4500 = 0x0b054500, kBroadcomProduct8502 = 0x0a5c8502, kDragonRiseProduct0006 = 0x00790006, kDragonRiseProduct0011 = 0x00790011, + kElecomProduct200f = 0x056e200f, + kElecomProduct2010 = 0x056e2010, kGoogleProduct2c40 = 0x18d12c40, kGoogleProduct9400 = 0x18d19400, kGreenAsiaProduct0003 = 0x0e8f0003, + kHoriProduct00c1 = 0x0f0d00c1, kLakeviewResearchProduct0005 = 0x09250005, kLakeviewResearchProduct8866 = 0x09258866, kLogitechProductc216 = 0x046dc216, diff --git a/chromium/device/gamepad/gamepad_platform_data_fetcher_android.cc b/chromium/device/gamepad/gamepad_platform_data_fetcher_android.cc index 38a6cb45240..0d16efd0222 100644 --- a/chromium/device/gamepad/gamepad_platform_data_fetcher_android.cc +++ b/chromium/device/gamepad/gamepad_platform_data_fetcher_android.cc @@ -121,15 +121,17 @@ static void JNI_GamepadList_SetGamepadData( std::vector<float> buttons; base::android::JavaFloatArrayToFloatVector(env, jbuttons, &buttons); - // Set Gamepad buttonslength to total number of axes on the gamepad - // device. Only return the first buttonsLengthCap if axeslength captured by + // Set Gamepad buttonslength to total number of buttons on the gamepad + // device. Only return the first buttonsLengthCap if buttonslength captured by // GamepadList is larger than buttonsLengthCap. pad.buttons_length = std::min(static_cast<int>(buttons.size()), static_cast<int>(Gamepad::kButtonsLengthCap)); // Copy buttons state to the Gamepad buttons[]. for (unsigned int j = 0; j < pad.buttons_length; j++) { - pad.buttons[j].pressed = buttons[j]; + pad.buttons[j].pressed = + buttons[j] > GamepadButton::kDefaultButtonPressedThreshold; + pad.buttons[j].touched = buttons[j] > 0.0f; pad.buttons[j].value = buttons[j]; } } diff --git a/chromium/device/gamepad/gamepad_standard_mappings.cc b/chromium/device/gamepad/gamepad_standard_mappings.cc index e30498514cb..94645a0fbfa 100644 --- a/chromium/device/gamepad/gamepad_standard_mappings.cc +++ b/chromium/device/gamepad/gamepad_standard_mappings.cc @@ -6,25 +6,31 @@ namespace device { -GamepadButton AxisToButton(float input) { - float value = (input + 1.f) / 2.f; +namespace { + +const float kButtonAxisDeadzone = 0.01f; + +GamepadButton ValueToButton(float value) { bool pressed = value > GamepadButton::kDefaultButtonPressedThreshold; - bool touched = value > 0.0f; + bool touched = value > 0.f; return GamepadButton(pressed, touched, value); } +} // namespace + +GamepadButton AxisToButton(float input) { + float value = (input + 1.f) / 2.f; + return ValueToButton(value); +} + GamepadButton AxisNegativeAsButton(float input) { - float value = (input < -0.5f) ? 1.f : 0.f; - bool pressed = value > GamepadButton::kDefaultButtonPressedThreshold; - bool touched = value > 0.0f; - return GamepadButton(pressed, touched, value); + float value = input < -kButtonAxisDeadzone ? -input : 0.f; + return ValueToButton(value); } GamepadButton AxisPositiveAsButton(float input) { - float value = (input > 0.5f) ? 1.f : 0.f; - bool pressed = value > GamepadButton::kDefaultButtonPressedThreshold; - bool touched = value > 0.0f; - return GamepadButton(pressed, touched, value); + float value = input > kButtonAxisDeadzone ? input : 0.f; + return ValueToButton(value); } GamepadButton ButtonFromButtonAndAxis(GamepadButton button, float axis) { @@ -33,7 +39,7 @@ GamepadButton ButtonFromButtonAndAxis(GamepadButton button, float axis) { } GamepadButton NullButton() { - return GamepadButton(false, false, 0.0); + return GamepadButton(); } void DpadFromAxis(Gamepad* mapped, float dir) { diff --git a/chromium/device/gamepad/gamepad_standard_mappings_linux.cc b/chromium/device/gamepad/gamepad_standard_mappings_linux.cc index bf685f48653..d438c3d93bf 100644 --- a/chromium/device/gamepad/gamepad_standard_mappings_linux.cc +++ b/chromium/device/gamepad/gamepad_standard_mappings_linux.cc @@ -35,6 +35,13 @@ enum StadiaGamepadButtons { STADIA_GAMEPAD_BUTTON_COUNT }; +// The Switch Pro controller has a Capture button that has no equivalent in the +// Standard Gamepad. +enum SwitchProButtons { + SWITCH_PRO_BUTTON_CAPTURE = BUTTON_INDEX_COUNT, + SWITCH_PRO_BUTTON_COUNT +}; + void MapperXInputStyleGamepad(const Gamepad& input, Gamepad* mapped) { *mapped = input; mapped->buttons[BUTTON_INDEX_LEFT_TRIGGER] = AxisToButton(input.axes[2]); @@ -613,11 +620,8 @@ void MapperSwitchJoyCon(const Gamepad& input, Gamepad* mapped) { } void MapperSwitchPro(const Gamepad& input, Gamepad* mapped) { - // The Switch Pro controller has a Capture button that has no equivalent in - // the Standard Gamepad. - const size_t kSwitchProExtraButtonCount = 1; *mapped = input; - mapped->buttons_length = BUTTON_INDEX_COUNT + kSwitchProExtraButtonCount; + mapped->buttons_length = SWITCH_PRO_BUTTON_COUNT; mapped->axes_length = AXIS_INDEX_COUNT; } @@ -768,7 +772,18 @@ void MapperSnakebyteIDroidCon(const Gamepad& input, Gamepad* mapped) { mapped->buttons[BUTTON_INDEX_RIGHT_THUMBSTICK] = input.buttons[5]; mapped->buttons[BUTTON_INDEX_META] = NullButton(); - if (input.axes_length == 7) { + if ((input.axes_used & 0b1000000) == 0) { + // "Game controller 1" mode: digital triggers. + mapped->buttons[BUTTON_INDEX_LEFT_TRIGGER] = input.buttons[8]; + mapped->buttons[BUTTON_INDEX_RIGHT_TRIGGER] = input.buttons[9]; + mapped->buttons[BUTTON_INDEX_DPAD_UP] = AxisNegativeAsButton(input.axes[5]); + mapped->buttons[BUTTON_INDEX_DPAD_DOWN] = + AxisPositiveAsButton(input.axes[5]); + mapped->buttons[BUTTON_INDEX_DPAD_LEFT] = + AxisNegativeAsButton(input.axes[4]); + mapped->buttons[BUTTON_INDEX_DPAD_RIGHT] = + AxisPositiveAsButton(input.axes[4]); + } else { // "Game controller 2" mode: analog triggers. mapped->buttons[BUTTON_INDEX_LEFT_TRIGGER] = AxisPositiveAsButton(input.axes[2]); @@ -781,31 +796,67 @@ void MapperSnakebyteIDroidCon(const Gamepad& input, Gamepad* mapped) { AxisNegativeAsButton(input.axes[5]); mapped->buttons[BUTTON_INDEX_DPAD_RIGHT] = AxisPositiveAsButton(input.axes[5]); - mapped->buttons[BUTTON_INDEX_META] = NullButton(); mapped->axes[AXIS_INDEX_RIGHT_STICK_X] = input.axes[3]; mapped->axes[AXIS_INDEX_RIGHT_STICK_Y] = input.axes[4]; - } else { - // "Game controller 1" mode: digital triggers. - mapped->buttons[BUTTON_INDEX_LEFT_TRIGGER] = input.buttons[8]; - mapped->buttons[BUTTON_INDEX_RIGHT_TRIGGER] = input.buttons[9]; - mapped->buttons[BUTTON_INDEX_DPAD_UP] = AxisNegativeAsButton(input.axes[5]); - mapped->buttons[BUTTON_INDEX_DPAD_DOWN] = - AxisPositiveAsButton(input.axes[5]); - mapped->buttons[BUTTON_INDEX_DPAD_LEFT] = - AxisNegativeAsButton(input.axes[4]); - mapped->buttons[BUTTON_INDEX_DPAD_RIGHT] = - AxisPositiveAsButton(input.axes[4]); } + mapped->buttons_length = BUTTON_INDEX_COUNT - 1; // no meta mapped->axes_length = AXIS_INDEX_COUNT; } +void MapperHoripadSwitch(const Gamepad& input, Gamepad* mapped) { + *mapped = input; + mapped->buttons[BUTTON_INDEX_PRIMARY] = input.buttons[1]; + mapped->buttons[BUTTON_INDEX_SECONDARY] = input.buttons[2]; + mapped->buttons[BUTTON_INDEX_TERTIARY] = input.buttons[0]; + mapped->buttons[BUTTON_INDEX_DPAD_UP] = AxisNegativeAsButton(input.axes[5]); + mapped->buttons[BUTTON_INDEX_DPAD_DOWN] = AxisPositiveAsButton(input.axes[5]); + mapped->buttons[BUTTON_INDEX_DPAD_LEFT] = AxisNegativeAsButton(input.axes[4]); + mapped->buttons[BUTTON_INDEX_DPAD_RIGHT] = + AxisPositiveAsButton(input.axes[4]); + mapped->buttons[BUTTON_INDEX_META] = input.buttons[12]; + mapped->buttons[SWITCH_PRO_BUTTON_CAPTURE] = input.buttons[13]; + mapped->buttons_length = SWITCH_PRO_BUTTON_COUNT; + mapped->axes_length = AXIS_INDEX_COUNT; +} + +void MapperElecomWiredDirectInput(const Gamepad& input, Gamepad* mapped) { + *mapped = input; + mapped->buttons[BUTTON_INDEX_PRIMARY] = input.buttons[2]; + mapped->buttons[BUTTON_INDEX_SECONDARY] = input.buttons[3]; + mapped->buttons[BUTTON_INDEX_TERTIARY] = input.buttons[0]; + mapped->buttons[BUTTON_INDEX_QUATERNARY] = input.buttons[1]; + mapped->buttons[BUTTON_INDEX_DPAD_UP] = AxisNegativeAsButton(input.axes[5]); + mapped->buttons[BUTTON_INDEX_DPAD_DOWN] = AxisPositiveAsButton(input.axes[5]); + mapped->buttons[BUTTON_INDEX_DPAD_LEFT] = AxisNegativeAsButton(input.axes[4]); + mapped->buttons[BUTTON_INDEX_DPAD_RIGHT] = + AxisPositiveAsButton(input.axes[4]); + mapped->buttons[BUTTON_INDEX_BACK_SELECT] = input.buttons[10]; + mapped->buttons[BUTTON_INDEX_START] = input.buttons[11]; + mapped->buttons[BUTTON_INDEX_LEFT_THUMBSTICK] = input.buttons[8]; + mapped->buttons[BUTTON_INDEX_RIGHT_THUMBSTICK] = input.buttons[9]; + mapped->buttons[BUTTON_INDEX_META] = input.buttons[12]; + mapped->buttons_length = BUTTON_INDEX_COUNT; + mapped->axes_length = AXIS_INDEX_COUNT; +} + +void MapperElecomWirelessDirectInput(const Gamepad& input, Gamepad* mapped) { + MapperElecomWiredDirectInput(input, mapped); + + mapped->axes[AXIS_INDEX_RIGHT_STICK_X] = input.axes[3]; + mapped->axes[AXIS_INDEX_RIGHT_STICK_Y] = input.axes[2]; +} + constexpr struct MappingData { GamepadId gamepad_id; GamepadStandardMappingFunction function; } AvailableMappings[] = { + // PowerA Wireless Controller - Nintendo GameCube style + {GamepadId::kPowerALicPro, MapperSwitchPro}, // DragonRise Generic USB {GamepadId::kDragonRiseProduct0006, MapperDragonRiseGeneric}, + // HORIPAD for Nintendo Switch + {GamepadId::kHoriProduct00c1, MapperHoripadSwitch}, // Xbox One S (Bluetooth) {GamepadId::kMicrosoftProduct02e0, MapperXboxOneS}, // Xbox One S (Bluetooth) @@ -882,6 +933,10 @@ constexpr struct MappingData { {GamepadId::kPrototypeVendorProduct9401, MapperStadiaControllerOldFirmware}, // Snakebyte iDroid:con {GamepadId::kBroadcomProduct8502, MapperSnakebyteIDroidCon}, + // Elecom JC-U4013SBK (DirectInput mode) + {GamepadId::kElecomProduct200f, MapperElecomWiredDirectInput}, + // Elecom JC-U4113SBK (DirectInput mode) + {GamepadId::kElecomProduct2010, MapperElecomWirelessDirectInput}, }; } // namespace diff --git a/chromium/device/gamepad/gamepad_standard_mappings_mac.mm b/chromium/device/gamepad/gamepad_standard_mappings_mac.mm index d42d6a7ccca..7d068935155 100644 --- a/chromium/device/gamepad/gamepad_standard_mappings_mac.mm +++ b/chromium/device/gamepad/gamepad_standard_mappings_mac.mm @@ -26,6 +26,13 @@ enum StadiaGamepadButtons { STADIA_GAMEPAD_BUTTON_COUNT }; +// The Switch Pro controller has a Capture button that has no equivalent in the +// Standard Gamepad. +enum SwitchProButtons { + SWITCH_PRO_BUTTON_CAPTURE = BUTTON_INDEX_COUNT, + SWITCH_PRO_BUTTON_COUNT +}; + void MapperXbox360Gamepad(const Gamepad& input, Gamepad* mapped) { *mapped = input; mapped->buttons[BUTTON_INDEX_LEFT_TRIGGER] = AxisToButton(input.axes[2]); @@ -536,11 +543,8 @@ void MapperSwitchJoyCon(const Gamepad& input, Gamepad* mapped) { } void MapperSwitchPro(const Gamepad& input, Gamepad* mapped) { - // The Switch Pro controller has a Capture button that has no equivalent in - // the Standard Gamepad. - const size_t kSwitchProExtraButtonCount = 1; *mapped = input; - mapped->buttons_length = BUTTON_INDEX_COUNT + kSwitchProExtraButtonCount; + mapped->buttons_length = SWITCH_PRO_BUTTON_COUNT; mapped->axes_length = AXIS_INDEX_COUNT; } @@ -583,12 +587,68 @@ void MapperXboxOneBluetooth(const Gamepad& input, Gamepad* mapped) { mapped->axes_length = AXIS_INDEX_COUNT; } +void MapperSnakebyteIDroidCon(const Gamepad& input, Gamepad* mapped) { + *mapped = input; + mapped->buttons[BUTTON_INDEX_TERTIARY] = input.buttons[3]; + mapped->buttons[BUTTON_INDEX_QUATERNARY] = input.buttons[4]; + mapped->buttons[BUTTON_INDEX_LEFT_SHOULDER] = input.buttons[6]; + mapped->buttons[BUTTON_INDEX_RIGHT_SHOULDER] = input.buttons[7]; + mapped->buttons[BUTTON_INDEX_BACK_SELECT] = input.buttons[10]; + mapped->buttons[BUTTON_INDEX_START] = input.buttons[11]; + mapped->buttons[BUTTON_INDEX_LEFT_THUMBSTICK] = input.buttons[2]; + mapped->buttons[BUTTON_INDEX_RIGHT_THUMBSTICK] = input.buttons[5]; + mapped->buttons[BUTTON_INDEX_META] = NullButton(); + DpadFromAxis(mapped, input.axes[9]); + + // The iDroid:con has two different modes. Distinguish them based on which + // axes are used. + if ((input.axes_used & 0b11000) == 0) { + // "Game controller 1" mode: digital triggers. + mapped->buttons[BUTTON_INDEX_LEFT_TRIGGER] = input.buttons[8]; + mapped->buttons[BUTTON_INDEX_RIGHT_TRIGGER] = input.buttons[9]; + mapped->axes[AXIS_INDEX_RIGHT_STICK_Y] = input.axes[5]; + } else { + // "Game controller 2" mode: analog triggers. + mapped->buttons[BUTTON_INDEX_LEFT_TRIGGER] = + AxisPositiveAsButton(input.axes[2]); + mapped->buttons[BUTTON_INDEX_RIGHT_TRIGGER] = + AxisNegativeAsButton(input.axes[2]); + mapped->axes[AXIS_INDEX_RIGHT_STICK_X] = input.axes[3]; + mapped->axes[AXIS_INDEX_RIGHT_STICK_Y] = input.axes[4]; + } + + mapped->buttons_length = BUTTON_INDEX_COUNT - 1; // no meta + mapped->axes_length = AXIS_INDEX_COUNT; +} + +void MapperHoripadSwitch(const Gamepad& input, Gamepad* mapped) { + *mapped = input; + mapped->buttons[BUTTON_INDEX_PRIMARY] = input.buttons[1]; + mapped->buttons[BUTTON_INDEX_SECONDARY] = input.buttons[2]; + mapped->buttons[BUTTON_INDEX_TERTIARY] = input.buttons[0]; + DpadFromAxis(mapped, input.axes[9]); + mapped->buttons[BUTTON_INDEX_META] = input.buttons[12]; + mapped->buttons[SWITCH_PRO_BUTTON_CAPTURE] = input.buttons[13]; + mapped->axes[AXIS_INDEX_LEFT_STICK_X] = input.axes[0]; + mapped->axes[AXIS_INDEX_LEFT_STICK_Y] = input.axes[1]; + mapped->axes[AXIS_INDEX_RIGHT_STICK_X] = input.axes[2]; + mapped->axes[AXIS_INDEX_RIGHT_STICK_Y] = input.axes[5]; + mapped->buttons_length = SWITCH_PRO_BUTTON_COUNT; + mapped->axes_length = AXIS_INDEX_COUNT; +} + constexpr struct MappingData { GamepadId gamepad_id; GamepadStandardMappingFunction function; } AvailableMappings[] = { + // PowerA Wireless Controller - Nintendo GameCube style + {GamepadId::kPowerALicPro, MapperSwitchPro}, + // Snakebyte iDroid:con + {GamepadId::kBroadcomProduct8502, MapperSnakebyteIDroidCon}, // DragonRise Generic USB {GamepadId::kDragonRiseProduct0006, MapperDragonRiseGeneric}, + // HORIPAD for Nintendo Switch + {GamepadId::kHoriProduct00c1, MapperHoripadSwitch}, // Xbox 360 Wired {GamepadId::kMicrosoftProduct028e, MapperXbox360Gamepad}, // Xbox 360 Wireless diff --git a/chromium/device/gamepad/gamepad_standard_mappings_win.cc b/chromium/device/gamepad/gamepad_standard_mappings_win.cc index aed6ca57a25..a4f48b2f7b6 100644 --- a/chromium/device/gamepad/gamepad_standard_mappings_win.cc +++ b/chromium/device/gamepad/gamepad_standard_mappings_win.cc @@ -26,6 +26,13 @@ enum StadiaGamepadButtons { STADIA_GAMEPAD_BUTTON_COUNT }; +// The Switch Pro controller has a Capture button that has no equivalent in the +// Standard Gamepad. +enum SwitchProButtons { + SWITCH_PRO_BUTTON_CAPTURE = BUTTON_INDEX_COUNT, + SWITCH_PRO_BUTTON_COUNT +}; + void MapperLogitechDInput(const Gamepad& input, Gamepad* mapped) { *mapped = input; mapped->buttons[BUTTON_INDEX_PRIMARY] = input.buttons[1]; @@ -53,11 +60,11 @@ void Mapper2Axes8Keys(const Gamepad& input, Gamepad* mapped) { AxisPositiveAsButton(input.axes[0]); // Missing buttons - mapped->buttons[BUTTON_INDEX_LEFT_TRIGGER] = GamepadButton(); - mapped->buttons[BUTTON_INDEX_RIGHT_TRIGGER] = GamepadButton(); - mapped->buttons[BUTTON_INDEX_LEFT_THUMBSTICK] = GamepadButton(); - mapped->buttons[BUTTON_INDEX_RIGHT_THUMBSTICK] = GamepadButton(); - mapped->buttons[BUTTON_INDEX_META] = GamepadButton(); + mapped->buttons[BUTTON_INDEX_LEFT_TRIGGER] = NullButton(); + mapped->buttons[BUTTON_INDEX_RIGHT_TRIGGER] = NullButton(); + mapped->buttons[BUTTON_INDEX_LEFT_THUMBSTICK] = NullButton(); + mapped->buttons[BUTTON_INDEX_RIGHT_THUMBSTICK] = NullButton(); + mapped->buttons[BUTTON_INDEX_META] = NullButton(); mapped->buttons_length = BUTTON_INDEX_COUNT - 1; mapped->axes_length = 0; @@ -392,11 +399,8 @@ void MapperSwitchJoyCon(const Gamepad& input, Gamepad* mapped) { } void MapperSwitchPro(const Gamepad& input, Gamepad* mapped) { - // The Switch Pro controller has a Capture button that has no equivalent in - // the Standard Gamepad. - const size_t kSwitchProExtraButtonCount = 1; *mapped = input; - mapped->buttons_length = BUTTON_INDEX_COUNT + kSwitchProExtraButtonCount; + mapped->buttons_length = SWITCH_PRO_BUTTON_COUNT; mapped->axes_length = AXIS_INDEX_COUNT; } @@ -416,12 +420,68 @@ void MapperSwitchComposite(const Gamepad& input, Gamepad* mapped) { mapped->axes_length = AXIS_INDEX_COUNT; } +void MapperSnakebyteIDroidCon(const Gamepad& input, Gamepad* mapped) { + *mapped = input; + mapped->buttons[BUTTON_INDEX_TERTIARY] = input.buttons[3]; + mapped->buttons[BUTTON_INDEX_QUATERNARY] = input.buttons[4]; + mapped->buttons[BUTTON_INDEX_LEFT_SHOULDER] = input.buttons[6]; + mapped->buttons[BUTTON_INDEX_RIGHT_SHOULDER] = input.buttons[7]; + mapped->buttons[BUTTON_INDEX_BACK_SELECT] = input.buttons[10]; + mapped->buttons[BUTTON_INDEX_START] = input.buttons[11]; + mapped->buttons[BUTTON_INDEX_LEFT_THUMBSTICK] = input.buttons[2]; + mapped->buttons[BUTTON_INDEX_RIGHT_THUMBSTICK] = input.buttons[5]; + mapped->buttons[BUTTON_INDEX_META] = NullButton(); + DpadFromAxis(mapped, input.axes[9]); + + // The iDroid:con has two different modes. Distinguish them based on which + // axes are used. + if ((input.axes_used & 0b11000) == 0) { + // "Game controller 1" mode: digital triggers. + mapped->buttons[BUTTON_INDEX_LEFT_TRIGGER] = input.buttons[8]; + mapped->buttons[BUTTON_INDEX_RIGHT_TRIGGER] = input.buttons[9]; + mapped->axes[AXIS_INDEX_RIGHT_STICK_Y] = input.axes[5]; + } else { + // "Game controller 2" mode: analog triggers. + mapped->buttons[BUTTON_INDEX_LEFT_TRIGGER] = + AxisPositiveAsButton(input.axes[2]); + mapped->buttons[BUTTON_INDEX_RIGHT_TRIGGER] = + AxisNegativeAsButton(input.axes[2]); + mapped->axes[AXIS_INDEX_RIGHT_STICK_X] = input.axes[3]; + mapped->axes[AXIS_INDEX_RIGHT_STICK_Y] = input.axes[4]; + } + + mapped->buttons_length = BUTTON_INDEX_COUNT - 1; // no meta + mapped->axes_length = AXIS_INDEX_COUNT; +} + +void MapperHoripadSwitch(const Gamepad& input, Gamepad* mapped) { + *mapped = input; + mapped->buttons[BUTTON_INDEX_PRIMARY] = input.buttons[1]; + mapped->buttons[BUTTON_INDEX_SECONDARY] = input.buttons[2]; + mapped->buttons[BUTTON_INDEX_TERTIARY] = input.buttons[0]; + DpadFromAxis(mapped, input.axes[9]); + mapped->buttons[BUTTON_INDEX_META] = input.buttons[12]; + mapped->buttons[SWITCH_PRO_BUTTON_CAPTURE] = input.buttons[13]; + mapped->axes[AXIS_INDEX_LEFT_STICK_X] = input.axes[0]; + mapped->axes[AXIS_INDEX_LEFT_STICK_Y] = input.axes[1]; + mapped->axes[AXIS_INDEX_RIGHT_STICK_X] = input.axes[2]; + mapped->axes[AXIS_INDEX_RIGHT_STICK_Y] = input.axes[5]; + mapped->buttons_length = SWITCH_PRO_BUTTON_COUNT; + mapped->axes_length = AXIS_INDEX_COUNT; +} + constexpr struct MappingData { GamepadId gamepad_id; GamepadStandardMappingFunction function; } AvailableMappings[] = { + // PowerA Wireless Controller - Nintendo GameCube style + {GamepadId::kPowerALicPro, MapperSwitchPro}, + // Snakebyte iDroid:con + {GamepadId::kBroadcomProduct8502, MapperSnakebyteIDroidCon}, // 2Axes 8Keys Game Pad {GamepadId::kDragonRiseProduct0011, Mapper2Axes8Keys}, + // HORIPAD for Nintendo Switch + {GamepadId::kHoriProduct00c1, MapperHoripadSwitch}, // Logitech F310, D-mode {GamepadId::kLogitechProductc216, MapperLogitechDInput}, // Logitech F510, D-mode diff --git a/chromium/device/gamepad/nintendo_controller.cc b/chromium/device/gamepad/nintendo_controller.cc index 662cc20c878..66c0a0c8509 100644 --- a/chromium/device/gamepad/nintendo_controller.cc +++ b/chromium/device/gamepad/nintendo_controller.cc @@ -95,6 +95,15 @@ const uint8_t kGyroPerformance208Hz = 0x01; const uint8_t kAccelerometerFilterBandwidth100Hz = 0x01; const uint8_t kPlayerLightPattern1 = 0x01; +// Bogus calibration value that should be ignored. +const uint16_t kCalBogusValue = 0xfff; + +// Default calibration values to use if the controller returns bogus values. +const uint16_t kCalDefaultDeadzone = 160; +const uint16_t kCalDefaultMin = 550; +const uint16_t kCalDefaultCenter = 2050; +const uint16_t kCalDefaultMax = 3550; + // Parameters for the "strong" and "weak" components of the dual-rumble effect. const double kVibrationFrequencyStrongRumble = 141.0; const double kVibrationFrequencyWeakRumble = 182.0; @@ -304,6 +313,11 @@ void UnpackSwitchAnalogStickParameters( DCHECK(data); // Only fetch the dead zone and range ratio. The other parameters are unknown. UnpackShorts(data[3], data[4], data[5], &cal.dead_zone, &cal.range_ratio); + if (cal.dead_zone == kCalBogusValue) { + // If the controller reports an invalid dead zone, default to something + // reasonable. + cal.dead_zone = kCalDefaultDeadzone; + } } // Unpack the IMU calibration data into |cal| @@ -349,14 +363,30 @@ void UnpackSwitchAnalogStickCalibration( UnpackShorts(data[9], data[10], data[11], &cal.rx_center, &cal.ry_center); UnpackShorts(data[12], data[13], data[14], &cal.rx_min, &cal.ry_min); UnpackShorts(data[15], data[16], data[17], &cal.rx_max, &cal.ry_max); - cal.lx_min = cal.lx_center - cal.lx_min; - cal.lx_max = cal.lx_center + cal.lx_max; - cal.ly_min = cal.ly_center - cal.ly_min; - cal.ly_max = cal.ly_center + cal.ly_max; - cal.rx_min = cal.rx_center - cal.rx_min; - cal.rx_max = cal.rx_center + cal.rx_max; - cal.ry_min = cal.ry_center - cal.ry_min; - cal.ry_max = cal.ry_center + cal.ry_max; + if (cal.lx_min == kCalBogusValue && cal.ly_max == kCalBogusValue) { + // If the controller reports bogus values, default to something reasonable. + cal.lx_min = kCalDefaultMin; + cal.lx_center = kCalDefaultCenter; + cal.lx_max = kCalDefaultMax; + cal.ly_min = kCalDefaultMin; + cal.ly_center = kCalDefaultCenter; + cal.ly_max = kCalDefaultMax; + cal.rx_min = kCalDefaultMin; + cal.rx_center = kCalDefaultCenter; + cal.rx_max = kCalDefaultMax; + cal.ry_min = kCalDefaultMin; + cal.ry_center = kCalDefaultCenter; + cal.ry_max = kCalDefaultMax; + } else { + cal.lx_min = cal.lx_center - cal.lx_min; + cal.lx_max = cal.lx_center + cal.lx_max; + cal.ly_min = cal.ly_center - cal.ly_min; + cal.ly_max = cal.ly_center + cal.ly_max; + cal.rx_min = cal.rx_center - cal.rx_min; + cal.rx_max = cal.rx_center + cal.rx_max; + cal.ry_min = cal.ry_center - cal.ry_min; + cal.ry_max = cal.ry_center + cal.ry_max; + } } // Unpack one frame of IMU data into |imu_data|. @@ -796,6 +826,9 @@ GamepadBusType BusTypeFromDeviceInfo(const mojom::HidDeviceInfo* device_info) { // Joy Cons can only be connected over Bluetooth. When connected through // a Charging Grip, the grip's ID is reported instead. return GAMEPAD_BUS_BLUETOOTH; + case GamepadId::kPowerALicPro: + // The PowerA controller can only be connected over Bluetooth. + return GAMEPAD_BUS_BLUETOOTH; default: break; } @@ -878,6 +911,7 @@ bool NintendoController::IsNintendoController(GamepadId gamepad_id) { case GamepadId::kNintendoProduct2007: case GamepadId::kNintendoProduct2009: case GamepadId::kNintendoProduct200e: + case GamepadId::kPowerALicPro: return true; default: break; @@ -918,7 +952,8 @@ GamepadHand NintendoController::GetGamepadHand() const { return GamepadHand::kNone; switch (gamepad_id_) { case GamepadId::kNintendoProduct2009: - // Switch Pro is held in both hands. + case GamepadId::kPowerALicPro: + // Switch Pro and PowerA are held in both hands. return GamepadHand::kNone; case GamepadId::kNintendoProduct2006: // Joy-Con L is held in the left hand. @@ -961,6 +996,7 @@ bool NintendoController::IsUsable() const { case GamepadId::kNintendoProduct2009: case GamepadId::kNintendoProduct2006: case GamepadId::kNintendoProduct2007: + case GamepadId::kPowerALicPro: return true; case GamepadId::kNintendoProduct200e: // Only usable as a composite device. @@ -1001,8 +1037,12 @@ void NintendoController::InitializeGamepadState(bool has_standard_mapping, Gamepad& pad) const { pad.buttons_length = SWITCH_BUTTON_INDEX_COUNT; pad.axes_length = device::AXIS_INDEX_COUNT; - pad.vibration_actuator.type = GamepadHapticActuatorType::kDualRumble; - pad.vibration_actuator.not_null = true; + if (gamepad_id_ == GamepadId::kPowerALicPro) { + pad.vibration_actuator.not_null = false; + } else { + pad.vibration_actuator.type = GamepadHapticActuatorType::kDualRumble; + pad.vibration_actuator.not_null = true; + } pad.timestamp = GamepadDataFetcher::CurrentTimeInMicroseconds(); if (is_composite_) { // Composite devices use the same product ID as the Switch Charging Grip. @@ -1407,7 +1447,13 @@ void NintendoController::ContinueInitSequence( case kPendingEnableVibration: if (spi_subcommand == kSubCommandEnableVibration) { CancelTimeout(); - MakeInitSequenceRequests(kPendingSetHomeLight); + // PowerA controller doesn't have a home light and trying to set it will + // fail, so skip this step. + if (gamepad_id_ == GamepadId::kPowerALicPro) { + MakeInitSequenceRequests(kPendingSetInputReportMode); + } else { + MakeInitSequenceRequests(kPendingSetHomeLight); + } } break; case kPendingSetHomeLight: diff --git a/chromium/device/gamepad/public/cpp/gamepad.h b/chromium/device/gamepad/public/cpp/gamepad.h index 9203c4ffbe1..3477d3d251a 100644 --- a/chromium/device/gamepad/public/cpp/gamepad.h +++ b/chromium/device/gamepad/public/cpp/gamepad.h @@ -8,6 +8,8 @@ #include <stddef.h> #include <cstdint> +#include <limits> + #include "base/component_export.h" #include "base/strings/string16.h" @@ -20,12 +22,14 @@ class GamepadButton { // Matches XInput's trigger deadzone. static constexpr float kDefaultButtonPressedThreshold = 30.f / 255.f; - GamepadButton() : pressed(false), touched(false), value(0.) {} + GamepadButton() = default; GamepadButton(bool pressed, bool touched, double value) - : pressed(pressed), touched(touched), value(value) {} - bool pressed; - bool touched; - double value; + : used(true), pressed(pressed), touched(touched), value(value) {} + // Whether the button is actually reported by the gamepad at all. + bool used{false}; + bool pressed{false}; + bool touched{false}; + double value{0.}; }; enum class GamepadHapticActuatorType { kVibration = 0, kDualRumble = 1 }; @@ -125,6 +129,14 @@ class COMPONENT_EXPORT(GAMEPAD_PUBLIC) Gamepad { // Number of valid entries in the axes array. unsigned axes_length; + // Bitfield indicating which entries of the axes array are actually used. If + // the axes index is actually used for this gamepad then the corresponding bit + // will be 1. + uint32_t axes_used; + static_assert(Gamepad::kAxesLengthCap <= + std::numeric_limits<uint32_t>::digits, + "axes_used is not large enough"); + // Normalized values representing axes, in the range [-1..1]. double axes[kAxesLengthCap]; diff --git a/chromium/device/gamepad/raw_input_gamepad_device_win.cc b/chromium/device/gamepad/raw_input_gamepad_device_win.cc index 5ba8b9f38f1..57473ca36e3 100644 --- a/chromium/device/gamepad/raw_input_gamepad_device_win.cc +++ b/chromium/device/gamepad/raw_input_gamepad_device_win.cc @@ -212,8 +212,10 @@ void RawInputGamepadDeviceWin::ReadPadState(Gamepad* pad) const { pad->timestamp = last_update_timestamp_; pad->buttons_length = buttons_length_; pad->axes_length = axes_length_; + pad->axes_used = axes_used_; for (unsigned int i = 0; i < buttons_length_; i++) { + pad->buttons[i].used = button_indices_used_[i]; pad->buttons[i].pressed = buttons_[i]; pad->buttons[i].value = buttons_[i] ? 1.0 : 0.0; } @@ -405,25 +407,18 @@ void RawInputGamepadDeviceWin::QueryButtonCapabilities(uint16_t button_count) { HidP_Input, button_caps.get(), &button_count, preparsed_data_); DCHECK_EQ(HIDP_STATUS_SUCCESS, status); - // Keep track of which button indices are in use. - std::vector<bool> button_indices_used(Gamepad::kButtonsLengthCap, false); - // Collect all inputs from the Button usage page. - QueryNormalButtonCapabilities(button_caps.get(), button_count, - &button_indices_used); + QueryNormalButtonCapabilities(button_caps.get(), button_count); // Check for common gamepad buttons that are not on the Button usage page. - QuerySpecialButtonCapabilities(button_caps.get(), button_count, - &button_indices_used); + QuerySpecialButtonCapabilities(button_caps.get(), button_count); } } void RawInputGamepadDeviceWin::QueryNormalButtonCapabilities( HIDP_BUTTON_CAPS button_caps[], - uint16_t button_count, - std::vector<bool>* button_indices_used) { + uint16_t button_count) { DCHECK(button_caps); - DCHECK(button_indices_used); // Collect all inputs from the Button usage page and assign button indices // based on the usage value. @@ -441,17 +436,15 @@ void RawInputGamepadDeviceWin::QueryNormalButtonCapabilities( std::min(Gamepad::kButtonsLengthCap - 1, button_index_max); buttons_length_ = std::max(buttons_length_, button_index_max + 1); for (size_t j = button_index_min; j <= button_index_max; ++j) - (*button_indices_used)[j] = true; + button_indices_used_[j] = true; } } } void RawInputGamepadDeviceWin::QuerySpecialButtonCapabilities( HIDP_BUTTON_CAPS button_caps[], - uint16_t button_count, - std::vector<bool>* button_indices_used) { + uint16_t button_count) { DCHECK(button_caps); - DCHECK(button_indices_used); // Check for common gamepad buttons that are not on the Button usage page. std::vector<bool> has_special_usage(kSpecialUsagesLen, false); @@ -483,19 +476,20 @@ void RawInputGamepadDeviceWin::QuerySpecialButtonCapabilities( // Advance to the next unused button index. while (button_index < Gamepad::kButtonsLengthCap && - (*button_indices_used)[button_index]) { + button_indices_used_[button_index]) { ++button_index; } if (button_index >= Gamepad::kButtonsLengthCap) break; special_button_map_[special_index] = button_index; - (*button_indices_used)[button_index] = true; + button_indices_used_[button_index] = true; ++button_index; if (--unmapped_button_count == 0) break; } + buttons_length_ = std::max(buttons_length_, button_index); } } @@ -516,6 +510,7 @@ void RawInputGamepadDeviceWin::QueryAxisCapabilities(uint16_t axis_count) { axes_[axis_index].active = true; axes_[axis_index].bitmask = GetBitmask(axes_caps[i].BitSize); axes_length_ = std::max(axes_length_, axis_index + 1); + axes_used_ |= 1 << axis_index; } else { mapped_all_axes = false; } @@ -538,6 +533,7 @@ void RawInputGamepadDeviceWin::QueryAxisCapabilities(uint16_t axis_count) { axes_[next_index].active = true; axes_[next_index].bitmask = GetBitmask(axes_caps[i].BitSize); axes_length_ = std::max(axes_length_, next_index + 1); + axes_used_ |= 1 << next_index; } } diff --git a/chromium/device/gamepad/raw_input_gamepad_device_win.h b/chromium/device/gamepad/raw_input_gamepad_device_win.h index 3c7c8999b74..60a90b15826 100644 --- a/chromium/device/gamepad/raw_input_gamepad_device_win.h +++ b/chromium/device/gamepad/raw_input_gamepad_device_win.h @@ -97,11 +97,9 @@ class RawInputGamepadDeviceWin final : public AbstractHapticGamepad { bool QueryDeviceCapabilities(); void QueryButtonCapabilities(uint16_t button_count); void QueryNormalButtonCapabilities(HIDP_BUTTON_CAPS button_caps[], - uint16_t button_count, - std::vector<bool>* button_indices_used); + uint16_t button_count); void QuerySpecialButtonCapabilities(HIDP_BUTTON_CAPS button_caps[], - uint16_t button_count, - std::vector<bool>* button_indices_used); + uint16_t button_count); void QueryAxisCapabilities(uint16_t axis_count); // True if the device described by this object is a valid RawInput gamepad. @@ -129,6 +127,15 @@ class RawInputGamepadDeviceWin final : public AbstractHapticGamepad { size_t buttons_length_ = 0; bool buttons_[Gamepad::kButtonsLengthCap]; + // Keep track of which button indices are in use. + std::vector<bool> button_indices_used_{Gamepad::kButtonsLengthCap, false}; + + // Bitfield to keep track of which axes indices are in use. + uint32_t axes_used_ = 0; + static_assert(Gamepad::kAxesLengthCap <= + std::numeric_limits<uint32_t>::digits, + "axes_used_ is not large enough"); + // Mapping from "Special" usage index (defined by the kSpecialUsages table) // to an index within the |buttons_| array, or -1 if the special usage is not // mapped for this device. |