Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / ash / autoclick / autoclick_controller.cc
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.
4
5 #include "ash/autoclick/autoclick_controller.h"
6
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"
19
20 namespace ash {
21
22 namespace {
23
24 // The threshold of mouse movement measured in DIP that will
25 // initiate a new autoclick.
26 const int kMovementThreshold = 20;
27
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;
37 }
38
39 }  // namespace
40
41 // static.
42 const int AutoclickController::kDefaultAutoclickDelayMs = 400;
43
44 class AutoclickControllerImpl : public AutoclickController,
45                                 public ui::EventHandler {
46  public:
47   AutoclickControllerImpl();
48   ~AutoclickControllerImpl() override;
49
50  private:
51   // AutoclickController overrides:
52   void SetEnabled(bool enabled) override;
53   bool IsEnabled() const override;
54   void SetAutoclickDelay(int delay_ms) override;
55   int GetAutoclickDelay() const override;
56
57   // ui::EventHandler overrides:
58   void OnMouseEvent(ui::MouseEvent* event) override;
59   void OnKeyEvent(ui::KeyEvent* event) override;
60   void OnTouchEvent(ui::TouchEvent* event) override;
61   void OnGestureEvent(ui::GestureEvent* event) override;
62   void OnScrollEvent(ui::ScrollEvent* event) override;
63
64   void InitClickTimer();
65
66   void DoAutoclick();
67
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_;
75
76   DISALLOW_COPY_AND_ASSIGN(AutoclickControllerImpl);
77 };
78
79
80 AutoclickControllerImpl::AutoclickControllerImpl()
81     : enabled_(false),
82       delay_ms_(kDefaultAutoclickDelayMs),
83       mouse_event_flags_(ui::EF_NONE),
84       anchor_location_(-kMovementThreshold, -kMovementThreshold) {
85   InitClickTimer();
86 }
87
88 AutoclickControllerImpl::~AutoclickControllerImpl() {
89 }
90
91 void AutoclickControllerImpl::SetEnabled(bool enabled) {
92   if (enabled_ == enabled)
93     return;
94   enabled_ = enabled;
95
96   if (enabled_) {
97     Shell::GetInstance()->AddPreTargetHandler(this);
98     autoclick_timer_->Stop();
99   } else {
100     Shell::GetInstance()->RemovePreTargetHandler(this);
101   }
102 }
103
104 bool AutoclickControllerImpl::IsEnabled() const {
105   return enabled_;
106 }
107
108 void AutoclickControllerImpl::SetAutoclickDelay(int delay_ms) {
109   delay_ms_ = delay_ms;
110   InitClickTimer();
111 }
112
113 int AutoclickControllerImpl::GetAutoclickDelay() const {
114   return delay_ms_;
115 }
116
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));
124 }
125
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();
130
131     gfx::Point mouse_location = event->root_location();
132     ::wm::ConvertPointToScreen(wm::GetRootWindowAt(mouse_location),
133                                &mouse_location);
134
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();
145     }
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();
151   }
152 }
153
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;
163
164   if (!IsModifierKey(event->key_code()))
165     autoclick_timer_->Stop();
166 }
167
168 void AutoclickControllerImpl::OnTouchEvent(ui::TouchEvent* event) {
169   autoclick_timer_->Stop();
170 }
171
172 void AutoclickControllerImpl::OnGestureEvent(ui::GestureEvent* event) {
173   autoclick_timer_->Stop();
174 }
175
176 void AutoclickControllerImpl::OnScrollEvent(ui::ScrollEvent* event) {
177   autoclick_timer_->Stop();
178 }
179
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.";
185
186   gfx::Point click_location(screen_location);
187   anchor_location_ = click_location;
188   ::wm::ConvertPointFromScreen(root_window, &click_location);
189
190   aura::WindowTreeHost* host = root_window->GetHost();
191   host->ConvertPointToHost(&click_location);
192
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);
203
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;
210 }
211
212 // static.
213 AutoclickController* AutoclickController::CreateInstance() {
214   return new AutoclickControllerImpl();
215 }
216
217 }  // namespace ash