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"
9 #include <linux/input.h>
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"
34 struct TouchCalibration
{
41 void GetTouchCalibration(TouchCalibration
* cal
) {
42 std::vector
<std::string
> parts
;
43 if (Tokenize(base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
44 switches::kTouchCalibration
),
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.";
61 TouchEventConverterEvdev::InProgressEvents::InProgressEvents()
72 TouchEventConverterEvdev::TouchEventConverterEvdev(
77 const EventDispatchCallback
& callback
)
78 : EventConverterEvdev(fd
, path
, id
, type
),
85 TouchEventConverterEvdev::~TouchEventConverterEvdev() {
90 void TouchEventConverterEvdev::Initialize(const EventDeviceInfo
& info
) {
91 pressure_min_
= info
.GetAbsMinimum(ABS_MT_PRESSURE
);
92 pressure_max_
= info
.GetAbsMaximum(ABS_MT_PRESSURE
);
93 x_min_tuxels_
= info
.GetAbsMinimum(ABS_MT_POSITION_X
);
94 x_num_tuxels_
= info
.GetAbsMaximum(ABS_MT_POSITION_X
) - x_min_tuxels_
+ 1;
95 y_min_tuxels_
= info
.GetAbsMinimum(ABS_MT_POSITION_Y
);
96 y_num_tuxels_
= info
.GetAbsMaximum(ABS_MT_POSITION_Y
) - y_min_tuxels_
+ 1;
98 // Apply --touch-calibration.
99 if (type() == INPUT_DEVICE_INTERNAL
) {
100 TouchCalibration cal
= {};
101 GetTouchCalibration(&cal
);
102 x_min_tuxels_
+= cal
.bezel_left
;
103 x_num_tuxels_
-= cal
.bezel_left
+ cal
.bezel_right
;
104 y_min_tuxels_
+= cal
.bezel_top
;
105 y_num_tuxels_
-= cal
.bezel_top
+ cal
.bezel_bottom
;
107 VLOG(1) << "applying touch calibration: "
108 << base::StringPrintf("[%d, %d, %d, %d]", cal
.bezel_left
,
109 cal
.bezel_right
, cal
.bezel_top
,
113 native_size_
= gfx::Size(x_num_tuxels_
, y_num_tuxels_
);
116 i
< std::min
<int>(info
.GetAbsMaximum(ABS_MT_SLOT
) + 1, MAX_FINGERS
);
118 events_
[i
].finger_
= info
.GetSlotValue(ABS_MT_TRACKING_ID
, i
);
120 events_
[i
].finger_
< 0 ? ET_TOUCH_RELEASED
: ET_TOUCH_PRESSED
;
121 events_
[i
].x_
= info
.GetSlotValue(ABS_MT_POSITION_X
, i
);
122 events_
[i
].y_
= info
.GetSlotValue(ABS_MT_POSITION_Y
, i
);
123 events_
[i
].radius_x_
= info
.GetSlotValue(ABS_MT_TOUCH_MAJOR
, i
);
124 events_
[i
].radius_y_
= info
.GetSlotValue(ABS_MT_TOUCH_MINOR
, i
);
125 events_
[i
].pressure_
= info
.GetSlotValue(ABS_MT_PRESSURE
, i
);
129 bool TouchEventConverterEvdev::Reinitialize() {
130 EventDeviceInfo info
;
131 if (info
.Initialize(fd_
)) {
138 bool TouchEventConverterEvdev::HasTouchscreen() const {
142 gfx::Size
TouchEventConverterEvdev::GetTouchscreenSize() const {
146 void TouchEventConverterEvdev::OnFileCanReadWithoutBlocking(int fd
) {
147 input_event inputs
[MAX_FINGERS
* 6 + 1];
148 ssize_t read_size
= read(fd
, inputs
, sizeof(inputs
));
150 if (errno
== EINTR
|| errno
== EAGAIN
)
153 PLOG(ERROR
) << "error reading device " << path_
.value();
158 for (unsigned i
= 0; i
< read_size
/ sizeof(*inputs
); i
++) {
159 ProcessInputEvent(inputs
[i
]);
163 void TouchEventConverterEvdev::ProcessInputEvent(const input_event
& input
) {
164 if (input
.type
== EV_SYN
) {
166 } else if(syn_dropped_
) {
167 // Do nothing. This branch indicates we have lost sync with the driver.
168 } else if (input
.type
== EV_ABS
) {
169 if (current_slot_
>= MAX_FINGERS
) {
170 LOG(ERROR
) << "too many touch events: " << current_slot_
;
174 } else if (input
.type
== EV_KEY
) {
175 switch (input
.code
) {
179 NOTIMPLEMENTED() << "invalid code for EV_KEY: " << input
.code
;
182 NOTIMPLEMENTED() << "invalid type: " << input
.type
;
186 void TouchEventConverterEvdev::ProcessAbs(const input_event
& input
) {
187 switch (input
.code
) {
188 case ABS_MT_TOUCH_MAJOR
:
189 altered_slots_
.set(current_slot_
);
190 // TODO(spang): If we have all of major, minor, and orientation,
191 // we can scale the ellipse correctly. However on the Pixel we get
192 // neither minor nor orientation, so this is all we can do.
193 events_
[current_slot_
].radius_x_
= input
.value
/ 2.0f
;
195 case ABS_MT_TOUCH_MINOR
:
196 altered_slots_
.set(current_slot_
);
197 events_
[current_slot_
].radius_y_
= input
.value
/ 2.0f
;
199 case ABS_MT_POSITION_X
:
200 altered_slots_
.set(current_slot_
);
201 events_
[current_slot_
].x_
= input
.value
;
203 case ABS_MT_POSITION_Y
:
204 altered_slots_
.set(current_slot_
);
205 events_
[current_slot_
].y_
= input
.value
;
207 case ABS_MT_TRACKING_ID
:
208 altered_slots_
.set(current_slot_
);
209 if (input
.value
< 0) {
210 events_
[current_slot_
].type_
= ET_TOUCH_RELEASED
;
212 events_
[current_slot_
].finger_
= input
.value
;
213 events_
[current_slot_
].type_
= ET_TOUCH_PRESSED
;
216 case ABS_MT_PRESSURE
:
217 altered_slots_
.set(current_slot_
);
218 events_
[current_slot_
].pressure_
= input
.value
- pressure_min_
;
219 events_
[current_slot_
].pressure_
/= pressure_max_
- pressure_min_
;
222 current_slot_
= input
.value
;
223 altered_slots_
.set(current_slot_
);
226 DVLOG(5) << "unhandled code for EV_ABS: " << input
.code
;
230 void TouchEventConverterEvdev::ProcessSyn(const input_event
& input
) {
231 switch (input
.code
) {
234 // Have to re-initialize.
235 if (Reinitialize()) {
236 syn_dropped_
= false;
237 altered_slots_
.reset();
239 LOG(ERROR
) << "failed to re-initialize device info";
242 ReportEvents(base::TimeDelta::FromMicroseconds(
243 input
.time
.tv_sec
* 1000000 + input
.time
.tv_usec
));
249 // For type A devices, we just get a stream of all current contacts,
250 // in some arbitrary order.
251 events_
[current_slot_
++].type_
= ET_TOUCH_PRESSED
;
255 // Some buffer has overrun. We ignore all events up to and
256 // including the next SYN_REPORT.
260 NOTIMPLEMENTED() << "invalid code for EV_SYN: " << input
.code
;
264 void TouchEventConverterEvdev::ReportEvent(int touch_id
,
265 const InProgressEvents
& event
, const base::TimeDelta
& delta
) {
269 double radius_x
= event
.radius_x_
;
270 double radius_y
= event
.radius_y_
;
272 // Transform the event according (this is used to align touches
273 // to the image based on display mode).
274 DeviceDataManager::GetInstance()->ApplyTouchTransformer(
276 DeviceDataManager::GetInstance()->ApplyTouchRadiusScale(
278 DeviceDataManager::GetInstance()->ApplyTouchRadiusScale(
281 gfx::PointF
location(x
, y
);
283 scoped_ptr
<TouchEvent
> touch_event(
284 new TouchEvent(event
.type_
, location
,
286 /* touch_id */ touch_id
,
288 /* radius_x */ radius_x
,
289 /* radius_y */ radius_y
,
292 touch_event
->set_source_device_id(id_
);
293 callback_
.Run(touch_event
.Pass());
296 void TouchEventConverterEvdev::ReportEvents(base::TimeDelta delta
) {
297 for (int i
= 0; i
< MAX_FINGERS
; i
++) {
298 if (altered_slots_
[i
]) {
299 ReportEvent(i
, events_
[i
], delta
);
301 // Subsequent events for this finger will be touch-move until it
303 events_
[i
].type_
= ET_TOUCH_MOVED
;
306 altered_slots_
.reset();