Commit 5e47a2b2 authored by Andrew Walbran's avatar Andrew Walbran Committed by Commit Bot

[gamepad] Keep track of which buttons and axes are used.

Often not all the buttons and axes between 0 and buttons_length /
axes_length are actually used. This change adds some fields to keep
track of which ones are used. This is necessary in some cases to
determine which mapping is appropriate.

Also fixes a bug where special buttons might not be counted towards
the buttons_length on Windows.

BUG=1073130

Change-Id: I9f69b7bc9f68e124b5682588af22a135ed8964a6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2216510Reviewed-by: default avatarMatt Reynolds <mattreynolds@chromium.org>
Commit-Queue: Andrew Walbran <qwandor@google.com>
Cr-Commit-Position: refs/heads/master@{#773106}
parent ba32b8e4
...@@ -250,6 +250,12 @@ void GamepadDeviceLinux::ReadPadState(Gamepad* pad) { ...@@ -250,6 +250,12 @@ void GamepadDeviceLinux::ReadPadState(Gamepad* pad) {
pad_updated = true; 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) if (pad_updated)
pad->timestamp = GamepadDataFetcher::CurrentTimeInMicroseconds(); pad->timestamp = GamepadDataFetcher::CurrentTimeInMicroseconds();
} }
...@@ -272,6 +278,7 @@ bool GamepadDeviceLinux::ReadJoydevState(Gamepad* pad) { ...@@ -272,6 +278,7 @@ bool GamepadDeviceLinux::ReadJoydevState(Gamepad* pad) {
continue; continue;
pad->axes[item] = event.value / kMaxLinuxAxisValue; pad->axes[item] = event.value / kMaxLinuxAxisValue;
pad->axes_used |= 1 << item;
if (item >= pad->axes_length) if (item >= pad->axes_length)
pad->axes_length = item + 1; pad->axes_length = item + 1;
...@@ -280,6 +287,7 @@ bool GamepadDeviceLinux::ReadJoydevState(Gamepad* pad) { ...@@ -280,6 +287,7 @@ bool GamepadDeviceLinux::ReadJoydevState(Gamepad* pad) {
if (item >= Gamepad::kButtonsLengthCap) if (item >= Gamepad::kButtonsLengthCap)
continue; continue;
pad->buttons[item].used = true;
pad->buttons[item].pressed = event.value; pad->buttons[item].pressed = event.value;
pad->buttons[item].value = event.value ? 1.0 : 0.0; pad->buttons[item].value = event.value ? 1.0 : 0.0;
......
...@@ -208,6 +208,7 @@ bool GamepadDeviceMac::AddButtons(Gamepad* gamepad) { ...@@ -208,6 +208,7 @@ bool GamepadDeviceMac::AddButtons(Gamepad* gamepad) {
continue; continue;
button_elements_[button_index] = element; button_elements_[button_index] = element;
gamepad->buttons[button_index].used = true;
button_count = std::max(button_count, button_index + 1); button_count = std::max(button_count, button_index + 1);
} else { } else {
// Check for common gamepad buttons that are not on the Button usage // Check for common gamepad buttons that are not on the Button usage
...@@ -241,6 +242,7 @@ bool GamepadDeviceMac::AddButtons(Gamepad* gamepad) { ...@@ -241,6 +242,7 @@ bool GamepadDeviceMac::AddButtons(Gamepad* gamepad) {
break; break;
button_elements_[button_index] = special_element[special_index]; button_elements_[button_index] = special_element[special_index];
gamepad->buttons[button_index].used = true;
button_count = std::max(button_count, button_index + 1); button_count = std::max(button_count, button_index + 1);
if (--unmapped_button_count == 0) if (--unmapped_button_count == 0)
...@@ -351,6 +353,8 @@ bool GamepadDeviceMac::AddAxes(Gamepad* gamepad) { ...@@ -351,6 +353,8 @@ bool GamepadDeviceMac::AddAxes(Gamepad* gamepad) {
axis_minimums_[axis_index] = axis_min; axis_minimums_[axis_index] = axis_min;
axis_maximums_[axis_index] = axis_max; axis_maximums_[axis_index] = axis_max;
axis_report_sizes_[axis_index] = IOHIDElementGetReportSize(element); axis_report_sizes_[axis_index] = IOHIDElementGetReportSize(element);
gamepad->axes_used |= 1 << axis_index;
} }
} }
......
...@@ -33,7 +33,7 @@ GamepadButton ButtonFromButtonAndAxis(GamepadButton button, float axis) { ...@@ -33,7 +33,7 @@ GamepadButton ButtonFromButtonAndAxis(GamepadButton button, float axis) {
} }
GamepadButton NullButton() { GamepadButton NullButton() {
return GamepadButton(false, false, 0.0); return GamepadButton();
} }
void DpadFromAxis(Gamepad* mapped, float dir) { void DpadFromAxis(Gamepad* mapped, float dir) {
......
...@@ -60,11 +60,11 @@ void Mapper2Axes8Keys(const Gamepad& input, Gamepad* mapped) { ...@@ -60,11 +60,11 @@ void Mapper2Axes8Keys(const Gamepad& input, Gamepad* mapped) {
AxisPositiveAsButton(input.axes[0]); AxisPositiveAsButton(input.axes[0]);
// Missing buttons // Missing buttons
mapped->buttons[BUTTON_INDEX_LEFT_TRIGGER] = GamepadButton(); mapped->buttons[BUTTON_INDEX_LEFT_TRIGGER] = NullButton();
mapped->buttons[BUTTON_INDEX_RIGHT_TRIGGER] = GamepadButton(); mapped->buttons[BUTTON_INDEX_RIGHT_TRIGGER] = NullButton();
mapped->buttons[BUTTON_INDEX_LEFT_THUMBSTICK] = GamepadButton(); mapped->buttons[BUTTON_INDEX_LEFT_THUMBSTICK] = NullButton();
mapped->buttons[BUTTON_INDEX_RIGHT_THUMBSTICK] = GamepadButton(); mapped->buttons[BUTTON_INDEX_RIGHT_THUMBSTICK] = NullButton();
mapped->buttons[BUTTON_INDEX_META] = GamepadButton(); mapped->buttons[BUTTON_INDEX_META] = NullButton();
mapped->buttons_length = BUTTON_INDEX_COUNT - 1; mapped->buttons_length = BUTTON_INDEX_COUNT - 1;
mapped->axes_length = 0; mapped->axes_length = 0;
......
...@@ -20,12 +20,14 @@ class GamepadButton { ...@@ -20,12 +20,14 @@ class GamepadButton {
// Matches XInput's trigger deadzone. // Matches XInput's trigger deadzone.
static constexpr float kDefaultButtonPressedThreshold = 30.f / 255.f; static constexpr float kDefaultButtonPressedThreshold = 30.f / 255.f;
GamepadButton() : pressed(false), touched(false), value(0.) {} GamepadButton() = default;
GamepadButton(bool pressed, bool touched, double value) GamepadButton(bool pressed, bool touched, double value)
: pressed(pressed), touched(touched), value(value) {} : used(true), pressed(pressed), touched(touched), value(value) {}
bool pressed; // Whether the button is actually reported by the gamepad at all.
bool touched; bool used{false};
double value; bool pressed{false};
bool touched{false};
double value{0.};
}; };
enum class GamepadHapticActuatorType { kVibration = 0, kDualRumble = 1 }; enum class GamepadHapticActuatorType { kVibration = 0, kDualRumble = 1 };
...@@ -125,6 +127,14 @@ class COMPONENT_EXPORT(GAMEPAD_PUBLIC) Gamepad { ...@@ -125,6 +127,14 @@ class COMPONENT_EXPORT(GAMEPAD_PUBLIC) Gamepad {
// Number of valid entries in the axes array. // Number of valid entries in the axes array.
unsigned axes_length; 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]. // Normalized values representing axes, in the range [-1..1].
double axes[kAxesLengthCap]; double axes[kAxesLengthCap];
......
...@@ -212,8 +212,10 @@ void RawInputGamepadDeviceWin::ReadPadState(Gamepad* pad) const { ...@@ -212,8 +212,10 @@ void RawInputGamepadDeviceWin::ReadPadState(Gamepad* pad) const {
pad->timestamp = last_update_timestamp_; pad->timestamp = last_update_timestamp_;
pad->buttons_length = buttons_length_; pad->buttons_length = buttons_length_;
pad->axes_length = axes_length_; pad->axes_length = axes_length_;
pad->axes_used = axes_used_;
for (unsigned int i = 0; i < buttons_length_; i++) { 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].pressed = buttons_[i];
pad->buttons[i].value = buttons_[i] ? 1.0 : 0.0; pad->buttons[i].value = buttons_[i] ? 1.0 : 0.0;
} }
...@@ -405,25 +407,18 @@ void RawInputGamepadDeviceWin::QueryButtonCapabilities(uint16_t button_count) { ...@@ -405,25 +407,18 @@ void RawInputGamepadDeviceWin::QueryButtonCapabilities(uint16_t button_count) {
HidP_Input, button_caps.get(), &button_count, preparsed_data_); HidP_Input, button_caps.get(), &button_count, preparsed_data_);
DCHECK_EQ(HIDP_STATUS_SUCCESS, status); 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. // Collect all inputs from the Button usage page.
QueryNormalButtonCapabilities(button_caps.get(), button_count, QueryNormalButtonCapabilities(button_caps.get(), button_count);
&button_indices_used);
// Check for common gamepad buttons that are not on the Button usage page. // Check for common gamepad buttons that are not on the Button usage page.
QuerySpecialButtonCapabilities(button_caps.get(), button_count, QuerySpecialButtonCapabilities(button_caps.get(), button_count);
&button_indices_used);
} }
} }
void RawInputGamepadDeviceWin::QueryNormalButtonCapabilities( void RawInputGamepadDeviceWin::QueryNormalButtonCapabilities(
HIDP_BUTTON_CAPS button_caps[], HIDP_BUTTON_CAPS button_caps[],
uint16_t button_count, uint16_t button_count) {
std::vector<bool>* button_indices_used) {
DCHECK(button_caps); DCHECK(button_caps);
DCHECK(button_indices_used);
// Collect all inputs from the Button usage page and assign button indices // Collect all inputs from the Button usage page and assign button indices
// based on the usage value. // based on the usage value.
...@@ -441,17 +436,15 @@ void RawInputGamepadDeviceWin::QueryNormalButtonCapabilities( ...@@ -441,17 +436,15 @@ void RawInputGamepadDeviceWin::QueryNormalButtonCapabilities(
std::min(Gamepad::kButtonsLengthCap - 1, button_index_max); std::min(Gamepad::kButtonsLengthCap - 1, button_index_max);
buttons_length_ = std::max(buttons_length_, button_index_max + 1); buttons_length_ = std::max(buttons_length_, button_index_max + 1);
for (size_t j = button_index_min; j <= button_index_max; ++j) 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( void RawInputGamepadDeviceWin::QuerySpecialButtonCapabilities(
HIDP_BUTTON_CAPS button_caps[], HIDP_BUTTON_CAPS button_caps[],
uint16_t button_count, uint16_t button_count) {
std::vector<bool>* button_indices_used) {
DCHECK(button_caps); DCHECK(button_caps);
DCHECK(button_indices_used);
// Check for common gamepad buttons that are not on the Button usage page. // Check for common gamepad buttons that are not on the Button usage page.
std::vector<bool> has_special_usage(kSpecialUsagesLen, false); std::vector<bool> has_special_usage(kSpecialUsagesLen, false);
...@@ -483,19 +476,20 @@ void RawInputGamepadDeviceWin::QuerySpecialButtonCapabilities( ...@@ -483,19 +476,20 @@ void RawInputGamepadDeviceWin::QuerySpecialButtonCapabilities(
// Advance to the next unused button index. // Advance to the next unused button index.
while (button_index < Gamepad::kButtonsLengthCap && while (button_index < Gamepad::kButtonsLengthCap &&
(*button_indices_used)[button_index]) { button_indices_used_[button_index]) {
++button_index; ++button_index;
} }
if (button_index >= Gamepad::kButtonsLengthCap) if (button_index >= Gamepad::kButtonsLengthCap)
break; break;
special_button_map_[special_index] = button_index; special_button_map_[special_index] = button_index;
(*button_indices_used)[button_index] = true; button_indices_used_[button_index] = true;
++button_index; ++button_index;
if (--unmapped_button_count == 0) if (--unmapped_button_count == 0)
break; break;
} }
buttons_length_ = std::max(buttons_length_, button_index);
} }
} }
...@@ -516,6 +510,7 @@ void RawInputGamepadDeviceWin::QueryAxisCapabilities(uint16_t axis_count) { ...@@ -516,6 +510,7 @@ void RawInputGamepadDeviceWin::QueryAxisCapabilities(uint16_t axis_count) {
axes_[axis_index].active = true; axes_[axis_index].active = true;
axes_[axis_index].bitmask = GetBitmask(axes_caps[i].BitSize); axes_[axis_index].bitmask = GetBitmask(axes_caps[i].BitSize);
axes_length_ = std::max(axes_length_, axis_index + 1); axes_length_ = std::max(axes_length_, axis_index + 1);
axes_used_ |= 1 << axis_index;
} else { } else {
mapped_all_axes = false; mapped_all_axes = false;
} }
...@@ -538,6 +533,7 @@ void RawInputGamepadDeviceWin::QueryAxisCapabilities(uint16_t axis_count) { ...@@ -538,6 +533,7 @@ void RawInputGamepadDeviceWin::QueryAxisCapabilities(uint16_t axis_count) {
axes_[next_index].active = true; axes_[next_index].active = true;
axes_[next_index].bitmask = GetBitmask(axes_caps[i].BitSize); axes_[next_index].bitmask = GetBitmask(axes_caps[i].BitSize);
axes_length_ = std::max(axes_length_, next_index + 1); axes_length_ = std::max(axes_length_, next_index + 1);
axes_used_ |= 1 << next_index;
} }
} }
......
...@@ -97,11 +97,9 @@ class RawInputGamepadDeviceWin final : public AbstractHapticGamepad { ...@@ -97,11 +97,9 @@ class RawInputGamepadDeviceWin final : public AbstractHapticGamepad {
bool QueryDeviceCapabilities(); bool QueryDeviceCapabilities();
void QueryButtonCapabilities(uint16_t button_count); void QueryButtonCapabilities(uint16_t button_count);
void QueryNormalButtonCapabilities(HIDP_BUTTON_CAPS button_caps[], void QueryNormalButtonCapabilities(HIDP_BUTTON_CAPS button_caps[],
uint16_t button_count, uint16_t button_count);
std::vector<bool>* button_indices_used);
void QuerySpecialButtonCapabilities(HIDP_BUTTON_CAPS button_caps[], void QuerySpecialButtonCapabilities(HIDP_BUTTON_CAPS button_caps[],
uint16_t button_count, uint16_t button_count);
std::vector<bool>* button_indices_used);
void QueryAxisCapabilities(uint16_t axis_count); void QueryAxisCapabilities(uint16_t axis_count);
// True if the device described by this object is a valid RawInput gamepad. // True if the device described by this object is a valid RawInput gamepad.
...@@ -129,6 +127,15 @@ class RawInputGamepadDeviceWin final : public AbstractHapticGamepad { ...@@ -129,6 +127,15 @@ class RawInputGamepadDeviceWin final : public AbstractHapticGamepad {
size_t buttons_length_ = 0; size_t buttons_length_ = 0;
bool buttons_[Gamepad::kButtonsLengthCap]; 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) // 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 // to an index within the |buttons_| array, or -1 if the special usage is not
// mapped for this device. // mapped for this 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