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/chromeos/touch_exploration_controller.h" | 5 #include "ui/chromeos/touch_exploration_controller.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "ui/aura/client/cursor_client.h" | 8 #include "ui/aura/client/cursor_client.h" |
9 #include "ui/aura/window.h" | 9 #include "ui/aura/window.h" |
| 10 #include "ui/aura/window_event_dispatcher.h" |
10 #include "ui/aura/window_tree_host.h" | 11 #include "ui/aura/window_tree_host.h" |
11 #include "ui/events/event.h" | 12 #include "ui/events/event.h" |
| 13 #include "ui/events/event_processor.h" |
12 | 14 |
13 namespace ui { | 15 namespace ui { |
14 | 16 |
| 17 namespace { |
| 18 // The default value for initial_touch_id_passthrough_mapping_ used |
| 19 // when the user has not yet released any fingers yet, so there's no |
| 20 // touch id remapping yet. |
| 21 const int kTouchIdUnassigned = 0; |
| 22 |
| 23 // The value for initial_touch_id_passthrough_mapping_ if the user has |
| 24 // released the first finger but some other fingers are held down. In this |
| 25 // state we don't do any touch id remapping, but we distinguish it from the |
| 26 // kTouchIdUnassigned state because we don't want to assign |
| 27 // initial_touch_id_passthrough_mapping_ a touch id anymore, |
| 28 // until all fingers are released. |
| 29 const int kTouchIdNone = -1; |
| 30 } // namespace |
| 31 |
15 TouchExplorationController::TouchExplorationController( | 32 TouchExplorationController::TouchExplorationController( |
16 aura::Window* root_window) | 33 aura::Window* root_window) |
17 : root_window_(root_window) { | 34 : root_window_(root_window), |
| 35 initial_touch_id_passthrough_mapping_(kTouchIdUnassigned), |
| 36 state_(NO_FINGERS_DOWN), |
| 37 event_handler_for_testing_(NULL) { |
18 CHECK(root_window); | 38 CHECK(root_window); |
19 root_window->GetHost()->GetEventSource()->AddEventRewriter(this); | 39 root_window->GetHost()->GetEventSource()->AddEventRewriter(this); |
20 } | 40 } |
21 | 41 |
22 TouchExplorationController::~TouchExplorationController() { | 42 TouchExplorationController::~TouchExplorationController() { |
23 root_window_->GetHost()->GetEventSource()->RemoveEventRewriter(this); | 43 root_window_->GetHost()->GetEventSource()->RemoveEventRewriter(this); |
24 } | 44 } |
25 | 45 |
| 46 void TouchExplorationController::CallTapTimerNowForTesting() { |
| 47 DCHECK(tap_timer_.IsRunning()); |
| 48 tap_timer_.Stop(); |
| 49 OnTapTimerFired(); |
| 50 } |
| 51 |
| 52 void TouchExplorationController::SetEventHandlerForTesting( |
| 53 ui::EventHandler* event_handler_for_testing) { |
| 54 event_handler_for_testing_ = event_handler_for_testing; |
| 55 } |
| 56 |
| 57 bool TouchExplorationController::IsInNoFingersDownStateForTesting() const { |
| 58 return state_ == NO_FINGERS_DOWN; |
| 59 } |
| 60 |
26 ui::EventRewriteStatus TouchExplorationController::RewriteEvent( | 61 ui::EventRewriteStatus TouchExplorationController::RewriteEvent( |
27 const ui::Event& event, | 62 const ui::Event& event, |
28 scoped_ptr<ui::Event>* rewritten_event) { | 63 scoped_ptr<ui::Event>* rewritten_event) { |
29 if (!event.IsTouchEvent()) | 64 if (!event.IsTouchEvent()) |
30 return ui::EVENT_REWRITE_CONTINUE; | 65 return ui::EVENT_REWRITE_CONTINUE; |
31 | |
32 const ui::TouchEvent& touch_event = | 66 const ui::TouchEvent& touch_event = |
33 static_cast<const ui::TouchEvent&>(event); | 67 static_cast<const ui::TouchEvent&>(event); |
| 68 |
| 69 // If the tap timer should have fired by now but hasn't, run it now and |
| 70 // stop the timer. This is important so that behavior is consistent with |
| 71 // the timestamps of the events, and not dependent on the granularity of |
| 72 // the timer. |
| 73 if (tap_timer_.IsRunning() && |
| 74 touch_event.time_stamp() - initial_press_->time_stamp() > |
| 75 gesture_detector_config_.double_tap_timeout) { |
| 76 tap_timer_.Stop(); |
| 77 OnTapTimerFired(); |
| 78 // Note: this may change the state. We should now continue and process |
| 79 // this event under this new state. |
| 80 } |
| 81 |
34 const ui::EventType type = touch_event.type(); | 82 const ui::EventType type = touch_event.type(); |
35 const gfx::PointF& location = touch_event.location_f(); | 83 const gfx::PointF& location = touch_event.location_f(); |
36 const int touch_id = touch_event.touch_id(); | 84 const int touch_id = touch_event.touch_id(); |
37 const int flags = touch_event.flags(); | 85 |
38 | 86 // Always update touch ids and touch locations, so we can use those |
39 if (type == ui::ET_TOUCH_PRESSED) { | 87 // no matter what state we're in. |
40 touch_ids_.push_back(touch_id); | 88 if (type == ui::ET_TOUCH_PRESSED) { |
| 89 current_touch_ids_.push_back(touch_id); |
41 touch_locations_.insert(std::pair<int, gfx::PointF>(touch_id, location)); | 90 touch_locations_.insert(std::pair<int, gfx::PointF>(touch_id, location)); |
42 // If this is the first and only finger touching - rewrite the touch as a | 91 } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) { |
43 // mouse move. Otherwise let the it go through as is. | 92 std::vector<int>::iterator it = std::find( |
44 if (touch_ids_.size() == 1) { | 93 current_touch_ids_.begin(), current_touch_ids_.end(), touch_id); |
45 *rewritten_event = CreateMouseMoveEvent(location, flags); | 94 |
| 95 // Can happen if touch exploration is enabled while fingers were down. |
| 96 if (it == current_touch_ids_.end()) |
| 97 return ui::EVENT_REWRITE_CONTINUE; |
| 98 |
| 99 current_touch_ids_.erase(it); |
| 100 touch_locations_.erase(touch_id); |
| 101 } else if (type == ui::ET_TOUCH_MOVED) { |
| 102 std::vector<int>::iterator it = std::find( |
| 103 current_touch_ids_.begin(), current_touch_ids_.end(), touch_id); |
| 104 |
| 105 // Can happen if touch exploration is enabled while fingers were down. |
| 106 if (it == current_touch_ids_.end()) |
| 107 return ui::EVENT_REWRITE_CONTINUE; |
| 108 |
| 109 touch_locations_[*it] = location; |
| 110 } |
| 111 |
| 112 // The rest of the processing depends on what state we're in. |
| 113 switch(state_) { |
| 114 case NO_FINGERS_DOWN: |
| 115 return InNoFingersDown(touch_event, rewritten_event); |
| 116 case SINGLE_TAP_PRESSED: |
| 117 return InSingleTapPressed(touch_event, rewritten_event); |
| 118 case SINGLE_TAP_RELEASED: |
| 119 return InSingleTapReleased(touch_event, rewritten_event); |
| 120 case DOUBLE_TAP_PRESSED: |
| 121 return InDoubleTapPressed(touch_event, rewritten_event); |
| 122 case TOUCH_EXPLORATION: |
| 123 return InTouchExploration(touch_event, rewritten_event); |
| 124 case PASSTHROUGH_MINUS_ONE: |
| 125 return InPassthroughMinusOne(touch_event, rewritten_event); |
| 126 } |
| 127 |
| 128 NOTREACHED(); |
| 129 return ui::EVENT_REWRITE_CONTINUE; |
| 130 } |
| 131 |
| 132 ui::EventRewriteStatus TouchExplorationController::NextDispatchEvent( |
| 133 const ui::Event& last_event, scoped_ptr<ui::Event>* new_event) { |
| 134 NOTREACHED(); |
| 135 return ui::EVENT_REWRITE_CONTINUE; |
| 136 } |
| 137 |
| 138 ui::EventRewriteStatus TouchExplorationController::InNoFingersDown( |
| 139 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event) { |
| 140 const ui::EventType type = event.type(); |
| 141 if (type == ui::ET_TOUCH_PRESSED) { |
| 142 initial_press_.reset(new TouchEvent(event)); |
| 143 tap_timer_.Start(FROM_HERE, |
| 144 gesture_detector_config_.double_tap_timeout, |
| 145 this, |
| 146 &TouchExplorationController::OnTapTimerFired); |
| 147 state_ = SINGLE_TAP_PRESSED; |
| 148 return ui::EVENT_REWRITE_DISCARD; |
| 149 } |
| 150 |
| 151 NOTREACHED(); |
| 152 return ui::EVENT_REWRITE_CONTINUE; |
| 153 } |
| 154 |
| 155 ui::EventRewriteStatus TouchExplorationController::InSingleTapPressed( |
| 156 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event) { |
| 157 const ui::EventType type = event.type(); |
| 158 |
| 159 if (type == ui::ET_TOUCH_PRESSED) { |
| 160 // Adding a second finger within the timeout period switches to |
| 161 // passthrough. |
| 162 state_ = PASSTHROUGH_MINUS_ONE; |
| 163 return InPassthroughMinusOne(event, rewritten_event); |
| 164 } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) { |
| 165 DCHECK_EQ(0U, current_touch_ids_.size()); |
| 166 state_ = SINGLE_TAP_RELEASED; |
| 167 return EVENT_REWRITE_DISCARD; |
| 168 } else if (type == ui::ET_TOUCH_MOVED) { |
| 169 // If the user moves far enough from the initial touch location (outside |
| 170 // the "slop" region, jump to the touch exploration mode early. |
| 171 // TODO(evy, lisayin): Add gesture recognition here instead - |
| 172 // we should probably jump to gesture mode here if the velocity is |
| 173 // high enough, and touch exploration if the velocity is lower. |
| 174 float delta = (event.location() - initial_press_->location()).Length(); |
| 175 if (delta > gesture_detector_config_.touch_slop) { |
46 EnterTouchToMouseMode(); | 176 EnterTouchToMouseMode(); |
47 return ui::EVENT_REWRITE_REWRITTEN; | 177 state_ = TOUCH_EXPLORATION; |
| 178 return InTouchExploration(event, rewritten_event); |
48 } | 179 } |
49 return ui::EVENT_REWRITE_CONTINUE; | 180 |
50 } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) { | 181 return EVENT_REWRITE_DISCARD; |
51 std::vector<int>::iterator it = | 182 } |
52 std::find(touch_ids_.begin(), touch_ids_.end(), touch_id); | 183 NOTREACHED() << "Unexpected event type received."; |
53 // We may fail to find the finger if the exploration mode was turned on | 184 return ui::EVENT_REWRITE_CONTINUE; |
54 // while the user had some fingers touching the screen. We simply ignore | 185 } |
55 // those fingers for the purposes of event transformation. | 186 |
56 if (it == touch_ids_.end()) | 187 ui::EventRewriteStatus TouchExplorationController::InSingleTapReleased( |
57 return ui::EVENT_REWRITE_CONTINUE; | 188 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event) { |
58 const bool first_finger_released = it == touch_ids_.begin(); | 189 const ui::EventType type = event.type(); |
59 touch_ids_.erase(it); | 190 if (type == ui::ET_TOUCH_PRESSED) { |
60 int num_erased = touch_locations_.erase(touch_id); | 191 // This is the second tap in a double-tap (or double tap-hold). |
61 DCHECK_EQ(num_erased, 1); | 192 // Rewrite at location of last touch exploration. |
62 const int num_fingers_remaining = touch_ids_.size(); | 193 ui::TouchEvent* rewritten_press_event = new ui::TouchEvent( |
63 | 194 ui::ET_TOUCH_PRESSED, |
64 if (num_fingers_remaining == 0) { | 195 last_touch_exploration_location_, |
65 *rewritten_event = CreateMouseMoveEvent(location, flags); | 196 event.touch_id(), |
66 return ui::EVENT_REWRITE_REWRITTEN; | 197 event.time_stamp()); |
67 } | 198 rewritten_press_event->set_flags(event.flags()); |
68 | 199 rewritten_event->reset(rewritten_press_event); |
69 // If we are left with one finger - enter the mouse move mode. | 200 state_ = DOUBLE_TAP_PRESSED; |
70 const bool enter_mouse_move_mode = num_fingers_remaining == 1; | 201 return ui::EVENT_REWRITE_REWRITTEN; |
71 | 202 } |
72 if (!enter_mouse_move_mode && !first_finger_released) { | 203 |
73 // No special handling needed. | 204 NOTREACHED(); |
74 return ui::EVENT_REWRITE_CONTINUE; | 205 return ui::EVENT_REWRITE_CONTINUE; |
75 } | 206 } |
76 | 207 |
77 // If the finger which was released was the first one, - we need to rewrite | 208 ui::EventRewriteStatus TouchExplorationController::InDoubleTapPressed( |
78 // the release event as a release of the was second / now first finger. | 209 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event) { |
79 // This is the finger which will now be getting "substracted". | 210 const ui::EventType type = event.type(); |
80 if (first_finger_released) { | 211 if (type == ui::ET_TOUCH_PRESSED) { |
81 int rewritten_release_id = touch_ids_[0]; | 212 return ui::EVENT_REWRITE_DISCARD; |
82 const gfx::PointF& rewritten_release_location = | 213 } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) { |
83 touch_locations_[rewritten_release_id]; | 214 if (current_touch_ids_.size() != 0) |
84 ui::TouchEvent* rewritten_release_event = new ui::TouchEvent( | 215 return EVENT_REWRITE_DISCARD; |
85 ui::ET_TOUCH_RELEASED, | 216 |
86 rewritten_release_location, | 217 // Rewrite at location of last touch exploration. |
87 rewritten_release_id, | 218 ui::TouchEvent* rewritten_release_event = new ui::TouchEvent( |
88 event.time_stamp()); | 219 ui::ET_TOUCH_RELEASED, |
89 rewritten_release_event->set_flags(touch_event.flags()); | 220 last_touch_exploration_location_, |
90 rewritten_event->reset(rewritten_release_event); | 221 event.touch_id(), |
91 } else if (enter_mouse_move_mode) { | 222 event.time_stamp()); |
92 // Dispatch the release event as is. | 223 rewritten_release_event->set_flags(event.flags()); |
93 // TODO(mfomitchev): We can get rid of this clause once we have | 224 rewritten_event->reset(rewritten_release_event); |
94 // EVENT_REWRITE_DISPATCH_ANOTHER working without having to set | 225 ResetToNoFingersDown(); |
95 // rewritten_event. | |
96 rewritten_event->reset(new ui::TouchEvent(touch_event)); | |
97 } | |
98 | |
99 if (enter_mouse_move_mode) { | |
100 // Since we are entering the mouse move mode - also dispatch a mouse move | |
101 // event at the location of the one remaining finger. (num_fingers == 1) | |
102 const gfx::PointF& mouse_move_location = touch_locations_[touch_ids_[0]]; | |
103 next_dispatch_event_ = | |
104 CreateMouseMoveEvent(mouse_move_location, flags).Pass(); | |
105 return ui::EVENT_REWRITE_DISPATCH_ANOTHER; | |
106 } | |
107 return ui::EVENT_REWRITE_REWRITTEN; | 226 return ui::EVENT_REWRITE_REWRITTEN; |
108 } else if (type == ui::ET_TOUCH_MOVED) { | 227 } else if (type == ui::ET_TOUCH_MOVED) { |
109 std::vector<int>::iterator it = | 228 return ui::EVENT_REWRITE_DISCARD; |
110 std::find(touch_ids_.begin(), touch_ids_.end(), touch_id); | 229 } |
111 // We may fail to find the finger if the exploration mode was turned on | 230 NOTREACHED() << "Unexpected event type received."; |
112 // while the user had some fingers touching the screen. We simply ignore | 231 return ui::EVENT_REWRITE_CONTINUE; |
113 // those fingers for the purposes of event transformation. | 232 } |
114 if (it == touch_ids_.end()) | 233 |
115 return ui::EVENT_REWRITE_CONTINUE; | 234 ui::EventRewriteStatus TouchExplorationController::InTouchExploration( |
116 touch_locations_[*it] = location; | 235 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event) { |
117 if (touch_ids_.size() == 1) { | 236 const ui::EventType type = event.type(); |
118 // Touch moves are rewritten as mouse moves when there's only one finger | 237 if (type == ui::ET_TOUCH_PRESSED) { |
119 // touching the screen. | 238 // Ignore any additional fingers when we're already in touch exploration |
120 *rewritten_event = CreateMouseMoveEvent(location, flags).Pass(); | 239 // mode. TODO(evy, lisayin): Support "split-tap" here instead. |
121 return ui::EVENT_REWRITE_REWRITTEN; | 240 return ui::EVENT_REWRITE_DISCARD; |
| 241 } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) { |
| 242 if (current_touch_ids_.size() == 0) |
| 243 ResetToNoFingersDown(); |
| 244 } else if (type != ui::ET_TOUCH_MOVED) { |
| 245 NOTREACHED() << "Unexpected event type received."; |
| 246 return ui::EVENT_REWRITE_CONTINUE; |
| 247 } |
| 248 |
| 249 // Rewrite as a mouse-move event. |
| 250 *rewritten_event = CreateMouseMoveEvent(event.location(), event.flags()); |
| 251 last_touch_exploration_location_ = event.location(); |
| 252 return ui::EVENT_REWRITE_REWRITTEN; |
| 253 } |
| 254 |
| 255 ui::EventRewriteStatus TouchExplorationController::InPassthroughMinusOne( |
| 256 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event) { |
| 257 ui::EventType type = event.type(); |
| 258 gfx::PointF location = event.location_f(); |
| 259 |
| 260 if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) { |
| 261 if (current_touch_ids_.size() == 0) |
| 262 ResetToNoFingersDown(); |
| 263 |
| 264 if (initial_touch_id_passthrough_mapping_ == kTouchIdUnassigned) { |
| 265 if (event.touch_id() == initial_press_->touch_id()) { |
| 266 initial_touch_id_passthrough_mapping_ = kTouchIdNone; |
| 267 } else { |
| 268 // If the only finger now remaining is the first finger, |
| 269 // rewrite as a move to the location of the first finger. |
| 270 initial_touch_id_passthrough_mapping_ = event.touch_id(); |
| 271 ui::TouchEvent* rewritten_passthrough_event = new ui::TouchEvent( |
| 272 ui::ET_TOUCH_MOVED, |
| 273 touch_locations_[initial_press_->touch_id()], |
| 274 initial_touch_id_passthrough_mapping_, |
| 275 event.time_stamp()); |
| 276 rewritten_passthrough_event->set_flags(event.flags()); |
| 277 rewritten_event->reset(rewritten_passthrough_event); |
| 278 return ui::EVENT_REWRITE_REWRITTEN; |
| 279 } |
122 } | 280 } |
123 if (touch_id == touch_ids_.front()) { | 281 } |
124 // Touch moves of the first finger are discarded when there's more than | 282 |
125 // one finger touching. | 283 if (event.touch_id() == initial_press_->touch_id()) { |
| 284 if (initial_touch_id_passthrough_mapping_ == kTouchIdNone || |
| 285 initial_touch_id_passthrough_mapping_ == kTouchIdUnassigned) { |
126 return ui::EVENT_REWRITE_DISCARD; | 286 return ui::EVENT_REWRITE_DISCARD; |
127 } | 287 } |
128 return ui::EVENT_REWRITE_CONTINUE; | 288 |
129 } | 289 ui::TouchEvent* rewritten_passthrough_event = new ui::TouchEvent( |
130 NOTREACHED() << "Unexpected event type received."; | 290 type, |
131 return ui::EVENT_REWRITE_CONTINUE; | 291 location, |
132 } | 292 initial_touch_id_passthrough_mapping_, |
133 | 293 event.time_stamp()); |
134 ui::EventRewriteStatus TouchExplorationController::NextDispatchEvent( | 294 rewritten_passthrough_event->set_flags(event.flags()); |
135 const ui::Event& last_event, | 295 rewritten_event->reset(rewritten_passthrough_event); |
136 scoped_ptr<ui::Event>* new_event) { | 296 return ui::EVENT_REWRITE_REWRITTEN; |
137 CHECK(next_dispatch_event_); | 297 } |
138 DCHECK(last_event.IsTouchEvent()); | 298 |
139 *new_event = next_dispatch_event_.Pass(); | 299 return ui::EVENT_REWRITE_CONTINUE; |
140 // Enter the mouse move mode if needed | 300 } |
141 if ((*new_event)->IsMouseEvent()) | 301 |
| 302 void TouchExplorationController::OnTapTimerFired() { |
| 303 if (state_ != SINGLE_TAP_RELEASED && state_ != SINGLE_TAP_PRESSED) |
| 304 return; |
| 305 |
| 306 if (state_ == SINGLE_TAP_RELEASED) { |
| 307 ResetToNoFingersDown(); |
| 308 } else { |
142 EnterTouchToMouseMode(); | 309 EnterTouchToMouseMode(); |
143 return ui::EVENT_REWRITE_REWRITTEN; | 310 state_ = TOUCH_EXPLORATION; |
| 311 } |
| 312 |
| 313 scoped_ptr<ui::Event> mouse_move = CreateMouseMoveEvent( |
| 314 initial_press_->location(), initial_press_->flags()); |
| 315 DispatchEvent(mouse_move.get()); |
| 316 last_touch_exploration_location_ = initial_press_->location(); |
| 317 } |
| 318 |
| 319 void TouchExplorationController::DispatchEvent(ui::Event* event) { |
| 320 if (event_handler_for_testing_) { |
| 321 event_handler_for_testing_->OnEvent(event); |
| 322 return; |
| 323 } |
| 324 |
| 325 ui::EventDispatchDetails result ALLOW_UNUSED = |
| 326 root_window_->GetHost()->dispatcher()->OnEventFromSource(event); |
144 } | 327 } |
145 | 328 |
146 scoped_ptr<ui::Event> TouchExplorationController::CreateMouseMoveEvent( | 329 scoped_ptr<ui::Event> TouchExplorationController::CreateMouseMoveEvent( |
147 const gfx::PointF& location, | 330 const gfx::PointF& location, |
148 int flags) { | 331 int flags) { |
149 return scoped_ptr<ui::Event>( | 332 return scoped_ptr<ui::Event>( |
150 new ui::MouseEvent( | 333 new ui::MouseEvent( |
151 ui::ET_MOUSE_MOVED, | 334 ui::ET_MOUSE_MOVED, |
152 location, | 335 location, |
153 location, | 336 location, |
154 flags | ui::EF_IS_SYNTHESIZED | ui::EF_TOUCH_ACCESSIBILITY, | 337 flags | ui::EF_IS_SYNTHESIZED | ui::EF_TOUCH_ACCESSIBILITY, |
155 0)); | 338 0)); |
156 } | 339 } |
157 | 340 |
158 void TouchExplorationController::EnterTouchToMouseMode() { | 341 void TouchExplorationController::EnterTouchToMouseMode() { |
159 aura::client::CursorClient* cursor_client = | 342 aura::client::CursorClient* cursor_client = |
160 aura::client::GetCursorClient(root_window_); | 343 aura::client::GetCursorClient(root_window_); |
161 if (cursor_client && !cursor_client->IsMouseEventsEnabled()) | 344 if (cursor_client && !cursor_client->IsMouseEventsEnabled()) |
162 cursor_client->EnableMouseEvents(); | 345 cursor_client->EnableMouseEvents(); |
163 if (cursor_client && cursor_client->IsCursorVisible()) | 346 if (cursor_client && cursor_client->IsCursorVisible()) |
164 cursor_client->HideCursor(); | 347 cursor_client->HideCursor(); |
165 } | 348 } |
166 | 349 |
| 350 void TouchExplorationController::ResetToNoFingersDown() { |
| 351 state_ = NO_FINGERS_DOWN; |
| 352 initial_touch_id_passthrough_mapping_ = kTouchIdUnassigned; |
| 353 if (tap_timer_.IsRunning()) |
| 354 tap_timer_.Stop(); |
| 355 } |
| 356 |
167 } // namespace ui | 357 } // namespace ui |
OLD | NEW |