Chromium Code Reviews| Index: ash/touch/touch_exploration_controller.cc |
| diff --git a/ash/touch/touch_exploration_controller.cc b/ash/touch/touch_exploration_controller.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..3661d1dbebe822d4174a530dc2f8600949f61b0b |
| --- /dev/null |
| +++ b/ash/touch/touch_exploration_controller.cc |
| @@ -0,0 +1,174 @@ |
| +// 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 "ash/touch/touch_exploration_controller.h" |
| + |
| +#include "ash/root_window_settings.h" |
| +#include "ash/shell.h" |
| +#include "ash/wm/coordinate_conversion.h" |
| +#include "base/logging.h" |
| +#include "ui/aura/window_tree_host.h" |
| +#include "ui/events/event.h" |
| +#include "ui/events/event_processor.h" |
| +#include "ui/gfx/point.h" |
| + |
| +namespace ash { |
| +namespace internal { |
| + |
| +TouchExplorationController::TouchExplorationController( |
| + aura::Window* root_window) : |
| + display_id_(GetRootWindowSettings(root_window)->display_id), |
| + root_window_(root_window) { |
| + Shell::GetInstance()->display_controller()->AddObserver(this); |
| + root_window_->AddPreTargetHandler(this); |
| +} |
| + |
| +TouchExplorationController::~TouchExplorationController() { |
| + Shell::GetInstance()->display_controller()->RemoveObserver(this); |
| + if (root_window_) |
| + root_window_->RemovePreTargetHandler(this); |
| +} |
| + |
| +void TouchExplorationController::OnTouchEvent(ui::TouchEvent* event) { |
| + ui::EventType type = event->type(); |
| + if (type == ui::ET_TOUCH_PRESSED) { |
| + LOG(ERROR) << "ET_TOUCH_PRESSED"; |
| + // If this is the first and only finger touching - we are entering the |
| + // mouse move mode. |
| + if (touch_ids_.size() == 0) { |
| + // TODO: Here and in other cases we take the flags from the touch event |
|
mfomitchev
2014/04/11 21:00:58
Question here
sadrul
2014/04/14 20:22:11
Yes. The EventRewriter implementation should do th
|
| + // and send them along with the synthesized mouse event - is that correct? |
| + GenerateMouseEvent( |
| + ui::ET_MOUSE_ENTERED, event->location(), event->flags()); |
| + event->SetHandled(); |
| + event->StopPropagation(); |
|
mfomitchev
2014/04/11 21:00:58
If I don't call StopPropagation() (here and in oth
sadrul
2014/04/14 20:22:11
Yeah. We need to stop propagating the touch-event
|
| + } |
| + // If this is the second finger - we should exit the mouse move mode (which |
| + // we should have entered when the first finger touch started), and we |
| + // should let this touch go through as is. |
| + if (touch_ids_.size() == 1) { |
| + // Generate ET_MOUSE_EXITED in the location of the _first_ touch. |
| + int first_touch_id = touch_ids_.at(0); |
| + gfx::Point first_touch_location = touch_locations_[first_touch_id]; |
| + GenerateMouseEvent( |
|
sadrul
2014/04/14 20:22:11
WindowEventDispatcher takes care of dispatching mo
|
| + ui::ET_MOUSE_EXITED, first_touch_location, event->flags()); |
| + } |
| + touch_ids_.push_back(event->touch_id()); |
| + touch_locations_.insert( |
| + std::pair<int, gfx::Point>(event->touch_id(), event->location())); |
| + // Ignore the synthesized release events - we are synthesizing them below. |
| + } else if ((type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) |
| + && !(event->flags() & ui::EF_IS_SYNTHESIZED)) { |
| + LOG(ERROR) << (type == ui::ET_TOUCH_RELEASED ? |
| + "ET_TOUCH_RELEASED" : "ET_TOUCH_CANCELLED"); |
| + int touch_id = event->touch_id(); |
| + std::vector<int>::iterator it = |
| + std::find(touch_ids_.begin(), touch_ids_.end(), touch_id); |
| + if (it != touch_ids_.end()) { |
| + // If it was the first finger that was lifted, we need to do a few |
| + // things depending on how many fingers were on the screen: |
| + // 1. If only one finger was on the screen, this is simply equivalent to |
| + // the end of the mouse move. |
| + // 2. If there were multiple fingers on the screen, this is equivalent |
| + // to lifting the _second_ finger. Also, if there were exactly two |
| + // fingers touching, we are only left with one, so we are entering the |
| + // mouse move mode, and so we should also generate ET_MOUSE_ENTERED. |
| + if (it == touch_ids_.begin()) { |
| + if (touch_ids_.size() == 1) { |
| + GenerateMouseEvent( |
| + ui::ET_MOUSE_EXITED, event->location(), event->flags()); |
| + } else { |
| + LOG(ERROR) << "Generating touch release event"; |
| + // Generate a touch release event for the second finger. |
| + int second_touch_id = touch_ids_.at(1); |
| + gfx::Point second_touch_location = touch_locations_[second_touch_id]; |
| + aura::Window* root = wm::GetRootWindowAt(second_touch_location); |
| + DCHECK(root) |
| + << "Root window not found while generating touch release event."; |
| + aura::WindowTreeHost* host = root->GetHost(); |
| + // TODO: Should I use another constructor to pass in the flags? |
|
mfomitchev
2014/04/11 21:00:58
Question here
|
| + ui::TouchEvent touch_event(ui::ET_TOUCH_RELEASED, |
| + second_touch_location, |
| + second_touch_id, |
| + event->time_stamp()); |
| + host->event_processor()->OnEventFromSource(&touch_event); |
| + // If there were exactly two fingers touching - generate |
| + // ET_MOUSE_ENTERED. |
| + if (touch_ids_.size() == 2) { |
| + GenerateMouseEvent( |
| + ui::ET_MOUSE_ENTERED, second_touch_location, event->flags()); |
| + } |
| + } |
| + event->SetHandled(); |
| + event->StopPropagation(); |
| + } |
| + touch_ids_.erase(it); |
| + touch_locations_.erase(touch_id); |
| + } else { |
| + NOTREACHED(); |
| + } |
| + } else if (type == ui::ET_TOUCH_MOVED) { |
| + LOG(ERROR) << "ET_TOUCH_MOVED"; |
| + // Consume if it is the first finger. |
| + // If it is the only finger - generate a mouse move event. |
| + std::vector<int>::iterator it = |
| + std::find(touch_ids_.begin(), touch_ids_.end(), event->touch_id()); |
| + if (it != touch_ids_.end()) { |
| + if (it == touch_ids_.begin()) { |
| + if (touch_ids_.size() == 1) { |
| + GenerateMouseEvent( |
| + ui::ET_MOUSE_MOVED, event->location(), event->flags()); |
| + } |
| + event->SetHandled(); |
| + event->StopPropagation(); |
| + } |
| + touch_locations_[*it] = event->location(); |
| + } else { |
| + NOTREACHED(); |
| + } |
| + } |
| +} |
| + |
| +void TouchExplorationController::OnDisplaysInitialized() { |
| + OnDisplayConfigurationChanged(); |
| +} |
| + |
| +void TouchExplorationController::OnDisplayConfigurationChanging() { |
| + if (!root_window_) |
| + return; |
| + |
| + root_window_->RemovePreTargetHandler(this); |
| + root_window_ = NULL; |
| +} |
| + |
| +void TouchExplorationController::OnDisplayConfigurationChanged() { |
| + if (root_window_) |
| + return; |
| + |
| + root_window_ = Shell::GetInstance()->display_controller()-> |
| + GetRootWindowForDisplayId(display_id_); |
| + root_window_->AddPreTargetHandler(this); |
| +} |
| + |
| +void TouchExplorationController::GenerateMouseEvent(ui::EventType event_type, |
| + gfx::Point location, |
| + int flags) { |
| + aura::Window* root_window = wm::GetRootWindowAt(location); |
| + DCHECK(root_window) |
| + << "Root window not found while converting touch to mouse event."; |
| + aura::WindowTreeHost* host = root_window->GetHost(); |
| + |
| + LOG(ERROR) << "Generating mouse event: type=" << event_type; |
| + ui::MouseEvent mouse_event(event_type, |
| + location, |
| + location, |
| + ui::EF_IS_SYNTHESIZED | flags, |
| + 0); |
| + |
| + // TODO: Should I use WindowEventDispatcher instead? |
|
mfomitchev
2014/04/11 21:00:58
Question here
sadrul
2014/04/14 20:22:11
This is fine.
|
| + host->event_processor()->OnEventFromSource(&mouse_event); |
| +} |
| + |
| +} // namespace internal |
| +} // namespace ash |