Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / ui / events / ozone / evdev / touch_event_converter_evdev.cc
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/devices/device_util_linux.h"
27 #include "ui/events/event.h"
28 #include "ui/events/event_constants.h"
29 #include "ui/events/event_switches.h"
30 #include "ui/gfx/screen.h"
31
32 namespace {
33
34 struct TouchCalibration {
35   int bezel_left;
36   int bezel_right;
37   int bezel_top;
38   int bezel_bottom;
39 };
40
41 void GetTouchCalibration(TouchCalibration* cal) {
42   std::vector<std::string> parts;
43   if (Tokenize(CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
44                    switches::kTouchCalibration),
45                ",",
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.";
55   }
56 }
57
58 float TuxelsToPixels(float val,
59                      float min_tuxels,
60                      float num_tuxels,
61                      float min_pixels,
62                      float num_pixels) {
63   // Map [min_tuxels, min_tuxels + num_tuxels) to
64   //     [min_pixels, min_pixels + num_pixels).
65   return min_pixels + (val - min_tuxels) * num_pixels / num_tuxels;
66 }
67
68 float TuxelToPixelSize(float val, float num_tuxels, float num_pixels) {
69   return val * num_pixels / num_tuxels;
70 }
71
72 }  // namespace
73
74 namespace ui {
75
76 TouchEventConverterEvdev::InProgressEvents::InProgressEvents()
77     : x_(0),
78       y_(0),
79       id_(-1),
80       finger_(-1),
81       type_(ET_UNKNOWN),
82       radius_x_(0),
83       radius_y_(0),
84       pressure_(0) {
85 }
86
87 TouchEventConverterEvdev::TouchEventConverterEvdev(
88     int fd,
89     base::FilePath path,
90     int id,
91     const EventDeviceInfo& info,
92     const EventDispatchCallback& callback)
93     : EventConverterEvdev(fd, path, id),
94       callback_(callback),
95       syn_dropped_(false),
96       is_type_a_(false),
97       current_slot_(0),
98       is_internal_(IsTouchscreenInternal(path)) {
99   Init(info);
100 }
101
102 TouchEventConverterEvdev::~TouchEventConverterEvdev() {
103   Stop();
104   close(fd_);
105 }
106
107 void TouchEventConverterEvdev::Init(const EventDeviceInfo& info) {
108   gfx::Screen* screen = gfx::Screen::GetScreenByType(gfx::SCREEN_TYPE_NATIVE);
109   if (!screen)
110     return;  // No scaling.
111   gfx::Display display = screen->GetPrimaryDisplay();
112   gfx::Size size = display.GetSizeInPixel();
113
114   pressure_min_ = info.GetAbsMinimum(ABS_MT_PRESSURE);
115   pressure_max_ = info.GetAbsMaximum(ABS_MT_PRESSURE);
116   x_min_tuxels_ = info.GetAbsMinimum(ABS_MT_POSITION_X);
117   x_num_tuxels_ = info.GetAbsMaximum(ABS_MT_POSITION_X) - x_min_tuxels_ + 1;
118   y_min_tuxels_ = info.GetAbsMinimum(ABS_MT_POSITION_Y);
119   y_num_tuxels_ = info.GetAbsMaximum(ABS_MT_POSITION_Y) - y_min_tuxels_ + 1;
120   native_size_ = gfx::Size(x_num_tuxels_, y_num_tuxels_);
121
122   // Map coordinates onto screen.
123   x_min_pixels_ = 0;
124   y_min_pixels_ = 0;
125   x_num_pixels_ = size.width();
126   y_num_pixels_ = size.height();
127
128   VLOG(1) << "mapping touch coordinates to screen coordinates: "
129           << base::StringPrintf("%dx%d", size.width(), size.height());
130
131   // Apply --touch-calibration.
132   TouchCalibration cal = {};
133   GetTouchCalibration(&cal);
134   x_min_tuxels_ += cal.bezel_left;
135   x_num_tuxels_ -= cal.bezel_left + cal.bezel_right;
136   y_min_tuxels_ += cal.bezel_top;
137   y_num_tuxels_ -= cal.bezel_top + cal.bezel_bottom;
138
139   VLOG(1) << "applying touch calibration: "
140           << base::StringPrintf("[%d, %d, %d, %d]",
141                                 cal.bezel_left,
142                                 cal.bezel_right,
143                                 cal.bezel_top,
144                                 cal.bezel_bottom);
145
146   for (int i = 0;
147        i < std::min<int>(info.GetAbsMaximum(ABS_MT_SLOT) + 1, MAX_FINGERS);
148        ++i) {
149     events_[i].finger_ = info.GetSlotValue(ABS_MT_TRACKING_ID, i);
150     events_[i].type_ =
151         events_[i].finger_ < 0 ? ET_TOUCH_RELEASED : ET_TOUCH_PRESSED;
152     events_[i].x_ = info.GetSlotValue(ABS_MT_POSITION_X, i);
153     events_[i].y_ = info.GetSlotValue(ABS_MT_POSITION_Y, i);
154     events_[i].radius_x_ = info.GetSlotValue(ABS_MT_TOUCH_MAJOR, i);
155     events_[i].radius_y_ = info.GetSlotValue(ABS_MT_TOUCH_MINOR, i);
156     events_[i].pressure_ = info.GetSlotValue(ABS_MT_PRESSURE, i);
157   }
158 }
159
160 bool TouchEventConverterEvdev::Reinitialize() {
161   EventDeviceInfo info;
162   if (info.Initialize(fd_)) {
163     Init(info);
164     return true;
165   }
166   return false;
167 }
168
169 bool TouchEventConverterEvdev::HasTouchscreen() const {
170   return true;
171 }
172
173 gfx::Size TouchEventConverterEvdev::GetTouchscreenSize() const {
174   return native_size_;
175 }
176
177 bool TouchEventConverterEvdev::IsInternal() const {
178   return is_internal_;
179 }
180
181 void TouchEventConverterEvdev::OnFileCanReadWithoutBlocking(int fd) {
182   input_event inputs[MAX_FINGERS * 6 + 1];
183   ssize_t read_size = read(fd, inputs, sizeof(inputs));
184   if (read_size < 0) {
185     if (errno == EINTR || errno == EAGAIN)
186       return;
187     if (errno != ENODEV)
188       PLOG(ERROR) << "error reading device " << path_.value();
189     Stop();
190     return;
191   }
192
193   for (unsigned i = 0; i < read_size / sizeof(*inputs); i++) {
194     ProcessInputEvent(inputs[i]);
195   }
196 }
197
198 void TouchEventConverterEvdev::ProcessInputEvent(const input_event& input) {
199   if (input.type == EV_SYN) {
200     ProcessSyn(input);
201   } else if(syn_dropped_) {
202     // Do nothing. This branch indicates we have lost sync with the driver.
203   } else if (input.type == EV_ABS) {
204     if (current_slot_ >= MAX_FINGERS) {
205       LOG(ERROR) << "too many touch events: " << current_slot_;
206       return;
207     }
208     ProcessAbs(input);
209   } else if (input.type == EV_KEY) {
210     switch (input.code) {
211       case BTN_TOUCH:
212         break;
213       default:
214         NOTIMPLEMENTED() << "invalid code for EV_KEY: " << input.code;
215     }
216   } else {
217     NOTIMPLEMENTED() << "invalid type: " << input.type;
218   }
219 }
220
221 void TouchEventConverterEvdev::ProcessAbs(const input_event& input) {
222   switch (input.code) {
223     case ABS_MT_TOUCH_MAJOR:
224       altered_slots_.set(current_slot_);
225       // TODO(spang): If we have all of major, minor, and orientation,
226       // we can scale the ellipse correctly. However on the Pixel we get
227       // neither minor nor orientation, so this is all we can do.
228       events_[current_slot_].radius_x_ =
229           TuxelToPixelSize(input.value, x_num_tuxels_, x_num_pixels_) / 2.0f;
230       break;
231     case ABS_MT_TOUCH_MINOR:
232       altered_slots_.set(current_slot_);
233       events_[current_slot_].radius_y_ =
234           TuxelToPixelSize(input.value, y_num_tuxels_, y_num_pixels_) / 2.0f;
235       break;
236     case ABS_MT_POSITION_X:
237       altered_slots_.set(current_slot_);
238       events_[current_slot_].x_ = TuxelsToPixels(input.value,
239                                                  x_min_tuxels_,
240                                                  x_num_tuxels_,
241                                                  x_min_pixels_,
242                                                  x_num_pixels_);
243       break;
244     case ABS_MT_POSITION_Y:
245       altered_slots_.set(current_slot_);
246       events_[current_slot_].y_ = TuxelsToPixels(input.value,
247                                                  y_min_tuxels_,
248                                                  y_num_tuxels_,
249                                                  y_min_pixels_,
250                                                  y_num_pixels_);
251       break;
252     case ABS_MT_TRACKING_ID:
253       altered_slots_.set(current_slot_);
254       if (input.value < 0) {
255         events_[current_slot_].type_ = ET_TOUCH_RELEASED;
256       } else {
257         events_[current_slot_].finger_ = input.value;
258         events_[current_slot_].type_ = ET_TOUCH_PRESSED;
259       }
260       break;
261     case ABS_MT_PRESSURE:
262       altered_slots_.set(current_slot_);
263       events_[current_slot_].pressure_ = input.value - pressure_min_;
264       events_[current_slot_].pressure_ /= pressure_max_ - pressure_min_;
265       break;
266     case ABS_MT_SLOT:
267       current_slot_ = input.value;
268       altered_slots_.set(current_slot_);
269       break;
270     default:
271       DVLOG(5) << "unhandled code for EV_ABS: " << input.code;
272   }
273 }
274
275 void TouchEventConverterEvdev::ProcessSyn(const input_event& input) {
276   switch (input.code) {
277     case SYN_REPORT:
278       if (syn_dropped_) {
279         // Have to re-initialize.
280         if (Reinitialize()) {
281           syn_dropped_ = false;
282           altered_slots_.reset();
283         } else {
284           LOG(ERROR) << "failed to re-initialize device info";
285         }
286       } else {
287         ReportEvents(base::TimeDelta::FromMicroseconds(
288             input.time.tv_sec * 1000000 + input.time.tv_usec));
289       }
290       if (is_type_a_)
291         current_slot_ = 0;
292       break;
293     case SYN_MT_REPORT:
294       // For type A devices, we just get a stream of all current contacts,
295       // in some arbitrary order.
296       events_[current_slot_++].type_ = ET_TOUCH_PRESSED;
297       is_type_a_ = true;
298       break;
299     case SYN_DROPPED:
300       // Some buffer has overrun. We ignore all events up to and
301       // including the next SYN_REPORT.
302       syn_dropped_ = true;
303       break;
304     default:
305       NOTIMPLEMENTED() << "invalid code for EV_SYN: " << input.code;
306   }
307 }
308
309 void TouchEventConverterEvdev::ReportEvents(base::TimeDelta delta) {
310   for (int i = 0; i < MAX_FINGERS; i++) {
311     if (altered_slots_[i]) {
312       // TODO(rikroege): Support elliptical finger regions.
313       scoped_ptr<TouchEvent> event(
314           new TouchEvent(events_[i].type_,
315                          gfx::PointF(events_[i].x_, events_[i].y_),
316                          /* flags */ 0,
317                          /* touch_id */ i,
318                          delta,
319                          /* radius_x */ events_[i].radius_x_,
320                          /* radius_y */ events_[i].radius_y_,
321                          /* angle */ 0.,
322                          events_[i].pressure_));
323       event->set_source_device_id(id_);
324       callback_.Run(event.Pass());
325
326       // Subsequent events for this finger will be touch-move until it
327       // is released.
328       events_[i].type_ = ET_TOUCH_MOVED;
329     }
330   }
331   altered_slots_.reset();
332 }
333
334 }  // namespace ui