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..cdecf58b9c946ee8e93df2524daea5722620762a |
--- /dev/null |
+++ b/ui/events/ozone/gamepad/generic_gamepad_mapping.cc |
@@ -0,0 +1,191 @@ |
+// 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 <cstdint> |
+#include <list> |
+#include <set> |
+#include <vector> |
+ |
+#include "base/macros.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 ui { |
+// This helper class is used to generate generic mapping. |
+class GenericMappingHelper { |
+ public: |
+ GenericMappingHelper(const EventDeviceInfo& devinfo, |
spang
2017/06/01 05:08:12
This organization is surprising. Everything happen
jkwang
2017/06/02 22:03:52
Done.
|
+ std::vector<AbsMapEntry>* abs_map, |
+ std::vector<KeyMapEntry>* key_map) |
+ : devinfo_(devinfo), abs_map_(abs_map), key_map_(key_map) { |
+ for (uint16_t i = 0; i < WG_BUTTON_COUNT; i++) { |
+ unmapped_wg_btn_.push_back(i); |
spang
2017/06/01 05:08:13
bitset
with a vector this should call reserve() i
jkwang
2017/06/02 22:03:51
Done.
|
+ } |
+ |
+ for (uint16_t i = 0; i < WG_ABS_COUNT; i++) { |
+ unmapped_wg_abs_.push_back(i); |
+ } |
+ MapAbs(); |
+ MapBtns(); |
+ } |
+ |
+ private: |
+ // MapAbs will map all the abs events. |
+ void MapAbs() { |
spang
2017/06/01 05:08:13
Although linux uses btn and abs Google style is to
jkwang
2017/06/02 22:03:51
Done.
|
+ TryMapHat(); |
+ TryMapTrigger(); |
+ MapOtherAbs(); |
+ } |
+ |
+ // MapBtns will map all the btn events. |
+ void MapBtns() { |
spang
2017/06/01 05:08:12
MapButtons()
jkwang
2017/06/02 22:03:51
Done.
|
+ // Map Mode. |
+ StaticMapBtnTo(BTN_MODE, WG_BUTTON_MODE); |
+ // Special care for adt style select/start. |
+ StaticMapBtnTo(KEY_BACK, WG_BUTTON_SELECT); |
+ StaticMapBtnTo(KEY_HOMEPAGE, WG_BUTTON_START); |
+ |
+ // 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; |
spang
2017/06/01 05:08:12
Confused by this - what's "i" for here (Why not it
jkwang
2017/06/02 22:03:51
As the comments, it's https://github.com/spotify/l
|
+ if (unmapped_wg_btn_.empty()) { |
+ return; |
+ } |
+ |
+ if (devinfo_.HasKeyEvent(code) && !mapped_ev_btn_.count(code)) { |
spang
2017/06/01 05:08:13
This would read a lot more clearly if you make a f
jkwang
2017/06/02 22:03:52
Done.
|
+ key_map_->push_back({code, unmapped_wg_btn_.front()}); |
+ unmapped_wg_btn_.pop_front(); |
+ } |
+ } |
+ |
+ for (int i = 0; i < BTN_JOYSTICK - BTN_MISC; i++) { |
+ int code = i + BTN_MISC; |
+ if (unmapped_wg_btn_.empty()) { |
+ return; |
+ } |
+ |
+ if (devinfo_.HasKeyEvent(code) && !mapped_ev_btn_.count(code)) { |
+ key_map_->push_back({code, unmapped_wg_btn_.front()}); |
+ unmapped_wg_btn_.pop_front(); |
+ } |
+ } |
+ } |
+ |
+ void StaticMapBtnTo(uint16_t ev_code, uint16_t wg_code) { |
+ if (devinfo_.HasKeyEvent(ev_code)) { |
+ key_map_->push_back({ev_code, wg_code}); |
+ unmapped_wg_btn_.remove(wg_code); |
+ mapped_ev_btn_.insert(ev_code); |
+ } |
+ } |
+ |
+ // We always want to map HAT0X and HAT0Y to DPAD. |
+ void TryMapHat() { |
+ if (!devinfo_.HasAbsEvent(ABS_HAT0X) || !devinfo_.HasAbsEvent(ABS_HAT0Y)) { |
+ return; |
+ } |
+ |
+ unmapped_wg_btn_.remove(WG_BUTTON_DPAD_UP); |
+ unmapped_wg_btn_.remove(WG_BUTTON_DPAD_DOWN); |
+ unmapped_wg_btn_.remove(WG_BUTTON_DPAD_LEFT); |
+ unmapped_wg_btn_.remove(WG_BUTTON_DPAD_RIGHT); |
+ |
+ mapped_ev_abs_.insert(ABS_HAT0X); |
+ mapped_ev_abs_.insert(ABS_HAT0Y); |
+ |
+ abs_map_->push_back(TO_BTN(ABS_HAT0X, kHAT_X)); |
+ abs_map_->push_back(TO_BTN(ABS_HAT0Y, kHAT_Y)); |
+ } |
+ |
+ void TryMapTrigger() { |
+ // ABS_BRAKE, ABS_GAS style. |
+ if (devinfo_.HasAbsEvent(ABS_BRAKE) && devinfo_.HasAbsEvent(ABS_GAS)) { |
+ abs_map_->push_back(TO_BTN(ABS_BRAKE, WG_BUTTON_LT)); |
+ abs_map_->push_back(TO_BTN(ABS_GAS, WG_BUTTON_RT)); |
+ |
+ mapped_ev_abs_.insert(ABS_BRAKE); |
+ mapped_ev_abs_.insert(ABS_GAS); |
+ unmapped_wg_btn_.remove(WG_BUTTON_LT); |
+ unmapped_wg_btn_.remove(WG_BUTTON_RT); |
+ |
+ return; |
+ } |
+ |
+ // XInput style: If X,Y,Z,RX,RY,RZ are all there, Z and RZ are triggers. |
+ 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)) { |
+ abs_map_->push_back(TO_BTN(ABS_Z, WG_BUTTON_LT)); |
spang
2017/06/01 05:08:13
Can you make more functions to make this read well
jkwang
2017/06/02 22:03:52
Done.
|
+ abs_map_->push_back(TO_BTN(ABS_RZ, WG_BUTTON_RT)); |
+ mapped_ev_abs_.insert(ABS_Z); |
+ mapped_ev_abs_.insert(ABS_RZ); |
+ unmapped_wg_btn_.remove(WG_BUTTON_LT); |
+ unmapped_wg_btn_.remove(WG_BUTTON_RT); |
+ } |
+ } |
+ |
+ // Map other Abs in the Joydev style. |
+ void MapOtherAbs() { |
+ for (int code = 0; code < ABS_CNT; ++code) { |
+ if (unmapped_wg_abs_.empty()) { |
+ return; |
+ } |
+ |
+ if (devinfo_.HasAbsEvent(code) && !mapped_ev_abs_.count(code)) { |
+ abs_map_->push_back(TO_ABS(code, unmapped_wg_abs_.front())); |
+ unmapped_wg_abs_.pop_front(); |
+ } |
+ } |
+ } |
+ |
+ const EventDeviceInfo& devinfo_; |
+ // Webgamepad button and abs remain unmapped. |
+ std::list<uint16_t> unmapped_wg_btn_; |
spang
2017/06/01 05:08:13
You can use a std::bitset here. Or std::vector. st
jkwang
2017/06/02 22:03:51
Done.
|
+ std::list<uint16_t> unmapped_wg_abs_; |
+ // Evdev btn and abs that are already mapped. |
+ std::set<uint16_t> mapped_ev_btn_; |
spang
2017/06/01 05:08:13
Also bitset
jkwang
2017/06/02 22:03:51
Done.
|
+ std::set<uint16_t> mapped_ev_abs_; |
+ |
+ std::vector<AbsMapEntry>* abs_map_; |
+ std::vector<KeyMapEntry>* key_map_; |
+}; |
+ |
+GenericGamepadMapping::GenericGamepadMapping( |
+ const EventDeviceInfo& device_info) { |
+ GenericMappingHelper(device_info, &abs_map_, &key_map_); |
+} |
+ |
+GenericGamepadMapping::~GenericGamepadMapping() {} |
+ |
+bool GenericGamepadMapping::operator()(uint16_t type, |
+ uint16_t code, |
+ GamepadEventType* mapped_type, |
+ uint16_t* mapped_code) { |
+ if (type == EV_KEY) { |
+ for (auto entry : key_map_) { |
+ if (entry.evdev_code == code) { |
+ *mapped_type = GamepadEventType::BUTTON; |
+ *mapped_code = entry.mapped_code; |
+ return true; |
+ } |
+ } |
+ return false; |
+ } |
+ |
+ if (type == EV_ABS) { |
+ for (auto entry : abs_map_) { |
+ if (entry.evdev_code == code) { |
+ *mapped_type = entry.mapped_type; |
+ *mapped_code = entry.mapped_code; |
+ return true; |
+ } |
+ } |
+ return false; |
+ } |
+ return false; |
+}; |
+ |
+} // namespace ui |