Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(167)

Unified Diff: ui/events/ozone/gamepad/generic_gamepad_mapping.cc

Issue 2899893003: Add generic mapping for gamepad (Closed)
Patch Set: Add generic mapping for gamepad Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ui/events/ozone/gamepad/generic_gamepad_mapping.cc
diff --git a/ui/events/ozone/gamepad/generic_gamepad_mapping.cc b/ui/events/ozone/gamepad/generic_gamepad_mapping.cc
new file mode 100644
index 0000000000000000000000000000000000000000..343b2a98c40a1f14d67df83a0a1c45522c4440ad
--- /dev/null
+++ b/ui/events/ozone/gamepad/generic_gamepad_mapping.cc
@@ -0,0 +1,250 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <linux/input.h>
+#include <algorithm>
+#include <bitset>
+#include <cstdint>
+#include <list>
+#include <set>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "ui/events/ozone/evdev/event_device_info.h"
+#include "ui/events/ozone/gamepad/generic_gamepad_mapping.h"
+#include "ui/events/ozone/gamepad/webgamepad_constants.h"
+
+namespace {
+using ui::GamepadEventType;
+
+class GenericGamepadMapper : public ui::GamepadMapper {
+ public:
+ GenericGamepadMapper(std::vector<ui::AbsMapEntry> axis_mapping,
+ std::vector<ui::KeyMapEntry> button_mapping) {
+ axis_mapping.swap(axis_mapping_);
+ button_mapping.swap(button_mapping_);
+ }
+
+ bool Map(uint16_t type,
+ uint16_t code,
+ ui::GamepadEventType* mapped_type,
+ uint16_t* mapped_code) const override {
+ if (type == EV_KEY) {
+ for (auto entry : button_mapping_) {
+ if (entry.evdev_code == code) {
+ *mapped_type = ui::GamepadEventType::BUTTON;
+ *mapped_code = entry.mapped_code;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ if (type == EV_ABS) {
+ for (auto entry : axis_mapping_) {
+ if (entry.evdev_code == code) {
+ *mapped_type = entry.mapped_type;
+ *mapped_code = entry.mapped_code;
+ return true;
+ }
+ }
+ return false;
+ }
+ return false;
+ }
+
+ ~GenericGamepadMapper() override {}
+
+ private:
+ std::vector<ui::AbsMapEntry> axis_mapping_;
+ std::vector<ui::KeyMapEntry> button_mapping_;
+};
+
+// This helper class will be used to build generic mapping.
+class GamepadMapperBuilder {
+ public:
+ explicit GamepadMapperBuilder(const ui::EventDeviceInfo& devinfo)
+ : devinfo_(devinfo) {}
+
+ std::unique_ptr<ui::GamepadMapper> ToGamepadMapper() {
+ return base::MakeUnique<GenericGamepadMapper>(std::move(axis_mapping_),
+ std::move(button_mapping_));
+ }
+
+ void MapButton(uint16_t from_button, uint16_t mapped_button) {
+ if (!devinfo_.HasKeyEvent(from_button)) {
+ return;
+ }
+ DCHECK(!IfEvdevButtonMappedFrom(from_button));
+ DCHECK(!IfWebgamepadButtonMappedTo(mapped_button));
+
+ button_mapping_.push_back({from_button, mapped_button});
+ evdev_buttons_.set(from_button);
+ webgamepad_buttons_.set(mapped_button);
+ }
+
+ void MapAxisToButton(uint16_t from_axis, uint16_t mapped_button) {
+ if (!devinfo_.HasAbsEvent(from_axis)) {
+ return;
+ }
+ DCHECK(!IfEvdevAxisMappedFrom(from_axis));
+ evdev_axes_.set(from_axis);
+ axis_mapping_.push_back(TO_BTN(from_axis, mapped_button));
+
+ if (mapped_button == ui::kHAT_X) {
+ DCHECK(!IfWebgamepadButtonMappedTo(ui::WG_BUTTON_DPAD_LEFT));
+ DCHECK(!IfWebgamepadButtonMappedTo(ui::WG_BUTTON_DPAD_RIGHT));
+
+ webgamepad_buttons_.set(ui::WG_BUTTON_DPAD_LEFT);
+ webgamepad_buttons_.set(ui::WG_BUTTON_DPAD_RIGHT);
+ } else if (mapped_button == ui::kHAT_Y) {
+ DCHECK(!IfWebgamepadButtonMappedTo(ui::WG_BUTTON_DPAD_UP));
+ DCHECK(!IfWebgamepadButtonMappedTo(ui::WG_BUTTON_DPAD_DOWN));
+
+ webgamepad_buttons_.set(ui::WG_BUTTON_DPAD_UP);
+ webgamepad_buttons_.set(ui::WG_BUTTON_DPAD_DOWN);
+ } else {
+ DCHECK(!IfWebgamepadButtonMappedTo(mapped_button));
+ webgamepad_buttons_.set(mapped_button);
+ }
+ }
+
+ void MapAxisToAxis(uint16_t from_axis, uint16_t mapped_axis) {
+ if (!devinfo_.HasAbsEvent(from_axis)) {
+ return;
+ }
+ DCHECK(!IfEvdevAxisMappedFrom(from_axis));
+ DCHECK(!IfWebgamepadAxisMappedTo(mapped_axis));
+
+ axis_mapping_.push_back(TO_ABS(from_axis, mapped_axis));
+ evdev_axes_.set(from_axis);
+ webgamepad_axes_.set(mapped_axis);
+ }
+
+ void MapButtonLikeJoydev() {
+ uint16_t next_unmapped_button = 0;
+ // In linux kernel, joydev.c map evdev events in the same way.
+ for (int i = BTN_JOYSTICK - BTN_MISC; i < KEY_MAX - BTN_MISC + 1; i++) {
+ int code = i + BTN_MISC;
+ if (devinfo_.HasKeyEvent(code) && !IfEvdevButtonMappedFrom(code) &&
+ FindNextUnmappedCode(webgamepad_buttons_, &next_unmapped_button)) {
+ MapButton(code, next_unmapped_button);
+ }
+ }
+
+ for (int i = 0; i < BTN_JOYSTICK - BTN_MISC; i++) {
+ int code = i + BTN_MISC;
+ if (devinfo_.HasKeyEvent(code) && !IfEvdevButtonMappedFrom(code) &&
+ FindNextUnmappedCode(webgamepad_buttons_, &next_unmapped_button)) {
+ MapButton(code, next_unmapped_button);
+ }
+ }
+ }
+
+ void MapAxisLikeJoydev() {
+ uint16_t next_unmapped_axis = 0;
+ for (int code = 0; code < ABS_CNT; ++code) {
+ if (devinfo_.HasAbsEvent(code) && !IfEvdevAxisMappedFrom(code) &&
+ FindNextUnmappedCode(webgamepad_axes_, &next_unmapped_axis)) {
+ MapAxisToAxis(code, next_unmapped_axis);
+ }
+ }
+ }
+
+ private:
+ // This function helps to find the next unmapped button or axis. Code is the
+ // last unmapped code and will be the next unmapped code when the function
+ // returns.
+ template <typename T>
+ bool FindNextUnmappedCode(const T& bitset, uint16_t* code) {
+ for (uint16_t i = *code; i < bitset.size(); ++i) {
+ if (!bitset.test(i)) {
+ *code = i;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool IfEvdevButtonMappedFrom(uint16_t code) {
+ DCHECK_LT(code, KEY_CNT);
+ return evdev_buttons_.test(code);
+ }
+
+ bool IfEvdevAxisMappedFrom(uint16_t code) {
+ DCHECK_LT(code, ABS_CNT);
+ return evdev_axes_.test(code);
+ }
+
+ bool IfWebgamepadButtonMappedTo(uint16_t code) {
+ DCHECK_LT(code, ui::WG_BUTTON_COUNT);
+ return webgamepad_buttons_.test(code);
+ }
+
+ bool IfWebgamepadAxisMappedTo(uint16_t code) {
+ DCHECK_LT(code, ui::WG_ABS_COUNT);
+ return webgamepad_axes_.test(code);
+ }
+
+ const ui::EventDeviceInfo& devinfo_;
+
+ // Mapped webgamepad buttons and axes will be marked as true.
+ std::bitset<ui::WG_BUTTON_COUNT> webgamepad_buttons_;
+ std::bitset<ui::WG_ABS_COUNT> webgamepad_axes_;
+ // Evdev buttons and axes that are already mapped will be marked as true.
+ std::bitset<KEY_CNT> evdev_buttons_;
+ std::bitset<ABS_CNT> evdev_axes_;
+
+ // Generated Mapping.
+ std::vector<ui::AbsMapEntry> axis_mapping_;
+ std::vector<ui::KeyMapEntry> button_mapping_;
+};
+
+void MapSpecialButtons(GamepadMapperBuilder* builder) {
+ // Map mode seperately.
+ builder->MapButton(BTN_MODE, ui::WG_BUTTON_MODE);
+ // Take care of ADT style back and start.
+ builder->MapButton(KEY_BACK, ui::WG_BUTTON_SELECT);
+ builder->MapButton(KEY_HOMEPAGE, ui::WG_BUTTON_START);
+}
+
+void MapSpecialAxes(const ui::EventDeviceInfo& devinfo,
+ GamepadMapperBuilder* builder) {
+ // HAT0X and HAT0Y always map to DPAD.
+ builder->MapAxisToButton(ABS_HAT0X, ui::kHAT_X);
+ builder->MapAxisToButton(ABS_HAT0Y, ui::kHAT_Y);
+
+ // When ABS_BRAKE and ABS_GAS supported at the same time, they are mapped to
+ // l-trigger and r-trigger.
+ // Otherwise, when x,y,z,rx,ry,rz are all supported, z and rz are mapped to
+ // triggers (As XInput gamepad mapper).
+ if (devinfo.HasAbsEvent(ABS_BRAKE) && devinfo.HasAbsEvent(ABS_GAS)) {
+ builder->MapAxisToButton(ABS_BRAKE, ui::WG_BUTTON_LT);
+ builder->MapAxisToButton(ABS_GAS, ui::WG_BUTTON_RT);
+ } else if (devinfo.HasAbsEvent(ABS_X) && devinfo.HasAbsEvent(ABS_Y) &&
+ devinfo.HasAbsEvent(ABS_Z) && devinfo.HasAbsEvent(ABS_RX) &&
+ devinfo.HasAbsEvent(ABS_RY) && devinfo.HasAbsEvent(ABS_RZ)) {
+ builder->MapAxisToButton(ABS_Z, ui::WG_BUTTON_LT);
+ builder->MapAxisToButton(ABS_RZ, ui::WG_BUTTON_RT);
+ }
+}
+} // namespace
+
+namespace ui {
+std::unique_ptr<GamepadMapper> BuildGenericGamepadMapper(
+ const EventDeviceInfo& info) {
+ GamepadMapperBuilder builder(info);
+ // Must map axes first as axis might be mapped to button and occupy some
+ // webgamepad button slots.
+ MapSpecialAxes(info, &builder);
+ builder.MapAxisLikeJoydev();
+
+ MapSpecialButtons(&builder);
+ builder.MapButtonLikeJoydev();
+
+ return builder.ToGamepadMapper();
+}
+
+} // namespace ui
« no previous file with comments | « ui/events/ozone/gamepad/generic_gamepad_mapping.h ('k') | ui/events/ozone/gamepad/generic_gamepad_mapping_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698