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/chromeos/touch_exploration_controller.h" |
| 6 |
| 7 #include "base/logging.h" |
| 8 #include "ui/aura/client/cursor_client.h" |
| 9 #include "ui/aura/window.h" |
| 10 #include "ui/aura/window_tree_host.h" |
| 11 #include "ui/events/event.h" |
| 12 |
| 13 namespace ui { |
| 14 |
| 15 TouchExplorationController::TouchExplorationController( |
| 16 aura::Window* root_window) |
| 17 : root_window_(root_window) { |
| 18 CHECK(root_window); |
| 19 root_window->GetHost()->GetEventSource()->AddEventRewriter(this); |
| 20 } |
| 21 |
| 22 TouchExplorationController::~TouchExplorationController() { |
| 23 root_window_->GetHost()->GetEventSource()->RemoveEventRewriter(this); |
| 24 } |
| 25 |
| 26 ui::EventRewriteStatus TouchExplorationController::RewriteEvent( |
| 27 const ui::Event& event, |
| 28 scoped_ptr<ui::Event>* rewritten_event) { |
| 29 if (!event.IsTouchEvent()) |
| 30 return ui::EVENT_REWRITE_CONTINUE; |
| 31 |
| 32 const ui::TouchEvent& touch_event = |
| 33 static_cast<const ui::TouchEvent&>(event); |
| 34 const ui::EventType type = touch_event.type(); |
| 35 const gfx::PointF& location = touch_event.location_f(); |
| 36 const int touch_id = touch_event.touch_id(); |
| 37 const int flags = touch_event.flags(); |
| 38 |
| 39 if (type == ui::ET_TOUCH_PRESSED) { |
| 40 touch_ids_.push_back(touch_id); |
| 41 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 |
| 43 // mouse move. Otherwise let the it go through as is. |
| 44 if (touch_ids_.size() == 1) { |
| 45 *rewritten_event = CreateMouseMoveEvent(location, flags); |
| 46 EnterTouchToMouseMode(); |
| 47 return ui::EVENT_REWRITE_REWRITTEN; |
| 48 } |
| 49 return ui::EVENT_REWRITE_CONTINUE; |
| 50 } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) { |
| 51 std::vector<int>::iterator it = |
| 52 std::find(touch_ids_.begin(), touch_ids_.end(), touch_id); |
| 53 // We may fail to find the finger if the exploration mode was turned on |
| 54 // while the user had some fingers touching the screen. We simply ignore |
| 55 // those fingers for the purposes of event transformation. |
| 56 if (it == touch_ids_.end()) |
| 57 return ui::EVENT_REWRITE_CONTINUE; |
| 58 const bool first_finger_released = it == touch_ids_.begin(); |
| 59 touch_ids_.erase(it); |
| 60 int num_erased = touch_locations_.erase(touch_id); |
| 61 DCHECK_EQ(num_erased, 1); |
| 62 const int num_fingers_remaining = touch_ids_.size(); |
| 63 |
| 64 if (num_fingers_remaining == 0) { |
| 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; |
| 108 } else if (type == ui::ET_TOUCH_MOVED) { |
| 109 std::vector<int>::iterator it = |
| 110 std::find(touch_ids_.begin(), touch_ids_.end(), touch_id); |
| 111 // We may fail to find the finger if the exploration mode was turned on |
| 112 // while the user had some fingers touching the screen. We simply ignore |
| 113 // those fingers for the purposes of event transformation. |
| 114 if (it == touch_ids_.end()) |
| 115 return ui::EVENT_REWRITE_CONTINUE; |
| 116 touch_locations_[*it] = location; |
| 117 if (touch_ids_.size() == 1) { |
| 118 // Touch moves are rewritten as mouse moves when there's only one finger |
| 119 // touching the screen. |
| 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(); |
| 143 return ui::EVENT_REWRITE_REWRITTEN; |
| 144 } |
| 145 |
| 146 scoped_ptr<ui::Event> TouchExplorationController::CreateMouseMoveEvent( |
| 147 const gfx::PointF& location, |
| 148 int flags) { |
| 149 return scoped_ptr<ui::Event>( |
| 150 new ui::MouseEvent(ui::ET_MOUSE_MOVED, |
| 151 location, |
| 152 location, |
| 153 flags | ui::EF_IS_SYNTHESIZED | ui::EF_FROM_TOUCH, |
| 154 0)); |
| 155 } |
| 156 |
| 157 void TouchExplorationController::EnterTouchToMouseMode() { |
| 158 aura::client::CursorClient* cursor_client = |
| 159 aura::client::GetCursorClient(root_window_); |
| 160 if (cursor_client && !cursor_client->IsMouseEventsEnabled()) |
| 161 cursor_client->EnableMouseEvents(); |
| 162 if (cursor_client && cursor_client->IsCursorVisible()) |
| 163 cursor_client->HideCursor(); |
| 164 } |
| 165 |
| 166 } // namespace ui |
OLD | NEW |