OLD | NEW |
(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/tablet_event_converter_evdev.h" |
| 6 |
| 7 #include <errno.h> |
| 8 #include <linux/input.h> |
| 9 |
| 10 #include "base/message_loop/message_loop.h" |
| 11 #include "ui/events/event.h" |
| 12 |
| 13 namespace ui { |
| 14 |
| 15 TabletEventConverterEvdev::TabletEventConverterEvdev( |
| 16 int fd, |
| 17 base::FilePath path, |
| 18 int id, |
| 19 EventModifiersEvdev* modifiers, |
| 20 CursorDelegateEvdev* cursor, |
| 21 const EventDeviceInfo& info, |
| 22 const EventDispatchCallback& callback) |
| 23 : EventConverterEvdev(fd, path, id), |
| 24 cursor_(cursor), |
| 25 modifiers_(modifiers), |
| 26 callback_(callback), |
| 27 stylus_(0), |
| 28 abs_value_dirty_(false) { |
| 29 x_abs_min_ = info.GetAbsMinimum(ABS_X); |
| 30 x_abs_range_ = info.GetAbsMaximum(ABS_X) - x_abs_min_ + 1; |
| 31 y_abs_min_ = info.GetAbsMinimum(ABS_Y); |
| 32 y_abs_range_ = info.GetAbsMaximum(ABS_Y) - y_abs_min_ + 1; |
| 33 } |
| 34 |
| 35 TabletEventConverterEvdev::~TabletEventConverterEvdev() { |
| 36 Stop(); |
| 37 close(fd_); |
| 38 } |
| 39 |
| 40 void TabletEventConverterEvdev::OnFileCanReadWithoutBlocking(int fd) { |
| 41 input_event inputs[4]; |
| 42 ssize_t read_size = read(fd, inputs, sizeof(inputs)); |
| 43 if (read_size < 0) { |
| 44 if (errno == EINTR || errno == EAGAIN) |
| 45 return; |
| 46 if (errno != ENODEV) |
| 47 PLOG(ERROR) << "error reading device " << path_.value(); |
| 48 Stop(); |
| 49 return; |
| 50 } |
| 51 |
| 52 DCHECK_EQ(read_size % sizeof(*inputs), 0u); |
| 53 ProcessEvents(inputs, read_size / sizeof(*inputs)); |
| 54 } |
| 55 |
| 56 void TabletEventConverterEvdev::ProcessEvents(const input_event* inputs, |
| 57 int count) { |
| 58 for (int i = 0; i < count; ++i) { |
| 59 const input_event& input = inputs[i]; |
| 60 switch (input.type) { |
| 61 case EV_KEY: |
| 62 ConvertKeyEvent(input); |
| 63 break; |
| 64 case EV_ABS: |
| 65 ConvertAbsEvent(input); |
| 66 break; |
| 67 case EV_SYN: |
| 68 FlushEvents(); |
| 69 break; |
| 70 } |
| 71 } |
| 72 } |
| 73 |
| 74 void TabletEventConverterEvdev::ConvertKeyEvent(const input_event& input) { |
| 75 // Only handle other events if we have a stylus in proximity |
| 76 if (input.code >= BTN_TOOL_PEN && input.code <= BTN_TOOL_LENS) { |
| 77 if (input.value == 1) |
| 78 stylus_ = input.code; |
| 79 else if (input.value == 0) |
| 80 stylus_ = 0; |
| 81 else |
| 82 LOG(WARNING) << "Unexpected value: " << input.value |
| 83 << " for code: " << input.code; |
| 84 } |
| 85 |
| 86 if (input.code >= BTN_TOUCH && input.code <= BTN_STYLUS2) { |
| 87 DispatchMouseButton(input); |
| 88 return; |
| 89 } |
| 90 } |
| 91 |
| 92 void TabletEventConverterEvdev::ConvertAbsEvent(const input_event& input) { |
| 93 if (!cursor_) |
| 94 return; |
| 95 |
| 96 switch (input.code) { |
| 97 case ABS_X: |
| 98 x_abs_location_ = input.value; |
| 99 abs_value_dirty_ = true; |
| 100 break; |
| 101 case ABS_Y: |
| 102 y_abs_location_ = input.value; |
| 103 abs_value_dirty_ = true; |
| 104 break; |
| 105 } |
| 106 } |
| 107 |
| 108 void TabletEventConverterEvdev::UpdateCursor() { |
| 109 int width = cursor_->GetCursorDisplayBounds().width(); |
| 110 int height = cursor_->GetCursorDisplayBounds().height(); |
| 111 int x = ((x_abs_location_ - x_abs_min_) * width) / x_abs_range_; |
| 112 int y = ((y_abs_location_ - y_abs_min_) * height) / y_abs_range_; |
| 113 |
| 114 cursor_->MoveCursorTo(gfx::PointF(x, y)); |
| 115 } |
| 116 |
| 117 void TabletEventConverterEvdev::DispatchMouseButton(const input_event& input) { |
| 118 if (!cursor_) |
| 119 return; |
| 120 |
| 121 unsigned int modifier; |
| 122 // These are the same as X11 behaviour |
| 123 if (input.code == BTN_TOUCH) |
| 124 modifier = EVDEV_MODIFIER_LEFT_MOUSE_BUTTON; |
| 125 else if (input.code == BTN_STYLUS2) |
| 126 modifier = EVDEV_MODIFIER_RIGHT_MOUSE_BUTTON; |
| 127 else if (input.code == BTN_STYLUS) |
| 128 modifier = EVDEV_MODIFIER_MIDDLE_MOUSE_BUTTON; |
| 129 else |
| 130 return; |
| 131 |
| 132 if (abs_value_dirty_) { |
| 133 UpdateCursor(); |
| 134 abs_value_dirty_ = false; |
| 135 } |
| 136 |
| 137 int flag = modifiers_->GetEventFlagFromModifier(modifier); |
| 138 modifiers_->UpdateModifier(modifier, input.value); |
| 139 callback_.Run(make_scoped_ptr(new MouseEvent( |
| 140 input.value ? ET_MOUSE_PRESSED : ET_MOUSE_RELEASED, cursor_->location(), |
| 141 cursor_->location(), modifiers_->GetModifierFlags() | flag, flag))); |
| 142 } |
| 143 |
| 144 void TabletEventConverterEvdev::FlushEvents() { |
| 145 if (!cursor_) |
| 146 return; |
| 147 |
| 148 // Prevent propagation of invalid data on stylus lift off |
| 149 if (stylus_ == 0) { |
| 150 abs_value_dirty_ = false; |
| 151 return; |
| 152 } |
| 153 |
| 154 if (!abs_value_dirty_) |
| 155 return; |
| 156 |
| 157 UpdateCursor(); |
| 158 |
| 159 callback_.Run(make_scoped_ptr( |
| 160 new MouseEvent(ui::ET_MOUSE_MOVED, cursor_->location(), |
| 161 cursor_->location(), modifiers_->GetModifierFlags(), |
| 162 /* changed_button_flags */ 0))); |
| 163 |
| 164 abs_value_dirty_ = false; |
| 165 } |
| 166 |
| 167 } // namespace ui |
OLD | NEW |