summaryrefslogtreecommitdiff
path: root/chromium/ui/base/ozone/event_factory_ozone.cc
blob: afeff2b7a1997a76129bd51f401574a7104b3406 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/base/ozone/event_factory_ozone.h"

#include <fcntl.h>
#include <linux/input.h>
#include <poll.h>
#include <unistd.h>

#include "base/message_loop/message_pump_ozone.h"
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "ui/base/ozone/evdev/key_event_converter_ozone.h"
#include "ui/base/ozone/evdev/touch_event_converter_ozone.h"
#include "ui/base/ozone/event_factory_delegate_ozone.h"

namespace ui {

// static
EventFactoryDelegateOzone* EventFactoryOzone::delegate_ = NULL;

EventFactoryOzone::EventFactoryOzone() {}

EventFactoryOzone::~EventFactoryOzone() {
  // Always delete watchers before converters to prevent a possible race.
  STLDeleteValues<std::map<int, FDWatcher> >(&watchers_);
  STLDeleteValues<std::map<int, Converter> >(&converters_);
}

void EventFactoryOzone::CreateStartupEventConverters() {
  if (delegate_) {
    delegate_->CreateStartupEventConverters(this);
    return;
  }

  // If there is no |delegate_| set, read events from /dev/input/*

  // The number of devices in the directory is unknown without reading
  // the contents of the directory. Further, with hot-plugging,  the entries
  // might decrease during the execution of this loop. So exciting from the
  // loop on the first failure of open below is both cheaper and more
  // reliable.
  for (int id = 0; true; id++) {
    std::string path = base::StringPrintf("/dev/input/event%d", id);
    int fd = open(path.c_str(), O_RDONLY | O_NONBLOCK);
    if (fd < 0)
      break;
    size_t evtype = 0;
    COMPILE_ASSERT(sizeof(evtype) * 8 >= EV_MAX, evtype_wide_enough);
    if (ioctl(fd, EVIOCGBIT(0, sizeof(evtype)), &evtype) == -1) {
      DLOG(ERROR) << "failed ioctl EVIOCGBIT 0" << path;
      close(fd);
      continue;
    }

    scoped_ptr<EventConverterOzone> converter;
    // TODO(rjkroege) Add more device types. Support hot-plugging.
    if (evtype & (1 << EV_ABS))
      converter.reset(new TouchEventConverterOzone(fd, id));
    else if (evtype & (1 << EV_KEY))
      converter.reset(new KeyEventConverterOzone());

    if (converter) {
      AddEventConverter(fd, converter.Pass());
    } else {
      close(fd);
    }
  }
}

void EventFactoryOzone::SetEventFactoryDelegateOzone(
    EventFactoryDelegateOzone* delegate) {
  // It should be unnecessary to call this more than once.
  DCHECK(!delegate_);
  delegate_ = delegate;
}

void EventFactoryOzone::AddEventConverter(
    int fd,
    scoped_ptr<EventConverterOzone> converter) {
  CHECK(watchers_.count(fd) == 0 && converters_.count(fd) == 0);

  FDWatcher watcher = new base::MessagePumpLibevent::FileDescriptorWatcher();

  base::MessagePumpOzone::Current()->WatchFileDescriptor(
      fd,
      true,
      base::MessagePumpLibevent::WATCH_READ,
      watcher,
      converter.get());

  converters_[fd] = converter.release();
  watchers_[fd] = watcher;
}

void EventFactoryOzone::RemoveEventConverter(int fd) {
  // Always delete watchers before converters to prevent a possible race.
  delete watchers_[fd];
  delete converters_[fd];
  watchers_.erase(fd);
  converters_.erase(fd);
}

}  // namespace ui