Landing Recent QUIC Changes.
[chromium-blink-merge.git] / ui / events / ozone / evdev / touch_event_converter_evdev.cc
blob8522a60e60dc75cf9a5d2106cc2ccdf8e240a0b1
1 // Copyright 2014 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.
5 #include "ui/events/ozone/evdev/touch_event_converter_evdev.h"
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <linux/input.h>
10 #include <poll.h>
11 #include <stdio.h>
12 #include <unistd.h>
14 #include <cmath>
15 #include <limits>
17 #include "base/bind.h"
18 #include "base/callback.h"
19 #include "base/command_line.h"
20 #include "base/logging.h"
21 #include "base/memory/scoped_vector.h"
22 #include "base/message_loop/message_loop.h"
23 #include "base/strings/string_number_conversions.h"
24 #include "base/strings/string_util.h"
25 #include "base/strings/stringprintf.h"
26 #include "ui/events/devices/device_data_manager.h"
27 #include "ui/events/devices/device_util_linux.h"
28 #include "ui/events/event.h"
29 #include "ui/events/event_constants.h"
30 #include "ui/events/event_switches.h"
31 #include "ui/events/ozone/evdev/device_event_dispatcher_evdev.h"
33 namespace {
35 struct TouchCalibration {
36 int bezel_left;
37 int bezel_right;
38 int bezel_top;
39 int bezel_bottom;
42 void GetTouchCalibration(TouchCalibration* cal) {
43 std::vector<std::string> parts;
44 if (Tokenize(base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
45 switches::kTouchCalibration),
46 ",", &parts) >= 4) {
47 if (!base::StringToInt(parts[0], &cal->bezel_left))
48 DLOG(ERROR) << "Incorrect left border calibration value passed.";
49 if (!base::StringToInt(parts[1], &cal->bezel_right))
50 DLOG(ERROR) << "Incorrect right border calibration value passed.";
51 if (!base::StringToInt(parts[2], &cal->bezel_top))
52 DLOG(ERROR) << "Incorrect top border calibration value passed.";
53 if (!base::StringToInt(parts[3], &cal->bezel_bottom))
54 DLOG(ERROR) << "Incorrect bottom border calibration value passed.";
58 } // namespace
60 namespace ui {
62 TouchEventConverterEvdev::InProgressEvents::InProgressEvents()
63 : altered_(false),
64 x_(0),
65 y_(0),
66 id_(-1),
67 finger_(-1),
68 type_(ET_UNKNOWN),
69 radius_x_(0),
70 radius_y_(0),
71 pressure_(0) {
74 TouchEventConverterEvdev::TouchEventConverterEvdev(
75 int fd,
76 base::FilePath path,
77 int id,
78 InputDeviceType type,
79 DeviceEventDispatcherEvdev* dispatcher)
80 : EventConverterEvdev(fd, path, id, type),
81 dispatcher_(dispatcher),
82 syn_dropped_(false),
83 is_type_a_(false),
84 current_slot_(0) {
87 TouchEventConverterEvdev::~TouchEventConverterEvdev() {
88 Stop();
89 close(fd_);
92 void TouchEventConverterEvdev::Initialize(const EventDeviceInfo& info) {
93 pressure_min_ = info.GetAbsMinimum(ABS_MT_PRESSURE);
94 pressure_max_ = info.GetAbsMaximum(ABS_MT_PRESSURE);
95 x_min_tuxels_ = info.GetAbsMinimum(ABS_MT_POSITION_X);
96 x_num_tuxels_ = info.GetAbsMaximum(ABS_MT_POSITION_X) - x_min_tuxels_ + 1;
97 y_min_tuxels_ = info.GetAbsMinimum(ABS_MT_POSITION_Y);
98 y_num_tuxels_ = info.GetAbsMaximum(ABS_MT_POSITION_Y) - y_min_tuxels_ + 1;
100 // Apply --touch-calibration.
101 if (type() == INPUT_DEVICE_INTERNAL) {
102 TouchCalibration cal = {};
103 GetTouchCalibration(&cal);
104 x_min_tuxels_ += cal.bezel_left;
105 x_num_tuxels_ -= cal.bezel_left + cal.bezel_right;
106 y_min_tuxels_ += cal.bezel_top;
107 y_num_tuxels_ -= cal.bezel_top + cal.bezel_bottom;
109 VLOG(1) << "applying touch calibration: "
110 << base::StringPrintf("[%d, %d, %d, %d]", cal.bezel_left,
111 cal.bezel_right, cal.bezel_top,
112 cal.bezel_bottom);
115 native_size_ = gfx::Size(x_num_tuxels_, y_num_tuxels_);
117 events_.resize(
118 std::min<int>(info.GetAbsMaximum(ABS_MT_SLOT) + 1, MAX_FINGERS));
119 for (size_t i = 0; i < events_.size(); ++i) {
120 events_[i].finger_ = info.GetSlotValue(ABS_MT_TRACKING_ID, i);
121 events_[i].type_ =
122 events_[i].finger_ < 0 ? ET_TOUCH_RELEASED : ET_TOUCH_PRESSED;
123 events_[i].x_ = info.GetSlotValue(ABS_MT_POSITION_X, i);
124 events_[i].y_ = info.GetSlotValue(ABS_MT_POSITION_Y, i);
125 events_[i].radius_x_ = info.GetSlotValue(ABS_MT_TOUCH_MAJOR, i);
126 events_[i].radius_y_ = info.GetSlotValue(ABS_MT_TOUCH_MINOR, i);
127 events_[i].pressure_ = info.GetSlotValue(ABS_MT_PRESSURE, i);
131 bool TouchEventConverterEvdev::Reinitialize() {
132 EventDeviceInfo info;
133 if (info.Initialize(fd_)) {
134 Initialize(info);
135 return true;
137 return false;
140 bool TouchEventConverterEvdev::HasTouchscreen() const {
141 return true;
144 gfx::Size TouchEventConverterEvdev::GetTouchscreenSize() const {
145 return native_size_;
148 void TouchEventConverterEvdev::OnFileCanReadWithoutBlocking(int fd) {
149 input_event inputs[MAX_FINGERS * 6 + 1];
150 ssize_t read_size = read(fd, inputs, sizeof(inputs));
151 if (read_size < 0) {
152 if (errno == EINTR || errno == EAGAIN)
153 return;
154 if (errno != ENODEV)
155 PLOG(ERROR) << "error reading device " << path_.value();
156 Stop();
157 return;
160 if (ignore_events_)
161 return;
163 for (unsigned i = 0; i < read_size / sizeof(*inputs); i++) {
164 ProcessInputEvent(inputs[i]);
168 void TouchEventConverterEvdev::ProcessInputEvent(const input_event& input) {
169 if (input.type == EV_SYN) {
170 ProcessSyn(input);
171 } else if(syn_dropped_) {
172 // Do nothing. This branch indicates we have lost sync with the driver.
173 } else if (input.type == EV_ABS) {
174 if (events_.size() <= current_slot_) {
175 LOG(ERROR) << "current_slot_ (" << current_slot_
176 << ") >= events_.size() (" << events_.size() << ")";
177 } else {
178 ProcessAbs(input);
180 } else if (input.type == EV_KEY) {
181 switch (input.code) {
182 case BTN_TOUCH:
183 break;
184 default:
185 NOTIMPLEMENTED() << "invalid code for EV_KEY: " << input.code;
187 } else {
188 NOTIMPLEMENTED() << "invalid type: " << input.type;
192 void TouchEventConverterEvdev::ProcessAbs(const input_event& input) {
193 switch (input.code) {
194 case ABS_MT_TOUCH_MAJOR:
195 // TODO(spang): If we have all of major, minor, and orientation,
196 // we can scale the ellipse correctly. However on the Pixel we get
197 // neither minor nor orientation, so this is all we can do.
198 events_[current_slot_].radius_x_ = input.value / 2.0f;
199 break;
200 case ABS_MT_TOUCH_MINOR:
201 events_[current_slot_].radius_y_ = input.value / 2.0f;
202 break;
203 case ABS_MT_POSITION_X:
204 events_[current_slot_].x_ = input.value;
205 break;
206 case ABS_MT_POSITION_Y:
207 events_[current_slot_].y_ = input.value;
208 break;
209 case ABS_MT_TRACKING_ID:
210 if (input.value < 0) {
211 events_[current_slot_].type_ = ET_TOUCH_RELEASED;
212 } else {
213 events_[current_slot_].finger_ = input.value;
214 events_[current_slot_].type_ = ET_TOUCH_PRESSED;
216 break;
217 case ABS_MT_PRESSURE:
218 events_[current_slot_].pressure_ = input.value - pressure_min_;
219 events_[current_slot_].pressure_ /= pressure_max_ - pressure_min_;
220 break;
221 case ABS_MT_SLOT:
222 if (input.value >= 0 &&
223 static_cast<size_t>(input.value) < events_.size()) {
224 current_slot_ = input.value;
225 } else {
226 LOG(ERROR) << "invalid touch event index: " << input.value;
227 return;
229 break;
230 default:
231 DVLOG(5) << "unhandled code for EV_ABS: " << input.code;
232 return;
234 events_[current_slot_].altered_ = true;
237 void TouchEventConverterEvdev::ProcessSyn(const input_event& input) {
238 switch (input.code) {
239 case SYN_REPORT:
240 if (syn_dropped_) {
241 // Have to re-initialize.
242 if (Reinitialize()) {
243 syn_dropped_ = false;
244 for(InProgressEvents& event: events_)
245 event.altered_ = false;
246 } else {
247 LOG(ERROR) << "failed to re-initialize device info";
249 } else {
250 ReportEvents(base::TimeDelta::FromMicroseconds(
251 input.time.tv_sec * 1000000 + input.time.tv_usec));
253 if (is_type_a_)
254 current_slot_ = 0;
255 break;
256 case SYN_MT_REPORT:
257 // For type A devices, we just get a stream of all current contacts,
258 // in some arbitrary order.
259 events_[current_slot_].type_ = ET_TOUCH_PRESSED;
260 if (events_.size() - 1 > current_slot_)
261 current_slot_++;
262 is_type_a_ = true;
263 break;
264 case SYN_DROPPED:
265 // Some buffer has overrun. We ignore all events up to and
266 // including the next SYN_REPORT.
267 syn_dropped_ = true;
268 break;
269 default:
270 NOTIMPLEMENTED() << "invalid code for EV_SYN: " << input.code;
274 void TouchEventConverterEvdev::ReportEvent(int touch_id,
275 const InProgressEvents& event,
276 const base::TimeDelta& timestamp) {
277 dispatcher_->DispatchTouchEvent(TouchEventParams(
278 id_, touch_id, event.type_, gfx::PointF(event.x_, event.y_),
279 gfx::Vector2dF(event.radius_x_, event.radius_y_), event.pressure_,
280 timestamp));
283 void TouchEventConverterEvdev::ReportEvents(base::TimeDelta delta) {
284 for (size_t i = 0; i < events_.size(); i++) {
285 if (events_[i].altered_) {
286 ReportEvent(i, events_[i], delta);
288 // Subsequent events for this finger will be touch-move until it
289 // is released.
290 events_[i].type_ = ET_TOUCH_MOVED;
291 events_[i].altered_ = false;
296 } // namespace ui