ui::PlatformWindowDelegate::OnClosed() isn't called when a ui::X11Window is closed
[chromium-blink-merge.git] / ash / autoclick / autoclick_controller.cc
blobd331f70fc165b21abf5c7b8418bb11c383be28a1
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/gfx/point.h"
17 #include "ui/gfx/vector2d.h"
18 #include "ui/wm/core/coordinate_conversion.h"
20 namespace ash {
22 namespace {
24 // The threshold of mouse movement measured in DIP that will
25 // initiate a new autoclick.
26 const int kMovementThreshold = 20;
28 bool IsModifierKey(ui::KeyboardCode key_code) {
29 return key_code == ui::VKEY_SHIFT ||
30 key_code == ui::VKEY_LSHIFT ||
31 key_code == ui::VKEY_CONTROL ||
32 key_code == ui::VKEY_LCONTROL ||
33 key_code == ui::VKEY_RCONTROL ||
34 key_code == ui::VKEY_MENU ||
35 key_code == ui::VKEY_LMENU ||
36 key_code == ui::VKEY_RMENU;
39 } // namespace
41 // static.
42 const int AutoclickController::kDefaultAutoclickDelayMs = 400;
44 class AutoclickControllerImpl : public AutoclickController,
45 public ui::EventHandler {
46 public:
47 AutoclickControllerImpl();
48 virtual ~AutoclickControllerImpl();
50 private:
51 // AutoclickController overrides:
52 virtual void SetEnabled(bool enabled) override;
53 virtual bool IsEnabled() const override;
54 virtual void SetAutoclickDelay(int delay_ms) override;
55 virtual int GetAutoclickDelay() const override;
57 // ui::EventHandler overrides:
58 virtual void OnMouseEvent(ui::MouseEvent* event) override;
59 virtual void OnKeyEvent(ui::KeyEvent* event) override;
60 virtual void OnTouchEvent(ui::TouchEvent* event) override;
61 virtual void OnGestureEvent(ui::GestureEvent* event) override;
62 virtual void OnScrollEvent(ui::ScrollEvent* event) override;
64 void InitClickTimer();
66 void DoAutoclick();
68 bool enabled_;
69 int delay_ms_;
70 int mouse_event_flags_;
71 scoped_ptr<base::Timer> autoclick_timer_;
72 // The position in screen coordinates used to determine
73 // the distance the mouse has moved.
74 gfx::Point anchor_location_;
76 DISALLOW_COPY_AND_ASSIGN(AutoclickControllerImpl);
80 AutoclickControllerImpl::AutoclickControllerImpl()
81 : enabled_(false),
82 delay_ms_(kDefaultAutoclickDelayMs),
83 mouse_event_flags_(ui::EF_NONE),
84 anchor_location_(-kMovementThreshold, -kMovementThreshold) {
85 InitClickTimer();
88 AutoclickControllerImpl::~AutoclickControllerImpl() {
91 void AutoclickControllerImpl::SetEnabled(bool enabled) {
92 if (enabled_ == enabled)
93 return;
94 enabled_ = enabled;
96 if (enabled_) {
97 Shell::GetInstance()->AddPreTargetHandler(this);
98 autoclick_timer_->Stop();
99 } else {
100 Shell::GetInstance()->RemovePreTargetHandler(this);
104 bool AutoclickControllerImpl::IsEnabled() const {
105 return enabled_;
108 void AutoclickControllerImpl::SetAutoclickDelay(int delay_ms) {
109 delay_ms_ = delay_ms;
110 InitClickTimer();
113 int AutoclickControllerImpl::GetAutoclickDelay() const {
114 return delay_ms_;
117 void AutoclickControllerImpl::InitClickTimer() {
118 autoclick_timer_.reset(new base::Timer(
119 FROM_HERE,
120 base::TimeDelta::FromMilliseconds(delay_ms_),
121 base::Bind(&AutoclickControllerImpl::DoAutoclick,
122 base::Unretained(this)),
123 false));
126 void AutoclickControllerImpl::OnMouseEvent(ui::MouseEvent* event) {
127 if (event->type() == ui::ET_MOUSE_MOVED &&
128 !(event->flags() & ui::EF_IS_SYNTHESIZED)) {
129 mouse_event_flags_ = event->flags();
131 gfx::Point mouse_location = event->root_location();
132 ::wm::ConvertPointToScreen(wm::GetRootWindowAt(mouse_location),
133 &mouse_location);
135 // The distance between the mouse location and the anchor location
136 // must exceed a certain threshold to initiate a new autoclick countdown.
137 // This ensures that mouse jitter caused by poor motor control does not
138 // 1. initiate an unwanted autoclick from rest
139 // 2. prevent the autoclick from ever occuring when the mouse
140 // arrives at the target.
141 gfx::Vector2d delta = mouse_location - anchor_location_;
142 if (delta.LengthSquared() >= kMovementThreshold * kMovementThreshold) {
143 anchor_location_ = event->root_location();
144 autoclick_timer_->Reset();
146 } else if (event->type() == ui::ET_MOUSE_PRESSED) {
147 autoclick_timer_->Stop();
148 } else if (event->type() == ui::ET_MOUSEWHEEL &&
149 autoclick_timer_->IsRunning()) {
150 autoclick_timer_->Reset();
154 void AutoclickControllerImpl::OnKeyEvent(ui::KeyEvent* event) {
155 int modifier_mask =
156 ui::EF_SHIFT_DOWN |
157 ui::EF_CONTROL_DOWN |
158 ui::EF_ALT_DOWN |
159 ui::EF_COMMAND_DOWN |
160 ui::EF_EXTENDED;
161 int new_modifiers = event->flags() & modifier_mask;
162 mouse_event_flags_ = (mouse_event_flags_ & ~modifier_mask) | new_modifiers;
164 if (!IsModifierKey(event->key_code()))
165 autoclick_timer_->Stop();
168 void AutoclickControllerImpl::OnTouchEvent(ui::TouchEvent* event) {
169 autoclick_timer_->Stop();
172 void AutoclickControllerImpl::OnGestureEvent(ui::GestureEvent* event) {
173 autoclick_timer_->Stop();
176 void AutoclickControllerImpl::OnScrollEvent(ui::ScrollEvent* event) {
177 autoclick_timer_->Stop();
180 void AutoclickControllerImpl::DoAutoclick() {
181 gfx::Point screen_location =
182 aura::Env::GetInstance()->last_mouse_location();
183 aura::Window* root_window = wm::GetRootWindowAt(screen_location);
184 DCHECK(root_window) << "Root window not found while attempting autoclick.";
186 gfx::Point click_location(screen_location);
187 anchor_location_ = click_location;
188 ::wm::ConvertPointFromScreen(root_window, &click_location);
190 aura::WindowTreeHost* host = root_window->GetHost();
191 host->ConvertPointToHost(&click_location);
193 ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED,
194 click_location,
195 click_location,
196 mouse_event_flags_ | ui::EF_LEFT_MOUSE_BUTTON,
197 ui::EF_LEFT_MOUSE_BUTTON);
198 ui::MouseEvent release_event(ui::ET_MOUSE_RELEASED,
199 click_location,
200 click_location,
201 mouse_event_flags_ | ui::EF_LEFT_MOUSE_BUTTON,
202 ui::EF_LEFT_MOUSE_BUTTON);
204 ui::EventDispatchDetails details =
205 host->event_processor()->OnEventFromSource(&press_event);
206 if (!details.dispatcher_destroyed)
207 details = host->event_processor()->OnEventFromSource(&release_event);
208 if (details.dispatcher_destroyed)
209 return;
212 // static.
213 AutoclickController* AutoclickController::CreateInstance() {
214 return new AutoclickControllerImpl();
217 } // namespace ash