Reorder permission message rules, so that related rules appear together.
[chromium-blink-merge.git] / ash / autoclick / autoclick_controller.cc
blob39d1b020d6db22ef54fe7fcee064579028687d40
1 // Copyright 2013 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.
5 #include "ash/autoclick/autoclick_controller.h"
7 #include "ash/shell.h"
8 #include "ash/wm/coordinate_conversion.h"
9 #include "base/timer/timer.h"
10 #include "ui/aura/env.h"
11 #include "ui/aura/window_tree_host.h"
12 #include "ui/events/event.h"
13 #include "ui/events/event_constants.h"
14 #include "ui/events/event_handler.h"
15 #include "ui/events/event_processor.h"
16 #include "ui/events/event_utils.h"
17 #include "ui/gfx/geometry/point.h"
18 #include "ui/gfx/geometry/vector2d.h"
19 #include "ui/wm/core/coordinate_conversion.h"
21 namespace ash {
23 namespace {
25 // The threshold of mouse movement measured in DIP that will
26 // initiate a new autoclick.
27 const int kMovementThreshold = 20;
29 bool IsModifierKey(ui::KeyboardCode key_code) {
30 return key_code == ui::VKEY_SHIFT ||
31 key_code == ui::VKEY_LSHIFT ||
32 key_code == ui::VKEY_CONTROL ||
33 key_code == ui::VKEY_LCONTROL ||
34 key_code == ui::VKEY_RCONTROL ||
35 key_code == ui::VKEY_MENU ||
36 key_code == ui::VKEY_LMENU ||
37 key_code == ui::VKEY_RMENU;
40 } // namespace
42 // static.
43 const int AutoclickController::kDefaultAutoclickDelayMs = 400;
45 class AutoclickControllerImpl : public AutoclickController,
46 public ui::EventHandler {
47 public:
48 AutoclickControllerImpl();
49 ~AutoclickControllerImpl() override;
51 private:
52 // AutoclickController overrides:
53 void SetEnabled(bool enabled) override;
54 bool IsEnabled() const override;
55 void SetAutoclickDelay(int delay_ms) override;
56 int GetAutoclickDelay() const override;
58 // ui::EventHandler overrides:
59 void OnMouseEvent(ui::MouseEvent* event) override;
60 void OnKeyEvent(ui::KeyEvent* event) override;
61 void OnTouchEvent(ui::TouchEvent* event) override;
62 void OnGestureEvent(ui::GestureEvent* event) override;
63 void OnScrollEvent(ui::ScrollEvent* event) override;
65 void InitClickTimer();
67 void DoAutoclick();
69 bool enabled_;
70 int delay_ms_;
71 int mouse_event_flags_;
72 scoped_ptr<base::Timer> autoclick_timer_;
73 // The position in screen coordinates used to determine
74 // the distance the mouse has moved.
75 gfx::Point anchor_location_;
77 DISALLOW_COPY_AND_ASSIGN(AutoclickControllerImpl);
81 AutoclickControllerImpl::AutoclickControllerImpl()
82 : enabled_(false),
83 delay_ms_(kDefaultAutoclickDelayMs),
84 mouse_event_flags_(ui::EF_NONE),
85 anchor_location_(-kMovementThreshold, -kMovementThreshold) {
86 InitClickTimer();
89 AutoclickControllerImpl::~AutoclickControllerImpl() {
92 void AutoclickControllerImpl::SetEnabled(bool enabled) {
93 if (enabled_ == enabled)
94 return;
95 enabled_ = enabled;
97 if (enabled_) {
98 Shell::GetInstance()->AddPreTargetHandler(this);
99 autoclick_timer_->Stop();
100 } else {
101 Shell::GetInstance()->RemovePreTargetHandler(this);
105 bool AutoclickControllerImpl::IsEnabled() const {
106 return enabled_;
109 void AutoclickControllerImpl::SetAutoclickDelay(int delay_ms) {
110 delay_ms_ = delay_ms;
111 InitClickTimer();
114 int AutoclickControllerImpl::GetAutoclickDelay() const {
115 return delay_ms_;
118 void AutoclickControllerImpl::InitClickTimer() {
119 autoclick_timer_.reset(new base::Timer(
120 FROM_HERE,
121 base::TimeDelta::FromMilliseconds(delay_ms_),
122 base::Bind(&AutoclickControllerImpl::DoAutoclick,
123 base::Unretained(this)),
124 false));
127 void AutoclickControllerImpl::OnMouseEvent(ui::MouseEvent* event) {
128 if (event->type() == ui::ET_MOUSE_MOVED &&
129 !(event->flags() & ui::EF_IS_SYNTHESIZED)) {
130 mouse_event_flags_ = event->flags();
132 gfx::Point mouse_location = event->location();
133 ::wm::ConvertPointToScreen(static_cast<aura::Window*>(event->target()),
134 &mouse_location);
136 // The distance between the mouse location and the anchor location
137 // must exceed a certain threshold to initiate a new autoclick countdown.
138 // This ensures that mouse jitter caused by poor motor control does not
139 // 1. initiate an unwanted autoclick from rest
140 // 2. prevent the autoclick from ever occuring when the mouse
141 // arrives at the target.
142 gfx::Vector2d delta = mouse_location - anchor_location_;
143 if (delta.LengthSquared() >= kMovementThreshold * kMovementThreshold) {
144 anchor_location_ = mouse_location;
145 autoclick_timer_->Reset();
147 } else if (event->type() == ui::ET_MOUSE_PRESSED) {
148 autoclick_timer_->Stop();
149 } else if (event->type() == ui::ET_MOUSEWHEEL &&
150 autoclick_timer_->IsRunning()) {
151 autoclick_timer_->Reset();
155 void AutoclickControllerImpl::OnKeyEvent(ui::KeyEvent* event) {
156 int modifier_mask =
157 ui::EF_SHIFT_DOWN |
158 ui::EF_CONTROL_DOWN |
159 ui::EF_ALT_DOWN |
160 ui::EF_COMMAND_DOWN |
161 ui::EF_EXTENDED;
162 int new_modifiers = event->flags() & modifier_mask;
163 mouse_event_flags_ = (mouse_event_flags_ & ~modifier_mask) | new_modifiers;
165 if (!IsModifierKey(event->key_code()))
166 autoclick_timer_->Stop();
169 void AutoclickControllerImpl::OnTouchEvent(ui::TouchEvent* event) {
170 autoclick_timer_->Stop();
173 void AutoclickControllerImpl::OnGestureEvent(ui::GestureEvent* event) {
174 autoclick_timer_->Stop();
177 void AutoclickControllerImpl::OnScrollEvent(ui::ScrollEvent* event) {
178 autoclick_timer_->Stop();
181 void AutoclickControllerImpl::DoAutoclick() {
182 gfx::Point screen_location =
183 aura::Env::GetInstance()->last_mouse_location();
184 aura::Window* root_window = wm::GetRootWindowAt(screen_location);
185 DCHECK(root_window) << "Root window not found while attempting autoclick.";
187 gfx::Point click_location(screen_location);
188 anchor_location_ = click_location;
190 ::wm::ConvertPointFromScreen(root_window, &click_location);
191 aura::WindowTreeHost* host = root_window->GetHost();
192 host->ConvertPointToHost(&click_location);
194 ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, click_location,
195 click_location, ui::EventTimeForNow(),
196 mouse_event_flags_ | ui::EF_LEFT_MOUSE_BUTTON,
197 ui::EF_LEFT_MOUSE_BUTTON);
198 ui::MouseEvent release_event(ui::ET_MOUSE_RELEASED, click_location,
199 click_location, ui::EventTimeForNow(),
200 mouse_event_flags_ | ui::EF_LEFT_MOUSE_BUTTON,
201 ui::EF_LEFT_MOUSE_BUTTON);
203 ui::EventDispatchDetails details =
204 host->event_processor()->OnEventFromSource(&press_event);
205 if (!details.dispatcher_destroyed)
206 details = host->event_processor()->OnEventFromSource(&release_event);
207 if (details.dispatcher_destroyed)
208 return;
211 // static.
212 AutoclickController* AutoclickController::CreateInstance() {
213 return new AutoclickControllerImpl();
216 } // namespace ash