1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ui/events/ozone/evdev/gamepad_event_converter_evdev.h"
6
7 #include <errno.h>
8 #include <linux/input.h>
9 #include <stddef.h>
10
11 #include "base/trace_event/trace_event.h"
12 #include "ui/events/event_utils.h"
13 #include "ui/events/ozone/evdev/device_event_dispatcher_evdev.h"
14 #include "ui/events/ozone/gamepad/gamepad_event.h"
15 #include "ui/events/ozone/gamepad/gamepad_provider_ozone.h"
16
17 namespace ui {
18
GamepadEventConverterEvdev(base::ScopedFD fd,base::FilePath path,int id,const EventDeviceInfo & devinfo,DeviceEventDispatcherEvdev * dispatcher)19 GamepadEventConverterEvdev::GamepadEventConverterEvdev(
20 base::ScopedFD fd,
21 base::FilePath path,
22 int id,
23 const EventDeviceInfo& devinfo,
24 DeviceEventDispatcherEvdev* dispatcher)
25 : EventConverterEvdev(fd.get(),
26 path,
27 id,
28 devinfo.device_type(),
29 devinfo.name(),
30 devinfo.phys(),
31 devinfo.vendor_id(),
32 devinfo.product_id(),
33 devinfo.version()),
34 will_send_frame_(false),
35 input_device_fd_(std::move(fd)),
36 dispatcher_(dispatcher) {
37 input_absinfo abs_info;
38 for (int code = 0; code < ABS_CNT; ++code) {
39 abs_info = devinfo.GetAbsInfoByCode(code);
40 if (devinfo.HasAbsEvent(code)) {
41 ui::GamepadDevice::Axis axis;
42 axis.code = code;
43 axis.min_value = abs_info.minimum;
44 axis.max_value = abs_info.maximum;
45 axis.flat = abs_info.flat;
46 axis.fuzz = abs_info.fuzz;
47 axis.resolution = abs_info.resolution;
48 axes_.push_back(axis);
49 }
50 }
51 }
52
~GamepadEventConverterEvdev()53 GamepadEventConverterEvdev::~GamepadEventConverterEvdev() {
54 DCHECK(!IsEnabled());
55 }
56
HasGamepad() const57 bool GamepadEventConverterEvdev::HasGamepad() const {
58 return true;
59 }
60
OnFileCanReadWithoutBlocking(int fd)61 void GamepadEventConverterEvdev::OnFileCanReadWithoutBlocking(int fd) {
62 TRACE_EVENT1("evdev",
63 "GamepadEventConverterEvdev::OnFileCanReadWithoutBlocking", "fd",
64 fd);
65 while (true) {
66 input_event input;
67 ssize_t read_size = read(fd, &input, sizeof(input));
68 if (read_size != sizeof(input)) {
69 if (errno == EINTR || errno == EAGAIN)
70 return;
71 if (errno != ENODEV)
72 PLOG(ERROR) << "error reading device " << path_.value();
73 Stop();
74 return;
75 }
76
77 if (!IsEnabled())
78 return;
79
80 ProcessEvent(input);
81 }
82 }
OnDisabled()83 void GamepadEventConverterEvdev::OnDisabled() {
84 ResetGamepad();
85 }
86
87 std::vector<ui::GamepadDevice::Axis>
GetGamepadAxes() const88 GamepadEventConverterEvdev::GetGamepadAxes() const {
89 return axes_;
90 }
91
ProcessEvent(const input_event & evdev_ev)92 void GamepadEventConverterEvdev::ProcessEvent(const input_event& evdev_ev) {
93 base::TimeTicks timestamp = TimeTicksFromInputEvent(evdev_ev);
94 // We may have missed Gamepad releases. Reset everything.
95 // If the event is sync, we send a frame.
96 if (evdev_ev.type == EV_SYN) {
97 if (evdev_ev.code == SYN_DROPPED) {
98 LOG(WARNING) << "kernel dropped input events";
99 ResyncGamepad();
100 } else if (evdev_ev.code == SYN_REPORT) {
101 OnSync(timestamp);
102 }
103 } else if (evdev_ev.type == EV_KEY) {
104 ProcessEvdevKey(evdev_ev.code, evdev_ev.value, timestamp);
105 } else if (evdev_ev.type == EV_ABS) {
106 ProcessEvdevAbs(evdev_ev.code, evdev_ev.value, timestamp);
107 }
108 }
109
ProcessEvdevKey(uint16_t code,int value,const base::TimeTicks & timestamp)110 void GamepadEventConverterEvdev::ProcessEvdevKey(
111 uint16_t code,
112 int value,
113 const base::TimeTicks& timestamp) {
114 if (value)
115 pressed_buttons_.insert(code);
116 else
117 pressed_buttons_.erase(code);
118 GamepadEvent event(input_device_.id, GamepadEventType::BUTTON, code, value,
119 timestamp);
120 dispatcher_->DispatchGamepadEvent(event);
121 will_send_frame_ = true;
122 }
123
ProcessEvdevAbs(uint16_t code,int value,const base::TimeTicks & timestamp)124 void GamepadEventConverterEvdev::ProcessEvdevAbs(
125 uint16_t code,
126 int value,
127 const base::TimeTicks& timestamp) {
128 GamepadEvent event(input_device_.id, GamepadEventType::AXIS, code, value,
129 timestamp);
130 dispatcher_->DispatchGamepadEvent(event);
131 will_send_frame_ = true;
132 }
133
ResetGamepad()134 void GamepadEventConverterEvdev::ResetGamepad() {
135 base::TimeTicks timestamp = ui::EventTimeForNow();
136 // Reset all the buttons.
137 for (unsigned int code : pressed_buttons_)
138 ProcessEvdevKey(code, 0, timestamp);
139 // Reset all the axes.
140 for (int code = 0; code < ABS_CNT; ++code)
141 ProcessEvdevAbs(code, 0, timestamp);
142 OnSync(timestamp);
143 }
144
ResyncGamepad()145 void GamepadEventConverterEvdev::ResyncGamepad() {
146 base::TimeTicks timestamp = ui::EventTimeForNow();
147 // Reset all the buttons.
148 for (unsigned int code : pressed_buttons_)
149 ProcessEvdevKey(code, 0, timestamp);
150 // Read the state of all axis.
151 EventDeviceInfo info;
152 if (!info.Initialize(fd_, path_)) {
153 LOG(ERROR) << "Failed to synchronize state for gamepad device: "
154 << path_.value();
155 Stop();
156 return;
157 }
158 for (int code = 0; code < ABS_CNT; ++code) {
159 if (info.HasAbsEvent(code)) {
160 ProcessEvdevAbs(code, info.GetAbsValue(code), timestamp);
161 }
162 }
163 OnSync(timestamp);
164 }
165
OnSync(const base::TimeTicks & timestamp)166 void GamepadEventConverterEvdev::OnSync(const base::TimeTicks& timestamp) {
167 if (will_send_frame_) {
168 GamepadEvent event(input_device_.id, GamepadEventType::FRAME, 0, 0,
169 timestamp);
170 dispatcher_->DispatchGamepadEvent(event);
171 will_send_frame_ = false;
172 }
173 }
174 } // namespace ui
175