1// Copyright 2013 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/event_factory.h"
6
7#include <errno.h>
8#include <fcntl.h>
9#include <linux/input.h>
10#include <poll.h>
11#include <unistd.h>
12
13#include "base/strings/stringprintf.h"
14#include "ui/events/ozone/evdev/event_device_info.h"
15#include "ui/events/ozone/evdev/key_event_converter.h"
16#include "ui/events/ozone/evdev/touch_event_converter.h"
17#include "ui/events/ozone/event_factory_ozone.h"
18
19namespace ui {
20
21namespace {
22
23bool IsTouchPad(const EventDeviceInfo& devinfo) {
24  if (!devinfo.HasEventType(EV_ABS))
25    return false;
26
27  return devinfo.HasKeyEvent(BTN_LEFT) || devinfo.HasKeyEvent(BTN_MIDDLE) ||
28         devinfo.HasKeyEvent(BTN_RIGHT) || devinfo.HasKeyEvent(BTN_TOOL_FINGER);
29}
30
31bool IsTouchScreen(const EventDeviceInfo& devinfo) {
32  return devinfo.HasEventType(EV_ABS) && !IsTouchPad(devinfo);
33}
34
35}  // namespace
36
37EventFactoryEvdev::EventFactoryEvdev() {}
38
39EventFactoryEvdev::~EventFactoryEvdev() {}
40
41void EventFactoryEvdev::StartProcessingEvents() {
42  // The number of devices in the directory is unknown without reading
43  // the contents of the directory. Further, with hot-plugging,  the entries
44  // might decrease during the execution of this loop. So exciting from the
45  // loop on the first failure of open below is both cheaper and more
46  // reliable.
47  for (int id = 0; true; id++) {
48    std::string path = base::StringPrintf("/dev/input/event%d", id);
49    int fd = open(path.c_str(), O_RDONLY | O_NONBLOCK);
50    if (fd < 0) {
51      DLOG(ERROR) << "Cannot open '" << path << "': " << strerror(errno);
52      break;
53    }
54
55    EventDeviceInfo devinfo;
56    if (!devinfo.Initialize(fd)) {
57      DLOG(ERROR) << "failed to get device information for " << path;
58      close(fd);
59      continue;
60    }
61
62    if (IsTouchPad(devinfo)) {
63      LOG(WARNING) << "touchpad device not supported: " << path;
64      close(fd);
65      continue;
66    }
67
68    scoped_ptr<EventConverterOzone> converter;
69    // TODO(rjkroege) Add more device types. Support hot-plugging.
70    if (IsTouchScreen(devinfo))
71      converter.reset(new TouchEventConverterEvdev(fd, id));
72    else if (devinfo.HasEventType(EV_KEY))
73      converter.reset(new KeyEventConverterEvdev(fd, id, &modifiers_));
74
75    if (converter) {
76      AddEventConverter(fd, converter.Pass());
77    } else {
78      close(fd);
79    }
80  }
81}
82
83}  // namespace ui
84