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

Side by Side Diff: ui/events/ozone/evdev/touch_event_converter_evdev.cc

Issue 851853002: It is time. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Trying to reup because the last upload failed. Created 5 years, 11 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 unified diff | Download patch
OLDNEW
(Empty)
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.
4
5 #include "ui/events/ozone/evdev/touch_event_converter_evdev.h"
6
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>
13
14 #include <cmath>
15 #include <limits>
16
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/event.h"
27 #include "ui/events/event_constants.h"
28 #include "ui/events/event_switches.h"
29 #include "ui/gfx/screen.h"
30
31 namespace {
32
33 struct TouchCalibration {
34 int bezel_left;
35 int bezel_right;
36 int bezel_top;
37 int bezel_bottom;
38 };
39
40 void GetTouchCalibration(TouchCalibration* cal) {
41 std::vector<std::string> parts;
42 if (Tokenize(CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
43 switches::kTouchCalibration),
44 ",",
45 &parts) >= 4) {
46 if (!base::StringToInt(parts[0], &cal->bezel_left))
47 DLOG(ERROR) << "Incorrect left border calibration value passed.";
48 if (!base::StringToInt(parts[1], &cal->bezel_right))
49 DLOG(ERROR) << "Incorrect right border calibration value passed.";
50 if (!base::StringToInt(parts[2], &cal->bezel_top))
51 DLOG(ERROR) << "Incorrect top border calibration value passed.";
52 if (!base::StringToInt(parts[3], &cal->bezel_bottom))
53 DLOG(ERROR) << "Incorrect bottom border calibration value passed.";
54 }
55 }
56
57 float TuxelsToPixels(float val,
58 float min_tuxels,
59 float num_tuxels,
60 float min_pixels,
61 float num_pixels) {
62 // Map [min_tuxels, min_tuxels + num_tuxels) to
63 // [min_pixels, min_pixels + num_pixels).
64 return min_pixels + (val - min_tuxels) * num_pixels / num_tuxels;
65 }
66
67 float TuxelToPixelSize(float val, float num_tuxels, float num_pixels) {
68 return val * num_pixels / num_tuxels;
69 }
70
71 } // namespace
72
73 namespace ui {
74
75 TouchEventConverterEvdev::TouchEventConverterEvdev(
76 int fd,
77 base::FilePath path,
78 int id,
79 const EventDeviceInfo& info,
80 const EventDispatchCallback& callback)
81 : EventConverterEvdev(fd, path, id),
82 callback_(callback),
83 syn_dropped_(false),
84 is_type_a_(false),
85 current_slot_(0) {
86 Init(info);
87 }
88
89 TouchEventConverterEvdev::~TouchEventConverterEvdev() {
90 Stop();
91 close(fd_);
92 }
93
94 void TouchEventConverterEvdev::Init(const EventDeviceInfo& info) {
95 gfx::Screen* screen = gfx::Screen::GetScreenByType(gfx::SCREEN_TYPE_NATIVE);
96 if (!screen)
97 return; // No scaling.
98 gfx::Display display = screen->GetPrimaryDisplay();
99 gfx::Size size = display.GetSizeInPixel();
100
101 pressure_min_ = info.GetAbsMinimum(ABS_MT_PRESSURE);
102 pressure_max_ = info.GetAbsMaximum(ABS_MT_PRESSURE);
103 x_min_tuxels_ = info.GetAbsMinimum(ABS_MT_POSITION_X);
104 x_num_tuxels_ = info.GetAbsMaximum(ABS_MT_POSITION_X) - x_min_tuxels_ + 1;
105 y_min_tuxels_ = info.GetAbsMinimum(ABS_MT_POSITION_Y);
106 y_num_tuxels_ = info.GetAbsMaximum(ABS_MT_POSITION_Y) - y_min_tuxels_ + 1;
107 native_size_ = gfx::Size(x_num_tuxels_, y_num_tuxels_);
108
109 // Map coordinates onto screen.
110 x_min_pixels_ = 0;
111 y_min_pixels_ = 0;
112 x_num_pixels_ = size.width();
113 y_num_pixels_ = size.height();
114
115 VLOG(1) << "mapping touch coordinates to screen coordinates: "
116 << base::StringPrintf("%dx%d", size.width(), size.height());
117
118 // Apply --touch-calibration.
119 TouchCalibration cal = {};
120 GetTouchCalibration(&cal);
121 x_min_tuxels_ += cal.bezel_left;
122 x_num_tuxels_ -= cal.bezel_left + cal.bezel_right;
123 y_min_tuxels_ += cal.bezel_top;
124 y_num_tuxels_ -= cal.bezel_top + cal.bezel_bottom;
125
126 VLOG(1) << "applying touch calibration: "
127 << base::StringPrintf("[%d, %d, %d, %d]",
128 cal.bezel_left,
129 cal.bezel_right,
130 cal.bezel_top,
131 cal.bezel_bottom);
132 }
133
134 bool TouchEventConverterEvdev::Reinitialize() {
135 EventDeviceInfo info;
136 if (info.Initialize(fd_)) {
137 Init(info);
138 return true;
139 }
140 return false;
141 }
142
143 bool TouchEventConverterEvdev::HasTouchscreen() const {
144 return true;
145 }
146
147 gfx::Size TouchEventConverterEvdev::GetTouchscreenSize() const {
148 return native_size_;
149 }
150
151 void TouchEventConverterEvdev::OnFileCanReadWithoutBlocking(int fd) {
152 input_event inputs[MAX_FINGERS * 6 + 1];
153 ssize_t read_size = read(fd, inputs, sizeof(inputs));
154 if (read_size < 0) {
155 if (errno == EINTR || errno == EAGAIN)
156 return;
157 if (errno != ENODEV)
158 PLOG(ERROR) << "error reading device " << path_.value();
159 Stop();
160 return;
161 }
162
163 for (unsigned i = 0; i < read_size / sizeof(*inputs); i++) {
164 ProcessInputEvent(inputs[i]);
165 }
166 }
167
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 (current_slot_ >= MAX_FINGERS) {
175 LOG(ERROR) << "too many touch events: " << current_slot_;
176 return;
177 }
178 ProcessAbs(input);
179 } else if (input.type == EV_KEY) {
180 switch (input.code) {
181 case BTN_TOUCH:
182 break;
183 default:
184 NOTIMPLEMENTED() << "invalid code for EV_KEY: " << input.code;
185 }
186 } else {
187 NOTIMPLEMENTED() << "invalid type: " << input.type;
188 }
189 }
190
191 void TouchEventConverterEvdev::ProcessAbs(const input_event& input) {
192 switch (input.code) {
193 case ABS_MT_TOUCH_MAJOR:
194 altered_slots_.set(current_slot_);
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_ =
199 TuxelToPixelSize(input.value, x_num_tuxels_, x_num_pixels_) / 2.0f;
200 break;
201 case ABS_MT_TOUCH_MINOR:
202 altered_slots_.set(current_slot_);
203 events_[current_slot_].radius_y_ =
204 TuxelToPixelSize(input.value, y_num_tuxels_, y_num_pixels_) / 2.0f;
205 break;
206 case ABS_MT_POSITION_X:
207 altered_slots_.set(current_slot_);
208 events_[current_slot_].x_ = TuxelsToPixels(input.value,
209 x_min_tuxels_,
210 x_num_tuxels_,
211 x_min_pixels_,
212 x_num_pixels_);
213 break;
214 case ABS_MT_POSITION_Y:
215 altered_slots_.set(current_slot_);
216 events_[current_slot_].y_ = TuxelsToPixels(input.value,
217 y_min_tuxels_,
218 y_num_tuxels_,
219 y_min_pixels_,
220 y_num_pixels_);
221 break;
222 case ABS_MT_TRACKING_ID:
223 altered_slots_.set(current_slot_);
224 if (input.value < 0) {
225 events_[current_slot_].type_ = ET_TOUCH_RELEASED;
226 } else {
227 events_[current_slot_].finger_ = input.value;
228 events_[current_slot_].type_ = ET_TOUCH_PRESSED;
229 }
230 break;
231 case ABS_MT_PRESSURE:
232 altered_slots_.set(current_slot_);
233 events_[current_slot_].pressure_ = input.value - pressure_min_;
234 events_[current_slot_].pressure_ /= pressure_max_ - pressure_min_;
235 break;
236 case ABS_MT_SLOT:
237 current_slot_ = input.value;
238 altered_slots_.set(current_slot_);
239 break;
240 default:
241 DVLOG(5) << "unhandled code for EV_ABS: " << input.code;
242 }
243 }
244
245 void TouchEventConverterEvdev::ProcessSyn(const input_event& input) {
246 switch (input.code) {
247 case SYN_REPORT:
248 if (syn_dropped_) {
249 // Have to re-initialize.
250 if (Reinitialize()) {
251 syn_dropped_ = false;
252 altered_slots_.reset();
253 } else {
254 LOG(ERROR) << "failed to re-initialize device info";
255 }
256 } else {
257 ReportEvents(base::TimeDelta::FromMicroseconds(
258 input.time.tv_sec * 1000000 + input.time.tv_usec));
259 }
260 if (is_type_a_)
261 current_slot_ = 0;
262 break;
263 case SYN_MT_REPORT:
264 // For type A devices, we just get a stream of all current contacts,
265 // in some arbitrary order.
266 events_[current_slot_++].type_ = ET_TOUCH_PRESSED;
267 is_type_a_ = true;
268 break;
269 case SYN_DROPPED:
270 // Some buffer has overrun. We ignore all events up to and
271 // including the next SYN_REPORT.
272 syn_dropped_ = true;
273 break;
274 default:
275 NOTIMPLEMENTED() << "invalid code for EV_SYN: " << input.code;
276 }
277 }
278
279 void TouchEventConverterEvdev::ReportEvents(base::TimeDelta delta) {
280 for (int i = 0; i < MAX_FINGERS; i++) {
281 if (altered_slots_[i]) {
282 // TODO(rikroege): Support elliptical finger regions.
283 callback_.Run(make_scoped_ptr(
284 new TouchEvent(events_[i].type_,
285 gfx::PointF(events_[i].x_, events_[i].y_),
286 /* flags */ 0,
287 /* touch_id */ i,
288 delta,
289 /* radius_x */ events_[i].radius_x_,
290 /* radius_y */ events_[i].radius_y_,
291 /* angle */ 0.,
292 events_[i].pressure_)));
293
294 // Subsequent events for this finger will be touch-move until it
295 // is released.
296 events_[i].type_ = ET_TOUCH_MOVED;
297 }
298 }
299 altered_slots_.reset();
300 }
301
302 } // namespace ui
OLDNEW
« no previous file with comments | « ui/events/ozone/evdev/touch_event_converter_evdev.h ('k') | ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698