blob: 0cf79e90e0d8f431642d0a539c703a779058c9d3 [file] [log] [blame]
// Copyright 2013 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/autoclick/autoclick_controller.h"
#include "ash/aura/wm_window_aura.h"
#include "ash/autoclick/common/autoclick_controller_common.h"
#include "ash/autoclick/common/autoclick_controller_common_delegate.h"
#include "ash/common/wm/root_window_finder.h"
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/shell.h"
#include "base/timer/timer.h"
#include "ui/aura/window_observer.h"
#include "ui/aura/window_tree_host.h"
#include "ui/events/event.h"
#include "ui/events/event_handler.h"
#include "ui/events/event_processor.h"
#include "ui/events/event_utils.h"
#include "ui/views/widget/widget.h"
#include "ui/wm/core/coordinate_conversion.h"
namespace ash {
// static.
base::TimeDelta AutoclickController::GetDefaultAutoclickDelay() {
return base::TimeDelta::FromMilliseconds(int64_t{kDefaultAutoclickDelayMs});
}
const int AutoclickController::kDefaultAutoclickDelayMs = 1000;
class AutoclickControllerImpl : public AutoclickController,
public ui::EventHandler,
public AutoclickControllerCommonDelegate,
public aura::WindowObserver {
public:
AutoclickControllerImpl();
~AutoclickControllerImpl() override;
private:
void SetTapDownTarget(aura::Window* target);
// AutoclickController overrides:
void SetEnabled(bool enabled) override;
bool IsEnabled() const override;
void SetAutoclickDelay(base::TimeDelta delay) override;
// ui::EventHandler overrides:
void OnMouseEvent(ui::MouseEvent* event) override;
void OnKeyEvent(ui::KeyEvent* event) override;
void OnTouchEvent(ui::TouchEvent* event) override;
void OnGestureEvent(ui::GestureEvent* event) override;
void OnScrollEvent(ui::ScrollEvent* event) override;
// AutoclickControllerCommonDelegate overrides:
views::Widget* CreateAutoclickRingWidget(
const gfx::Point& event_location) override;
void UpdateAutoclickRingWidget(views::Widget* widget,
const gfx::Point& event_location) override;
void DoAutoclick(const gfx::Point& event_location,
const int mouse_event_flags) override;
void OnAutoclickCanceled() override;
// aura::WindowObserver overrides:
void OnWindowDestroying(aura::Window* window) override;
bool enabled_;
// The target window is observed by AutoclickControllerImpl for the duration
// of a autoclick gesture.
aura::Window* tap_down_target_;
std::unique_ptr<views::Widget> widget_;
std::unique_ptr<AutoclickControllerCommon> autoclick_controller_common_;
DISALLOW_COPY_AND_ASSIGN(AutoclickControllerImpl);
};
AutoclickControllerImpl::AutoclickControllerImpl()
: enabled_(false),
tap_down_target_(nullptr),
autoclick_controller_common_(
new AutoclickControllerCommon(GetDefaultAutoclickDelay(), this)) {}
AutoclickControllerImpl::~AutoclickControllerImpl() {
SetTapDownTarget(nullptr);
}
void AutoclickControllerImpl::SetTapDownTarget(aura::Window* target) {
if (tap_down_target_ == target)
return;
if (tap_down_target_)
tap_down_target_->RemoveObserver(this);
tap_down_target_ = target;
if (tap_down_target_)
tap_down_target_->AddObserver(this);
}
void AutoclickControllerImpl::SetEnabled(bool enabled) {
if (enabled_ == enabled)
return;
enabled_ = enabled;
if (enabled_) {
Shell::GetInstance()->AddPreTargetHandler(this);
autoclick_controller_common_->CancelAutoclick();
} else {
Shell::GetInstance()->RemovePreTargetHandler(this);
}
}
bool AutoclickControllerImpl::IsEnabled() const {
return enabled_;
}
void AutoclickControllerImpl::SetAutoclickDelay(base::TimeDelta delay) {
autoclick_controller_common_->SetAutoclickDelay(delay);
}
void AutoclickControllerImpl::OnMouseEvent(ui::MouseEvent* event) {
autoclick_controller_common_->HandleMouseEvent(*event);
}
void AutoclickControllerImpl::OnKeyEvent(ui::KeyEvent* event) {
autoclick_controller_common_->HandleKeyEvent(*event);
}
void AutoclickControllerImpl::OnTouchEvent(ui::TouchEvent* event) {
autoclick_controller_common_->CancelAutoclick();
}
void AutoclickControllerImpl::OnGestureEvent(ui::GestureEvent* event) {
autoclick_controller_common_->CancelAutoclick();
}
void AutoclickControllerImpl::OnScrollEvent(ui::ScrollEvent* event) {
autoclick_controller_common_->CancelAutoclick();
}
views::Widget* AutoclickControllerImpl::CreateAutoclickRingWidget(
const gfx::Point& event_location) {
aura::Window* target =
WmWindowAura::GetAuraWindow(ash::wm::GetRootWindowAt(event_location));
SetTapDownTarget(target);
aura::Window* root_window = target->GetRootWindow();
widget_.reset(new views::Widget);
views::Widget::InitParams params;
params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS;
params.accept_events = false;
params.activatable = views::Widget::InitParams::ACTIVATABLE_NO;
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.context = root_window;
params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
params.parent =
Shell::GetContainer(root_window, kShellWindowId_OverlayContainer);
widget_->Init(params);
widget_->SetOpacity(1.f);
return widget_.get();
}
void AutoclickControllerImpl::UpdateAutoclickRingWidget(
views::Widget* widget,
const gfx::Point& event_location) {
aura::Window* target =
WmWindowAura::GetAuraWindow(ash::wm::GetRootWindowAt(event_location));
SetTapDownTarget(target);
aura::Window* root_window = target->GetRootWindow();
if (widget->GetNativeView()->GetRootWindow() != root_window) {
views::Widget::ReparentNativeView(
widget->GetNativeView(),
Shell::GetContainer(root_window, kShellWindowId_OverlayContainer));
}
}
void AutoclickControllerImpl::DoAutoclick(const gfx::Point& event_location,
const int mouse_event_flags) {
aura::Window* root_window =
WmWindowAura::GetAuraWindow(wm::GetRootWindowAt(event_location));
DCHECK(root_window) << "Root window not found while attempting autoclick.";
gfx::Point click_location(event_location);
::wm::ConvertPointFromScreen(root_window, &click_location);
aura::WindowTreeHost* host = root_window->GetHost();
host->ConvertPointToHost(&click_location);
ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, click_location,
click_location, ui::EventTimeForNow(),
mouse_event_flags | ui::EF_LEFT_MOUSE_BUTTON,
ui::EF_LEFT_MOUSE_BUTTON);
ui::MouseEvent release_event(ui::ET_MOUSE_RELEASED, click_location,
click_location, ui::EventTimeForNow(),
mouse_event_flags | ui::EF_LEFT_MOUSE_BUTTON,
ui::EF_LEFT_MOUSE_BUTTON);
ui::EventDispatchDetails details =
host->event_processor()->OnEventFromSource(&press_event);
if (!details.dispatcher_destroyed)
details = host->event_processor()->OnEventFromSource(&release_event);
if (details.dispatcher_destroyed)
return;
}
void AutoclickControllerImpl::OnAutoclickCanceled() {
SetTapDownTarget(nullptr);
}
void AutoclickControllerImpl::OnWindowDestroying(aura::Window* window) {
DCHECK_EQ(tap_down_target_, window);
autoclick_controller_common_->CancelAutoclick();
}
// static.
AutoclickController* AutoclickController::CreateInstance() {
return new AutoclickControllerImpl();
}
} // namespace ash