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/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 |
| 15 TouchExplorationController::TouchExplorationController( | 17 TouchExplorationController::TouchExplorationController( |
| 16 aura::Window* root_window) | 18 aura::Window* root_window) |
| 17 : root_window_(root_window) { | 19 : root_window_(root_window), |
| 20 initial_touch_id_passthrough_mapping_(0), | |
| 21 state_(NO_FINGERS_DOWN), | |
| 22 event_handler_for_testing_(NULL) { | |
| 18 CHECK(root_window); | 23 CHECK(root_window); |
| 19 root_window->GetHost()->GetEventSource()->AddEventRewriter(this); | 24 root_window->GetHost()->GetEventSource()->AddEventRewriter(this); |
| 20 } | 25 } |
| 21 | 26 |
| 22 TouchExplorationController::~TouchExplorationController() { | 27 TouchExplorationController::~TouchExplorationController() { |
| 23 root_window_->GetHost()->GetEventSource()->RemoveEventRewriter(this); | 28 root_window_->GetHost()->GetEventSource()->RemoveEventRewriter(this); |
| 24 } | 29 } |
| 25 | 30 |
| 31 void TouchExplorationController::CallTapTimerNowForTesting() { | |
| 32 CHECK(tap_timer_.IsRunning()); | |
| 33 tap_timer_.Stop(); | |
| 34 OnTapTimerFired(); | |
| 35 } | |
| 36 | |
| 37 void TouchExplorationController::SetEventHandlerForTesting( | |
| 38 ui::EventHandler* event_handler_for_testing) { | |
| 39 event_handler_for_testing_ = event_handler_for_testing; | |
| 40 } | |
| 41 | |
| 26 ui::EventRewriteStatus TouchExplorationController::RewriteEvent( | 42 ui::EventRewriteStatus TouchExplorationController::RewriteEvent( |
| 27 const ui::Event& event, | 43 const ui::Event& event, |
| 28 scoped_ptr<ui::Event>* rewritten_event) { | 44 scoped_ptr<ui::Event>* rewritten_event) { |
| 29 if (!event.IsTouchEvent()) | 45 if (!event.IsTouchEvent()) |
| 30 return ui::EVENT_REWRITE_CONTINUE; | 46 return ui::EVENT_REWRITE_CONTINUE; |
| 31 | 47 |
| 32 const ui::TouchEvent& touch_event = | 48 const ui::TouchEvent& touch_event = |
| 33 static_cast<const ui::TouchEvent&>(event); | 49 static_cast<const ui::TouchEvent&>(event); |
| 34 const ui::EventType type = touch_event.type(); | 50 const ui::EventType type = touch_event.type(); |
| 35 const gfx::PointF& location = touch_event.location_f(); | 51 const gfx::PointF& location = touch_event.location_f(); |
| 36 const int touch_id = touch_event.touch_id(); | 52 const int touch_id = touch_event.touch_id(); |
| 37 const int flags = touch_event.flags(); | 53 |
| 38 | 54 // Always update touch ids and touch locations, so we can use those |
| 55 // no matter what state we're in. | |
| 39 if (type == ui::ET_TOUCH_PRESSED) { | 56 if (type == ui::ET_TOUCH_PRESSED) { |
| 40 touch_ids_.push_back(touch_id); | 57 touch_ids_.push_back(touch_id); |
| 41 touch_locations_.insert(std::pair<int, gfx::PointF>(touch_id, location)); | 58 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 | 59 } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) { |
| 43 // mouse move. Otherwise let the it go through as is. | 60 std::vector<int>::iterator it = |
| 44 if (touch_ids_.size() == 1) { | 61 std::find(touch_ids_.begin(), touch_ids_.end(), touch_id); |
| 45 *rewritten_event = CreateMouseMoveEvent(location, flags); | 62 |
| 63 // Can happen if touch exploration is enabled while fingers were down. | |
| 64 if (it == touch_ids_.end()) | |
| 65 return ui::EVENT_REWRITE_CONTINUE; | |
| 66 | |
| 67 touch_ids_.erase(it); | |
| 68 touch_locations_.erase(touch_id); | |
| 69 } else if (type == ui::ET_TOUCH_MOVED) { | |
| 70 std::vector<int>::iterator it = | |
| 71 std::find(touch_ids_.begin(), touch_ids_.end(), touch_id); | |
| 72 | |
| 73 // Can happen if touch exploration is enabled while fingers were down. | |
| 74 if (it == touch_ids_.end()) | |
| 75 return ui::EVENT_REWRITE_CONTINUE; | |
| 76 | |
| 77 touch_locations_[*it] = location; | |
| 78 } | |
| 79 | |
| 80 // The rest of the processing depends on what state we're in. | |
| 81 switch(state_) { | |
| 82 case NO_FINGERS_DOWN: | |
| 83 return OnNoFingersDown(touch_event, rewritten_event); | |
| 84 case GRACE_PERIOD: | |
| 85 return OnGracePeriod(touch_event, rewritten_event); | |
| 86 case TOUCH_EXPLORATION: | |
| 87 return OnTouchExploration(touch_event, rewritten_event); | |
| 88 case SINGLE_TAP_PENDING: | |
| 89 return OnSingleTapPending(touch_event, rewritten_event); | |
| 90 case DOUBLE_TAP_PRESSED: | |
| 91 return OnDoubleTapPressed(touch_event, rewritten_event); | |
| 92 case PASSTHROUGH_MINUS_ONE: | |
| 93 return OnPassthroughMinusOne(touch_event, rewritten_event); | |
| 94 } | |
| 95 | |
| 96 NOTREACHED(); | |
| 97 return ui::EVENT_REWRITE_CONTINUE; | |
| 98 } | |
| 99 | |
| 100 ui::EventRewriteStatus TouchExplorationController::NextDispatchEvent( | |
| 101 const ui::Event& last_event, scoped_ptr<ui::Event>* new_event) { | |
| 102 NOTREACHED(); | |
| 103 return ui::EVENT_REWRITE_CONTINUE; | |
| 104 } | |
| 105 | |
| 106 ui::EventRewriteStatus TouchExplorationController::OnNoFingersDown( | |
| 107 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event) { | |
| 108 const ui::EventType type = event.type(); | |
| 109 if (type == ui::ET_TOUCH_PRESSED) { | |
| 110 initial_press_.reset(new TouchEvent(event)); | |
| 111 tap_timer_.Start(FROM_HERE, | |
| 112 gesture_detector_config_.double_tap_timeout, | |
| 113 this, | |
| 114 &TouchExplorationController::OnTapTimerFired); | |
| 115 state_ = GRACE_PERIOD; | |
| 116 return ui::EVENT_REWRITE_DISCARD; | |
| 117 } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) { | |
|
aboxhall
2014/06/02 16:33:14
What's the point of these last two if blocks? They
dmazzoni
2014/06/03 07:46:51
You're right. Simplified.
| |
| 118 NOTREACHED(); | |
| 119 return ui::EVENT_REWRITE_CONTINUE; | |
| 120 } else if (type == ui::ET_TOUCH_MOVED) { | |
| 121 NOTREACHED(); | |
| 122 return ui::EVENT_REWRITE_CONTINUE; | |
| 123 } | |
| 124 NOTREACHED() << "Unexpected event type received."; | |
| 125 return ui::EVENT_REWRITE_CONTINUE; | |
| 126 } | |
| 127 | |
| 128 ui::EventRewriteStatus TouchExplorationController::OnGracePeriod( | |
| 129 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event) { | |
| 130 const ui::EventType type = event.type(); | |
| 131 if (event.time_stamp() - initial_press_->time_stamp() > | |
|
aboxhall
2014/06/02 16:33:14
Even though it's reasonably self-explanatory, it m
dmazzoni
2014/06/03 07:46:51
Done.
| |
| 132 gesture_detector_config_.double_tap_timeout) { | |
| 133 EnterTouchToMouseMode(); | |
| 134 state_ = TOUCH_EXPLORATION; | |
| 135 return OnTouchExploration(event, rewritten_event); | |
|
mfomitchev
2014/06/02 23:12:18
I think there still is a problem:
Suppose event i
dmazzoni
2014/06/03 07:46:51
Good catch.
I realized that we can handle this ca
| |
| 136 } | |
| 137 | |
| 138 if (type == ui::ET_TOUCH_PRESSED) { | |
| 139 // Adding a second finger within the timeout period switches to | |
| 140 // passthrough. | |
| 141 state_ = PASSTHROUGH_MINUS_ONE; | |
| 142 return OnPassthroughMinusOne(event, rewritten_event); | |
| 143 } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) { | |
| 144 DCHECK_EQ(0U, touch_ids_.size()); | |
| 145 state_ = SINGLE_TAP_PENDING; | |
| 146 return EVENT_REWRITE_DISCARD; | |
| 147 } else if (type == ui::ET_TOUCH_MOVED) { | |
| 148 // If the user moves far enough from the initial touch location (outside | |
| 149 // the "slop" region, jump to the touch exploration mode early. Note that | |
|
aboxhall
2014/06/02 16:33:14
Rephrase this note as an explicit TODO?
dmazzoni
2014/06/03 07:46:51
Done.
| |
| 150 // when we add gesture recognition, we should probably jump to gesture | |
| 151 // mode here if the velocity is high enough, and touch exploration if | |
| 152 // the velocity is lower. | |
| 153 float delta = (event.location() - initial_press_->location()).Length(); | |
| 154 if (delta > gesture_detector_config_.touch_slop) { | |
| 46 EnterTouchToMouseMode(); | 155 EnterTouchToMouseMode(); |
| 156 state_ = TOUCH_EXPLORATION; | |
| 157 return OnTouchExploration(event, rewritten_event); | |
| 158 } | |
| 159 | |
| 160 return EVENT_REWRITE_DISCARD; | |
| 161 } | |
| 162 NOTREACHED() << "Unexpected event type received."; | |
| 163 return ui::EVENT_REWRITE_CONTINUE; | |
| 164 } | |
| 165 | |
| 166 ui::EventRewriteStatus TouchExplorationController::OnTouchExploration( | |
| 167 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event) { | |
| 168 const ui::EventType type = event.type(); | |
| 169 if (type == ui::ET_TOUCH_PRESSED) { | |
| 170 // Ignore any additional fingers when we're already in touch exploration | |
| 171 // mode. Later, we should support "split-tap". | |
|
aboxhall
2014/06/02 16:33:14
TODO?
dmazzoni
2014/06/03 07:46:51
Done.
| |
| 172 return ui::EVENT_REWRITE_DISCARD; | |
| 173 } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) { | |
| 174 if (touch_ids_.size() == 0) | |
| 175 state_ = NO_FINGERS_DOWN; | |
| 176 } else if (type != ui::ET_TOUCH_MOVED) { | |
| 177 NOTREACHED() << "Unexpected event type received."; | |
| 178 return ui::EVENT_REWRITE_CONTINUE; | |
| 179 } | |
| 180 | |
| 181 // Rewrite as a mouse-move event. | |
| 182 *rewritten_event = CreateMouseMoveEvent(event.location(), event.flags()); | |
| 183 last_touch_exploration_location_ = event.location(); | |
| 184 return ui::EVENT_REWRITE_REWRITTEN; | |
| 185 } | |
| 186 | |
| 187 ui::EventRewriteStatus TouchExplorationController::OnSingleTapPending( | |
| 188 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event) { | |
| 189 const ui::EventType type = event.type(); | |
|
mfomitchev
2014/06/02 23:12:18
Should we have a case here for
(event.time_stamp(
dmazzoni
2014/06/03 07:46:51
Yes, but I think it's cleaner to have it up above.
| |
| 190 if (type == ui::ET_TOUCH_PRESSED) { | |
|
aboxhall
2014/06/02 16:33:14
Comment stating explicitly that this represents a
dmazzoni
2014/06/03 07:46:51
Done.
| |
| 191 // Rewrite at location of last touch exploration. | |
| 192 ui::TouchEvent* rewritten_press_event = new ui::TouchEvent( | |
| 193 ui::ET_TOUCH_PRESSED, | |
| 194 last_touch_exploration_location_, | |
| 195 event.touch_id(), | |
| 196 event.time_stamp()); | |
| 197 rewritten_press_event->set_flags(event.flags()); | |
| 198 rewritten_event->reset(rewritten_press_event); | |
| 199 state_ = DOUBLE_TAP_PRESSED; | |
| 200 return ui::EVENT_REWRITE_REWRITTEN; | |
| 201 } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) { | |
|
aboxhall
2014/06/02 16:33:14
Similarly, why are these else blocks here? Do they
dmazzoni
2014/06/03 07:46:51
Done.
| |
| 202 NOTREACHED(); | |
| 203 return ui::EVENT_REWRITE_CONTINUE; | |
| 204 } else if (type == ui::ET_TOUCH_MOVED) { | |
| 205 NOTREACHED(); | |
| 206 return ui::EVENT_REWRITE_CONTINUE; | |
| 207 } | |
| 208 NOTREACHED() << "Unexpected event type received."; | |
| 209 return ui::EVENT_REWRITE_CONTINUE; | |
| 210 } | |
| 211 | |
| 212 ui::EventRewriteStatus TouchExplorationController::OnDoubleTapPressed( | |
| 213 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event) { | |
| 214 const ui::EventType type = event.type(); | |
| 215 if (type == ui::ET_TOUCH_PRESSED) { | |
|
aboxhall
2014/06/02 16:33:14
How could we get a TOUCH_PRESSED directly after a
dmazzoni
2014/06/03 07:46:51
You have lots of fingers. :)
| |
| 216 return ui::EVENT_REWRITE_DISCARD; | |
| 217 } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) { | |
| 218 if (touch_ids_.size() != 0) | |
|
aboxhall
2014/06/02 16:33:14
It took me quite a while to work out what was goin
dmazzoni
2014/06/03 07:46:51
Sure, how about current_touch_ids_
| |
| 219 return EVENT_REWRITE_DISCARD; | |
| 220 | |
| 221 // Rewrite at location of last touch exploration. | |
| 222 ui::TouchEvent* rewritten_release_event = new ui::TouchEvent( | |
| 223 ui::ET_TOUCH_RELEASED, | |
| 224 last_touch_exploration_location_, | |
| 225 event.touch_id(), | |
| 226 event.time_stamp()); | |
| 227 rewritten_release_event->set_flags(event.flags()); | |
| 228 rewritten_event->reset(rewritten_release_event); | |
| 229 state_ = NO_FINGERS_DOWN; | |
| 230 return ui::EVENT_REWRITE_REWRITTEN; | |
| 231 } else if (type == ui::ET_TOUCH_MOVED) { | |
| 232 return ui::EVENT_REWRITE_DISCARD; | |
| 233 } | |
| 234 NOTREACHED() << "Unexpected event type received."; | |
| 235 return ui::EVENT_REWRITE_CONTINUE; | |
| 236 } | |
| 237 | |
| 238 ui::EventRewriteStatus TouchExplorationController::OnPassthroughMinusOne( | |
| 239 const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event) { | |
| 240 ui::EventType type = event.type(); | |
| 241 gfx::PointF location = event.location_f(); | |
| 242 | |
| 243 if (type == ui::ET_TOUCH_PRESSED) { | |
| 244 return ui::EVENT_REWRITE_CONTINUE; | |
|
mfomitchev
2014/06/02 23:12:18
Nit: It might make sense to get rid of this if. Th
dmazzoni
2014/06/03 07:46:51
Done.
| |
| 245 } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) { | |
| 246 if (touch_ids_.size() == 0) | |
| 247 state_ = NO_FINGERS_DOWN; | |
|
mfomitchev
2014/06/02 23:12:18
We also need to set initial_touch_id_passthrough_m
dmazzoni
2014/06/03 07:46:51
Done.
| |
| 248 | |
| 249 bool first_finger_still_down = | |
|
aboxhall
2014/06/02 16:33:14
Does the rest of this need to go inside this if bl
dmazzoni
2014/06/03 07:46:51
No, the ET_TOUCH_MOVED case doesn't early-return.
| |
| 250 touch_ids_.size() >= 1 && | |
| 251 touch_ids_[0] == initial_press_->touch_id(); | |
| 252 | |
| 253 if (first_finger_still_down && | |
| 254 touch_ids_.size() == 1 && | |
|
mfomitchev
2014/06/02 23:12:18
Hmm.. why do we only do this when there's only one
dmazzoni
2014/06/03 07:46:51
Sure, this is a bit simpler.
| |
| 255 event.touch_id() != initial_press_->touch_id() && | |
| 256 initial_touch_id_passthrough_mapping_ == 0) { | |
| 257 // If the only finger now remaining is the first finger, | |
| 258 // rewrite as a move to the location of the first finger. | |
| 259 initial_touch_id_passthrough_mapping_ = event.touch_id(); | |
| 260 ui::TouchEvent* rewritten_passthrough_event = new ui::TouchEvent( | |
| 261 ui::ET_TOUCH_MOVED, | |
| 262 touch_locations_[initial_press_->touch_id()], | |
| 263 initial_touch_id_passthrough_mapping_, | |
| 264 event.time_stamp()); | |
| 265 rewritten_passthrough_event->set_flags(event.flags()); | |
| 266 rewritten_event->reset(rewritten_passthrough_event); | |
| 47 return ui::EVENT_REWRITE_REWRITTEN; | 267 return ui::EVENT_REWRITE_REWRITTEN; |
| 48 } | 268 } |
| 49 return ui::EVENT_REWRITE_CONTINUE; | 269 } else if (type != ui::ET_TOUCH_MOVED) { |
| 50 } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) { | 270 NOTREACHED(); |
| 51 std::vector<int>::iterator it = | 271 return ui::EVENT_REWRITE_CONTINUE; |
| 52 std::find(touch_ids_.begin(), touch_ids_.end(), touch_id); | 272 } |
| 53 // We may fail to find the finger if the exploration mode was turned on | 273 |
| 54 // while the user had some fingers touching the screen. We simply ignore | 274 if (event.touch_id() == initial_press_->touch_id()) { |
| 55 // those fingers for the purposes of event transformation. | 275 if (!initial_touch_id_passthrough_mapping_) |
|
mfomitchev
2014/06/02 23:12:18
This would need to be changed to <= 0 if we use -1
dmazzoni
2014/06/03 07:46:51
Done.
| |
| 56 if (it == touch_ids_.end()) | 276 return ui::EVENT_REWRITE_DISCARD; |
| 57 return ui::EVENT_REWRITE_CONTINUE; | 277 |
| 58 const bool first_finger_released = it == touch_ids_.begin(); | 278 ui::TouchEvent* rewritten_passthrough_event = new ui::TouchEvent( |
| 59 touch_ids_.erase(it); | 279 type, |
| 60 int num_erased = touch_locations_.erase(touch_id); | 280 location, |
| 61 DCHECK_EQ(num_erased, 1); | 281 initial_touch_id_passthrough_mapping_, |
|
aboxhall
2014/06/02 16:33:14
I don't follow this either. It looks like we only
dmazzoni
2014/06/03 07:46:51
When you press two fingers, the first finger is ig
| |
| 62 const int num_fingers_remaining = touch_ids_.size(); | 282 event.time_stamp()); |
| 63 | 283 rewritten_passthrough_event->set_flags(event.flags()); |
| 64 if (num_fingers_remaining == 0) { | 284 rewritten_event->reset(rewritten_passthrough_event); |
| 65 *rewritten_event = CreateMouseMoveEvent(location, flags); | |
| 66 return ui::EVENT_REWRITE_REWRITTEN; | |
| 67 } | |
| 68 | |
| 69 // If we are left with one finger - enter the mouse move mode. | |
| 70 const bool enter_mouse_move_mode = num_fingers_remaining == 1; | |
| 71 | |
| 72 if (!enter_mouse_move_mode && !first_finger_released) { | |
| 73 // No special handling needed. | |
| 74 return ui::EVENT_REWRITE_CONTINUE; | |
| 75 } | |
| 76 | |
| 77 // If the finger which was released was the first one, - we need to rewrite | |
| 78 // the release event as a release of the was second / now first finger. | |
| 79 // This is the finger which will now be getting "substracted". | |
| 80 if (first_finger_released) { | |
| 81 int rewritten_release_id = touch_ids_[0]; | |
| 82 const gfx::PointF& rewritten_release_location = | |
| 83 touch_locations_[rewritten_release_id]; | |
| 84 ui::TouchEvent* rewritten_release_event = new ui::TouchEvent( | |
| 85 ui::ET_TOUCH_RELEASED, | |
| 86 rewritten_release_location, | |
| 87 rewritten_release_id, | |
| 88 event.time_stamp()); | |
| 89 rewritten_release_event->set_flags(touch_event.flags()); | |
| 90 rewritten_event->reset(rewritten_release_event); | |
| 91 } else if (enter_mouse_move_mode) { | |
| 92 // Dispatch the release event as is. | |
| 93 // TODO(mfomitchev): We can get rid of this clause once we have | |
| 94 // EVENT_REWRITE_DISPATCH_ANOTHER working without having to set | |
| 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; | 285 return ui::EVENT_REWRITE_REWRITTEN; |
| 108 } else if (type == ui::ET_TOUCH_MOVED) { | 286 } |
| 109 std::vector<int>::iterator it = | 287 |
| 110 std::find(touch_ids_.begin(), touch_ids_.end(), touch_id); | 288 return ui::EVENT_REWRITE_CONTINUE; |
| 111 // We may fail to find the finger if the exploration mode was turned on | 289 } |
| 112 // while the user had some fingers touching the screen. We simply ignore | 290 |
| 113 // those fingers for the purposes of event transformation. | 291 void TouchExplorationController::OnTapTimerFired() { |
| 114 if (it == touch_ids_.end()) | 292 if (state_ != SINGLE_TAP_PENDING && state_ != GRACE_PERIOD) |
| 115 return ui::EVENT_REWRITE_CONTINUE; | 293 return; |
| 116 touch_locations_[*it] = location; | 294 |
| 117 if (touch_ids_.size() == 1) { | 295 if (state_ == SINGLE_TAP_PENDING) { |
| 118 // Touch moves are rewritten as mouse moves when there's only one finger | 296 state_ = NO_FINGERS_DOWN; |
| 119 // touching the screen. | 297 } else { |
| 120 *rewritten_event = CreateMouseMoveEvent(location, flags).Pass(); | |
| 121 return ui::EVENT_REWRITE_REWRITTEN; | |
| 122 } | |
| 123 if (touch_id == touch_ids_.front()) { | |
| 124 // Touch moves of the first finger are discarded when there's more than | |
| 125 // one finger touching. | |
| 126 return ui::EVENT_REWRITE_DISCARD; | |
| 127 } | |
| 128 return ui::EVENT_REWRITE_CONTINUE; | |
| 129 } | |
| 130 NOTREACHED() << "Unexpected event type received."; | |
| 131 return ui::EVENT_REWRITE_CONTINUE; | |
| 132 } | |
| 133 | |
| 134 ui::EventRewriteStatus TouchExplorationController::NextDispatchEvent( | |
| 135 const ui::Event& last_event, | |
| 136 scoped_ptr<ui::Event>* new_event) { | |
| 137 CHECK(next_dispatch_event_); | |
| 138 DCHECK(last_event.IsTouchEvent()); | |
| 139 *new_event = next_dispatch_event_.Pass(); | |
| 140 // Enter the mouse move mode if needed | |
| 141 if ((*new_event)->IsMouseEvent()) | |
| 142 EnterTouchToMouseMode(); | 298 EnterTouchToMouseMode(); |
| 143 return ui::EVENT_REWRITE_REWRITTEN; | 299 state_ = TOUCH_EXPLORATION; |
| 300 } | |
| 301 | |
| 302 scoped_ptr<ui::Event> mouse_move = CreateMouseMoveEvent( | |
| 303 initial_press_->location(), initial_press_->flags()); | |
| 304 DispatchEvent(mouse_move.get()); | |
| 305 last_touch_exploration_location_ = initial_press_->location(); | |
| 306 } | |
| 307 | |
| 308 void TouchExplorationController::DispatchEvent(ui::Event* event) { | |
| 309 if (event_handler_for_testing_) { | |
| 310 event_handler_for_testing_->OnEvent(event); | |
| 311 return; | |
| 312 } | |
| 313 | |
| 314 ui::EventDispatchDetails result ALLOW_UNUSED = | |
| 315 root_window_->GetHost()->dispatcher()->OnEventFromSource(event); | |
| 144 } | 316 } |
| 145 | 317 |
| 146 scoped_ptr<ui::Event> TouchExplorationController::CreateMouseMoveEvent( | 318 scoped_ptr<ui::Event> TouchExplorationController::CreateMouseMoveEvent( |
| 147 const gfx::PointF& location, | 319 const gfx::PointF& location, |
| 148 int flags) { | 320 int flags) { |
| 149 return scoped_ptr<ui::Event>( | 321 return scoped_ptr<ui::Event>( |
| 150 new ui::MouseEvent( | 322 new ui::MouseEvent( |
| 151 ui::ET_MOUSE_MOVED, | 323 ui::ET_MOUSE_MOVED, |
| 152 location, | 324 location, |
| 153 location, | 325 location, |
| 154 flags | ui::EF_IS_SYNTHESIZED | ui::EF_TOUCH_ACCESSIBILITY, | 326 flags | ui::EF_IS_SYNTHESIZED | ui::EF_TOUCH_ACCESSIBILITY, |
| 155 0)); | 327 0)); |
| 156 } | 328 } |
| 157 | 329 |
| 158 void TouchExplorationController::EnterTouchToMouseMode() { | 330 void TouchExplorationController::EnterTouchToMouseMode() { |
| 159 aura::client::CursorClient* cursor_client = | 331 aura::client::CursorClient* cursor_client = |
| 160 aura::client::GetCursorClient(root_window_); | 332 aura::client::GetCursorClient(root_window_); |
| 161 if (cursor_client && !cursor_client->IsMouseEventsEnabled()) | 333 if (cursor_client && !cursor_client->IsMouseEventsEnabled()) |
| 162 cursor_client->EnableMouseEvents(); | 334 cursor_client->EnableMouseEvents(); |
| 163 if (cursor_client && cursor_client->IsCursorVisible()) | 335 if (cursor_client && cursor_client->IsCursorVisible()) |
| 164 cursor_client->HideCursor(); | 336 cursor_client->HideCursor(); |
| 165 } | 337 } |
| 166 | 338 |
| 167 } // namespace ui | 339 } // namespace ui |
| OLD | NEW |