Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/events/ozone/evdev/tablet_event_converter_evdev.h" | 5 #include "ui/events/ozone/evdev/tablet_event_converter_evdev.h" |
| 6 | 6 |
| 7 #include <errno.h> | 7 #include <errno.h> |
| 8 #include <linux/input.h> | 8 #include <linux/input.h> |
| 9 | 9 |
| 10 #include "base/message_loop/message_loop.h" | 10 #include "base/message_loop/message_loop.h" |
| 11 #include "base/time/time.h" | |
| 11 #include "ui/events/event.h" | 12 #include "ui/events/event.h" |
| 12 | 13 |
| 13 namespace ui { | 14 namespace ui { |
| 14 | 15 |
| 15 TabletEventConverterEvdev::TabletEventConverterEvdev( | 16 TabletEventConverterEvdev::TabletEventConverterEvdev( |
| 16 int fd, | 17 int fd, |
| 17 base::FilePath path, | 18 base::FilePath path, |
| 18 int id, | 19 int id, |
| 19 InputDeviceType type, | 20 InputDeviceType type, |
| 20 EventModifiersEvdev* modifiers, | 21 EventModifiersEvdev* modifiers, |
| 21 CursorDelegateEvdev* cursor, | 22 CursorDelegateEvdev* cursor, |
| 22 const EventDeviceInfo& info, | 23 const EventDeviceInfo& info, |
| 23 const EventDispatchCallback& callback) | 24 const EventDispatchCallback& callback) |
| 24 : EventConverterEvdev(fd, path, id, type), | 25 : EventConverterEvdev(fd, path, id, type), |
| 25 cursor_(cursor), | 26 cursor_(cursor), |
| 26 modifiers_(modifiers), | 27 modifiers_(modifiers), |
| 27 callback_(callback), | 28 callback_(callback), |
| 28 stylus_(0), | 29 stylus_(0), |
| 29 abs_value_dirty_(false) { | 30 abs_value_dirty_(false), |
| 31 on_screen_stylus_(false) { | |
| 30 x_abs_min_ = info.GetAbsMinimum(ABS_X); | 32 x_abs_min_ = info.GetAbsMinimum(ABS_X); |
| 31 x_abs_range_ = info.GetAbsMaximum(ABS_X) - x_abs_min_ + 1; | 33 x_abs_range_ = info.GetAbsMaximum(ABS_X) - x_abs_min_ + 1; |
| 32 y_abs_min_ = info.GetAbsMinimum(ABS_Y); | 34 y_abs_min_ = info.GetAbsMinimum(ABS_Y); |
| 33 y_abs_range_ = info.GetAbsMaximum(ABS_Y) - y_abs_min_ + 1; | 35 y_abs_range_ = info.GetAbsMaximum(ABS_Y) - y_abs_min_ + 1; |
| 36 pressure_min_ = info.GetAbsMinimum(ABS_PRESSURE); | |
| 37 pressure_range_ = info.GetAbsMaximum(ABS_PRESSURE) - pressure_min_ + 1; | |
| 38 on_screen_stylus_ = !info.HasProp(INPUT_PROP_POINTER); | |
| 34 } | 39 } |
| 35 | 40 |
| 36 TabletEventConverterEvdev::~TabletEventConverterEvdev() { | 41 TabletEventConverterEvdev::~TabletEventConverterEvdev() { |
| 37 Stop(); | 42 Stop(); |
| 38 close(fd_); | 43 close(fd_); |
| 39 } | 44 } |
| 40 | 45 |
| 41 void TabletEventConverterEvdev::OnFileCanReadWithoutBlocking(int fd) { | 46 void TabletEventConverterEvdev::OnFileCanReadWithoutBlocking(int fd) { |
| 42 input_event inputs[4]; | 47 input_event inputs[4]; |
| 43 ssize_t read_size = read(fd, inputs, sizeof(inputs)); | 48 ssize_t read_size = read(fd, inputs, sizeof(inputs)); |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 62 for (int i = 0; i < count; ++i) { | 67 for (int i = 0; i < count; ++i) { |
| 63 const input_event& input = inputs[i]; | 68 const input_event& input = inputs[i]; |
| 64 switch (input.type) { | 69 switch (input.type) { |
| 65 case EV_KEY: | 70 case EV_KEY: |
| 66 ConvertKeyEvent(input); | 71 ConvertKeyEvent(input); |
| 67 break; | 72 break; |
| 68 case EV_ABS: | 73 case EV_ABS: |
| 69 ConvertAbsEvent(input); | 74 ConvertAbsEvent(input); |
| 70 break; | 75 break; |
| 71 case EV_SYN: | 76 case EV_SYN: |
| 72 FlushEvents(); | 77 FlushEvents(input); |
| 73 break; | 78 break; |
| 74 } | 79 } |
| 75 } | 80 } |
| 76 } | 81 } |
| 77 | 82 |
| 78 void TabletEventConverterEvdev::ConvertKeyEvent(const input_event& input) { | 83 void TabletEventConverterEvdev::ConvertKeyEvent(const input_event& input) { |
| 79 // Only handle other events if we have a stylus in proximity | 84 // Only handle other events if we have a stylus in proximity |
| 80 if (input.code >= BTN_TOOL_PEN && input.code <= BTN_TOOL_LENS) { | 85 if (input.code >= BTN_TOOL_PEN && input.code <= BTN_TOOL_LENS) { |
| 81 if (input.value == 1) | 86 if (input.value == 1) |
| 82 stylus_ = input.code; | 87 stylus_ = input.code; |
| 83 else if (input.value == 0) | 88 else if (input.value == 0) |
| 84 stylus_ = 0; | 89 stylus_ = 0; |
| 85 else | 90 else |
| 86 LOG(WARNING) << "Unexpected value: " << input.value | 91 LOG(WARNING) << "Unexpected value: " << input.value |
| 87 << " for code: " << input.code; | 92 << " for code: " << input.code; |
| 88 } | 93 } |
| 89 | 94 |
| 90 if (input.code >= BTN_TOUCH && input.code <= BTN_STYLUS2) { | 95 if (input.code >= BTN_TOUCH && input.code <= BTN_STYLUS2) { |
| 91 DispatchMouseButton(input); | 96 if (input.code == BTN_TOUCH && on_screen_stylus_) { |
| 92 return; | 97 DispatchTouch(input); |
| 98 } else { | |
| 99 DispatchMouseButton(input); | |
| 100 } | |
| 93 } | 101 } |
| 94 } | 102 } |
| 95 | 103 |
| 96 void TabletEventConverterEvdev::ConvertAbsEvent(const input_event& input) { | 104 void TabletEventConverterEvdev::ConvertAbsEvent(const input_event& input) { |
| 97 if (!cursor_) | 105 if (!cursor_) |
| 98 return; | 106 return; |
| 99 | 107 |
| 100 switch (input.code) { | 108 switch (input.code) { |
| 101 case ABS_X: | 109 case ABS_X: |
| 102 x_abs_location_ = input.value; | 110 x_abs_location_ = input.value; |
| 103 abs_value_dirty_ = true; | 111 abs_value_dirty_ = true; |
| 104 break; | 112 break; |
| 105 case ABS_Y: | 113 case ABS_Y: |
| 106 y_abs_location_ = input.value; | 114 y_abs_location_ = input.value; |
| 107 abs_value_dirty_ = true; | 115 abs_value_dirty_ = true; |
| 108 break; | 116 break; |
| 117 case ABS_PRESSURE: | |
| 118 pressure_ = input.value; | |
| 119 break; | |
| 109 } | 120 } |
| 110 } | 121 } |
| 111 | 122 |
| 112 void TabletEventConverterEvdev::UpdateCursor() { | 123 void TabletEventConverterEvdev::UpdateCursor() { |
| 113 gfx::Rect display_bounds = cursor_->GetCursorDisplayBounds(); | 124 gfx::Rect display_bounds = cursor_->GetCursorDisplayBounds(); |
| 114 | 125 |
| 115 int x = | 126 int x = |
| 116 ((x_abs_location_ - x_abs_min_) * display_bounds.width()) / x_abs_range_; | 127 ((x_abs_location_ - x_abs_min_) * display_bounds.width()) / x_abs_range_; |
| 117 int y = | 128 int y = |
| 118 ((y_abs_location_ - y_abs_min_) * display_bounds.height()) / y_abs_range_; | 129 ((y_abs_location_ - y_abs_min_) * display_bounds.height()) / y_abs_range_; |
| 119 | 130 |
| 120 x += display_bounds.x(); | 131 x += display_bounds.x(); |
| 121 y += display_bounds.y(); | 132 y += display_bounds.y(); |
| 122 | 133 |
| 123 cursor_->MoveCursorTo(gfx::PointF(x, y)); | 134 cursor_->MoveCursorTo(gfx::PointF(x, y)); |
| 124 } | 135 } |
| 125 | 136 |
| 137 void TabletEventConverterEvdev::DispatchTouch(const input_event& input) { | |
| 138 if (abs_value_dirty_) { | |
| 139 UpdateCursor(); | |
| 140 abs_value_dirty_ = false; | |
| 141 } | |
| 142 | |
| 143 // Start making motion events touch motion rather than mouse | |
| 144 emit_touch_ = input.value; | |
| 145 | |
| 146 base::TimeDelta delta = base::TimeDelta::FromMicroseconds( | |
| 147 input.time.tv_sec * 1000000 + input.time.tv_usec); | |
| 148 scoped_ptr<TouchEvent> touch_event(new TouchEvent( | |
| 149 input.value ? ET_TOUCH_PRESSED : ET_TOUCH_RELEASED, | |
| 150 cursor_->GetLocation(), | |
| 151 /* flags */ 0, | |
| 152 /* touch_id */ 1, | |
| 153 /* delta */ delta, | |
| 154 /* radius_x */ 1.0, | |
| 155 /* radius_y */ 1.0, | |
| 156 /* angle */ 0., | |
| 157 /* force */ (float)(pressure_ - pressure_min_) / pressure_range_)); | |
| 158 touch_event->set_source_device_id(id_); | |
| 159 callback_.Run(touch_event.Pass()); | |
| 160 } | |
| 161 | |
| 126 void TabletEventConverterEvdev::DispatchMouseButton(const input_event& input) { | 162 void TabletEventConverterEvdev::DispatchMouseButton(const input_event& input) { |
| 127 if (!cursor_) | 163 if (!cursor_) |
| 128 return; | 164 return; |
| 129 | 165 |
| 130 unsigned int modifier; | 166 unsigned int modifier; |
| 131 // These are the same as X11 behaviour | 167 // These are the same as X11 behaviour |
| 132 if (input.code == BTN_TOUCH) | 168 if (input.code == BTN_TOUCH) |
| 133 modifier = EVDEV_MODIFIER_LEFT_MOUSE_BUTTON; | 169 modifier = EVDEV_MODIFIER_LEFT_MOUSE_BUTTON; |
| 134 else if (input.code == BTN_STYLUS2) | 170 else if (input.code == BTN_STYLUS2) |
| 135 modifier = EVDEV_MODIFIER_RIGHT_MOUSE_BUTTON; | 171 modifier = EVDEV_MODIFIER_RIGHT_MOUSE_BUTTON; |
| 136 else if (input.code == BTN_STYLUS) | 172 else if (input.code == BTN_STYLUS) |
| 137 modifier = EVDEV_MODIFIER_MIDDLE_MOUSE_BUTTON; | 173 modifier = EVDEV_MODIFIER_MIDDLE_MOUSE_BUTTON; |
| 138 else | 174 else |
| 139 return; | 175 return; |
| 140 | 176 |
| 141 if (abs_value_dirty_) { | 177 if (abs_value_dirty_) { |
| 142 UpdateCursor(); | 178 UpdateCursor(); |
| 143 abs_value_dirty_ = false; | 179 abs_value_dirty_ = false; |
| 144 } | 180 } |
| 145 | 181 |
| 146 int flag = modifiers_->GetEventFlagFromModifier(modifier); | 182 int flag = modifiers_->GetEventFlagFromModifier(modifier); |
| 147 modifiers_->UpdateModifier(modifier, input.value); | 183 modifiers_->UpdateModifier(modifier, input.value); |
| 148 callback_.Run(make_scoped_ptr( | 184 callback_.Run(make_scoped_ptr( |
| 149 new MouseEvent(input.value ? ET_MOUSE_PRESSED : ET_MOUSE_RELEASED, | 185 new MouseEvent(input.value ? ET_MOUSE_PRESSED : ET_MOUSE_RELEASED, |
| 150 cursor_->GetLocation(), cursor_->GetLocation(), | 186 cursor_->GetLocation(), cursor_->GetLocation(), |
| 151 modifiers_->GetModifierFlags() | flag, flag))); | 187 modifiers_->GetModifierFlags() | flag, flag))); |
| 152 } | 188 } |
| 153 | 189 |
| 154 void TabletEventConverterEvdev::FlushEvents() { | 190 void TabletEventConverterEvdev::FlushEvents(const input_event& input) { |
| 155 if (!cursor_) | 191 if (!cursor_) |
| 156 return; | 192 return; |
| 157 | 193 |
| 158 // Prevent propagation of invalid data on stylus lift off | 194 // Prevent propagation of invalid data on stylus lift off |
| 159 if (stylus_ == 0) { | 195 if (stylus_ == 0) { |
| 160 abs_value_dirty_ = false; | 196 abs_value_dirty_ = false; |
| 161 return; | 197 return; |
| 162 } | 198 } |
| 163 | 199 |
| 164 if (!abs_value_dirty_) | 200 if (!abs_value_dirty_) |
| 165 return; | 201 return; |
| 166 | 202 |
| 167 UpdateCursor(); | 203 UpdateCursor(); |
| 168 | 204 |
| 205 if (emit_touch_) { | |
| 206 base::TimeDelta delta = base::TimeDelta::FromMicroseconds( | |
| 207 input.time.tv_sec * 1000000 + input.time.tv_usec); | |
| 208 scoped_ptr<TouchEvent> touch_event(new TouchEvent( | |
| 209 ET_TOUCH_MOVED, | |
| 210 cursor_->GetLocation(), | |
| 211 /* flags */ 0, | |
| 212 /* touch_id */ 1, | |
|
Rick Byers
2015/01/19 20:44:20
What if there is both real touchscreen and stylus
| |
| 213 /* delta */ delta, | |
| 214 /* radius_x */ 1.0, | |
| 215 /* radius_y */ 1.0, | |
| 216 /* angle */ 0., | |
| 217 /* force */ (float)(pressure_ - pressure_min_) / pressure_range_)); | |
| 218 touch_event->set_source_device_id(id_); | |
| 219 callback_.Run(touch_event.Pass()); | |
| 220 } else { | |
| 169 callback_.Run(make_scoped_ptr( | 221 callback_.Run(make_scoped_ptr( |
| 170 new MouseEvent(ui::ET_MOUSE_MOVED, cursor_->GetLocation(), | 222 new MouseEvent(ui::ET_MOUSE_MOVED, cursor_->GetLocation(), |
| 171 cursor_->GetLocation(), modifiers_->GetModifierFlags(), | 223 cursor_->GetLocation(), modifiers_->GetModifierFlags(), |
| 172 /* changed_button_flags */ 0))); | 224 /* changed_button_flags */ 0))); |
| 173 | 225 } |
| 174 abs_value_dirty_ = false; | 226 abs_value_dirty_ = false; |
| 175 } | 227 } |
| 176 | 228 |
| 177 } // namespace ui | 229 } // namespace ui |
| OLD | NEW |