Chromium Code Reviews| Index: ui/chromeos/touch_exploration_controller.cc |
| diff --git a/ui/chromeos/touch_exploration_controller.cc b/ui/chromeos/touch_exploration_controller.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..03c63b0fe4eadf8b53c80c022783e5877c4750e5 |
| --- /dev/null |
| +++ b/ui/chromeos/touch_exploration_controller.cc |
| @@ -0,0 +1,170 @@ |
| +// Copyright 2014 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "ui/chromeos/touch_exploration_controller.h" |
| + |
| +#include "ui/aura/client/cursor_client.h" |
| +#include "ui/aura/window.h" |
| +#include "ui/aura/window_tree_host.h" |
| +#include "ui/events/event.h" |
| + |
| +namespace ui { |
| + |
| +TouchExplorationController::TouchExplorationController( |
| + aura::Window* root_window) |
| + : root_window_(root_window) { |
| + CHECK(root_window); |
| + root_window->GetHost()->GetEventSource()->AddEventRewriter(this); |
| +} |
| + |
| +TouchExplorationController::~TouchExplorationController() { |
| + root_window_->GetHost()->GetEventSource()->RemoveEventRewriter(this); |
| +} |
| + |
| +ui::EventRewriteStatus TouchExplorationController::RewriteEvent( |
| + const ui::Event& event, |
| + scoped_ptr<ui::Event>* rewritten_event) { |
| + if (!event.IsTouchEvent()) |
| + return ui::EVENT_REWRITE_CONTINUE; |
| + |
| + const ui::TouchEvent& touch_event = |
| + static_cast<const ui::TouchEvent&>(event); |
| + const ui::EventType type = touch_event.type(); |
| + const gfx::Point location = touch_event.location(); |
| + const int touch_id = touch_event.touch_id(); |
| + const int flags = touch_event.flags(); |
| + |
| + if (type == ui::ET_TOUCH_PRESSED) { |
| + touch_ids_.push_back(touch_id); |
| + touch_locations_.insert(std::pair<int, gfx::Point>(touch_id, location)); |
| + // If this is the first and only finger touching - rewrite the touch as a |
| + // mouse move. Otherwise let the it go through as is. |
| + if (touch_ids_.size() == 1) { |
| + rewritten_event->reset(CreateMouseMoveEvent(location, flags)); |
| + EnterTouchToMouseMode(); |
| + return ui::EVENT_REWRITE_REWRITTEN; |
| + } else { |
| + return ui::EVENT_REWRITE_CONTINUE; |
| + } |
| + } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) { |
| + std::vector<int>::iterator it = |
| + std::find(touch_ids_.begin(), touch_ids_.end(), touch_id); |
|
dmazzoni
2014/04/30 06:08:35
This can be written as just:
std::vector<int>::it
mfomitchev
2014/04/30 17:06:19
vector doesn't have find(), does it? I get a compi
dmazzoni
2014/04/30 17:45:07
Nevermind, I was thinking of other STL classes tha
|
| + // We may fail to find the finger if the exploration mode was turned on |
| + // while the user had some fingers touching the screen. We simply ignore |
| + // those fingers for the purposes of event transformation. |
| + if (it == touch_ids_.end()) |
| + return ui::EVENT_REWRITE_CONTINUE; |
| + const bool first_finger_released = it == touch_ids_.begin(); |
| + touch_ids_.erase(it); |
| + touch_locations_.erase(touch_id); |
|
dmazzoni
2014/04/30 06:08:35
Assert / dcheck that touch_locations contains touc
mfomitchev
2014/04/30 17:06:19
Done.
|
| + const int num_fingers_remaining = touch_ids_.size(); |
| + |
| + if (num_fingers_remaining == 0) { |
| + rewritten_event->reset(CreateMouseMoveEvent(location, flags)); |
| + return ui::EVENT_REWRITE_REWRITTEN; |
| + } |
| + |
| + // If we are left with one finger - enter the mouse move mode. |
| + const bool enter_mouse_move_mode = num_fingers_remaining == 1; |
| + |
| + if (!enter_mouse_move_mode && !first_finger_released) { |
| + // No special handling needed. |
| + return ui::EVENT_REWRITE_CONTINUE; |
| + } |
| + |
| + // If the finger which was released was the first one, - we need to rewrite |
| + // the release event as a release of the was second / now first finger. |
| + // This is the finger which will now be getting "substracted". |
| + if (first_finger_released) { |
| + int rewritten_release_id = touch_ids_[0]; |
| + gfx::Point rewritten_release_location = |
| + touch_locations_[rewritten_release_id]; |
| + ui::TouchEvent* rewritten_release_event = new ui::TouchEvent( |
| + ui::ET_TOUCH_RELEASED, |
| + rewritten_release_location, |
| + rewritten_release_id, |
| + event.time_stamp()); |
| + rewritten_event->reset(rewritten_release_event); |
| + } else if (enter_mouse_move_mode) { |
| + // Dispatch the release event as is. |
| + // TODO(mfomitchev): We can get rid of this clause once we have |
| + // EVENT_REWRITE_DISPATCH_ANOTHER working without having to set |
| + // rewritten_event. |
| + rewritten_event->reset(new ui::TouchEvent(touch_event)); |
| + } |
| + |
| + if (enter_mouse_move_mode) { |
| + // Since we are entering the mouse move mode - also dispatch a mouse move |
| + // event at the location of the one remaining finger. (num_fingers == 1) |
| + gfx::Point mouse_move_location = touch_locations_[touch_ids_[0]]; |
| + next_dispatch_event_.reset( |
| + CreateMouseMoveEvent(mouse_move_location, flags)); |
| + } |
| + |
| + if (enter_mouse_move_mode) { |
| + return ui::EVENT_REWRITE_DISPATCH_ANOTHER; |
| + } else { // first_finger_released == true |
| + return ui::EVENT_REWRITE_REWRITTEN; |
| + } |
| + } else if (type == ui::ET_TOUCH_MOVED) { |
| + std::vector<int>::iterator it = |
| + std::find(touch_ids_.begin(), touch_ids_.end(), touch_id); |
| + // We may fail to find the finger if the exploration mode was turned on |
| + // while the user had some fingers touching the screen. We simply ignore |
| + // those fingers for the purposes of event transformation. |
| + if (it == touch_ids_.end()) |
| + return ui::EVENT_REWRITE_CONTINUE; |
| + touch_locations_[*it] = location; |
| + if (touch_ids_.size() == 1) { |
| + // Touch moves are rewritten as mouse moves when there's only one finger |
| + // touching the screen. |
| + rewritten_event->reset(CreateMouseMoveEvent(location, flags)); |
| + return ui::EVENT_REWRITE_REWRITTEN; |
| + } else if (touch_id == touch_ids_.front()) { |
| + // Touch moves of the first finger are discarded when there's more than |
| + // one finger touching. |
| + return ui::EVENT_REWRITE_DISCARD; |
| + } else { |
| + return ui::EVENT_REWRITE_CONTINUE; |
| + } |
| + } else if (type == ui::ET_TOUCH_STATIONARY) { |
| + if (touch_id == touch_ids_.front()) |
| + return ui::EVENT_REWRITE_DISCARD; |
| + else |
| + return ui::EVENT_REWRITE_CONTINUE; |
| + } |
| + NOTREACHED(); |
|
dmazzoni
2014/04/30 06:08:35
Should you switch on |type| instead? Then not hand
mfomitchev
2014/04/30 17:06:19
Problem is, there's over 40 of values in the Even
dmazzoni
2014/04/30 17:45:07
Got it - the rest are thrown away with event.IsTou
|
| + return ui::EVENT_REWRITE_CONTINUE; |
| +} |
| + |
| +ui::EventRewriteStatus TouchExplorationController::NextDispatchEvent( |
| + const ui::Event& last_event, |
| + scoped_ptr<ui::Event>* new_event) { |
| + CHECK(next_dispatch_event_); |
| + *new_event = next_dispatch_event_.Pass(); |
| + // Enter the mouse move mode if needed |
| + if ((*new_event)->IsMouseEvent()) |
| + EnterTouchToMouseMode(); |
| + return ui::EVENT_REWRITE_REWRITTEN; |
| +} |
| + |
| +ui::Event* TouchExplorationController::CreateMouseMoveEvent(gfx::Point location, |
| + int flags) { |
| + return new ui::MouseEvent(ui::ET_MOUSE_MOVED, |
| + location, |
| + location, |
| + flags | ui::EF_IS_SYNTHESIZED | ui::EF_FROM_TOUCH, |
| + 0); |
| +} |
| + |
| +void TouchExplorationController::EnterTouchToMouseMode() { |
| + aura::client::CursorClient* cursor_client = |
| + aura::client::GetCursorClient(root_window_); |
| + if (cursor_client && !cursor_client->IsMouseEventsEnabled()) |
| + cursor_client->EnableMouseEvents(); |
| + if (cursor_client && cursor_client->IsCursorVisible()) |
| + cursor_client->HideCursor(); |
| +} |
| + |
| +} // namespace ui |