Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / ash / sticky_keys / sticky_keys_unittest.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/sticky_keys/sticky_keys_controller.h"
6
7 #include <X11/Xlib.h>
8 #undef None
9 #undef Bool
10 #undef RootWindow
11
12 #include "ash/shell.h"
13 #include "ash/test/ash_test_base.h"
14 #include "base/bind.h"
15 #include "base/callback.h"
16 #include "base/memory/scoped_vector.h"
17 #include "ui/aura/window.h"
18 #include "ui/aura/window_tree_host.h"
19 #include "ui/events/event_source.h"
20 #include "ui/events/test/events_test_utils_x11.h"
21
22 namespace ash {
23
24 namespace {
25
26 // The device id of the test touchpad device.
27 const unsigned int kTouchPadDeviceId = 1;
28
29 }  // namespace
30
31 class StickyKeysTest : public test::AshTestBase {
32  protected:
33   StickyKeysTest()
34       : target_(NULL),
35         root_window_(NULL) {}
36
37   virtual void SetUp() override {
38     test::AshTestBase::SetUp();
39
40     // |target_| owned by root window of shell. It is still safe to delete
41     // it ourselves.
42     target_ = CreateTestWindowInShellWithId(0);
43     root_window_ = target_->GetRootWindow();
44
45     ui::SetUpTouchPadForTest(kTouchPadDeviceId);
46   }
47
48   virtual void TearDown() override {
49     test::AshTestBase::TearDown();
50   }
51
52   virtual void OnShortcutPressed() {
53     if (target_) {
54       delete target_;
55       target_ = NULL;
56     }
57   }
58
59   ui::KeyEvent* GenerateKey(ui::EventType type, ui::KeyboardCode code) {
60     scoped_xevent_.InitKeyEvent(type, code, 0);
61     ui::KeyEvent* event = new ui::KeyEvent(scoped_xevent_);
62     return event;
63   }
64
65   // Creates a mouse event backed by a native XInput2 generic button event.
66   // This is the standard native event on Chromebooks.
67   ui::MouseEvent* GenerateMouseEvent(ui::EventType type) {
68     return GenerateMouseEventAt(type, gfx::Point());
69   }
70
71   // Creates a mouse event backed by a native XInput2 generic button event.
72   // The |location| should be in physical pixels.
73   ui::MouseEvent* GenerateMouseEventAt(ui::EventType type,
74                                        const gfx::Point& location) {
75     scoped_xevent_.InitGenericButtonEvent(
76         kTouchPadDeviceId,
77         type,
78         location,
79         0);
80     ui::MouseEvent* event = new ui::MouseEvent(scoped_xevent_);
81     return event;
82   }
83
84   ui::MouseWheelEvent* GenerateMouseWheelEvent(int wheel_delta) {
85     EXPECT_NE(0, wheel_delta);
86     scoped_xevent_.InitGenericMouseWheelEvent(
87         kTouchPadDeviceId, wheel_delta, 0);
88     ui::MouseWheelEvent* event = new ui::MouseWheelEvent(scoped_xevent_);
89     ui::Event::DispatcherApi dispatcher(event);
90     dispatcher.set_target(target_);
91     return event;
92   }
93
94   ui::ScrollEvent* GenerateScrollEvent(int scroll_delta) {
95     scoped_xevent_.InitScrollEvent(kTouchPadDeviceId, // deviceid
96                                    0,               // x_offset
97                                    scroll_delta,    // y_offset
98                                    0,               // x_offset_ordinal
99                                    scroll_delta,    // y_offset_ordinal
100                                    2);              // finger_count
101     ui::ScrollEvent* event = new ui::ScrollEvent(scoped_xevent_);
102     ui::Event::DispatcherApi dispatcher(event);
103     dispatcher.set_target(target_);
104     return event;
105   }
106
107   ui::ScrollEvent* GenerateFlingScrollEvent(int fling_delta,
108                                             bool is_cancel) {
109     scoped_xevent_.InitFlingScrollEvent(
110         kTouchPadDeviceId, // deviceid
111         0,               // x_velocity
112         fling_delta,     // y_velocity
113         0,               // x_velocity_ordinal
114         fling_delta,     // y_velocity_ordinal
115         is_cancel);      // is_cancel
116     ui::ScrollEvent* event = new ui::ScrollEvent(scoped_xevent_);
117     ui::Event::DispatcherApi dispatcher(event);
118     dispatcher.set_target(target_);
119     return event;
120   }
121
122   // Creates a synthesized KeyEvent that is not backed by a native event.
123   ui::KeyEvent* GenerateSynthesizedKeyEvent(ui::EventType type,
124                                             ui::KeyboardCode code) {
125     return new ui::KeyEvent(type, code, ui::EF_NONE);
126   }
127
128   // Creates a synthesized MouseEvent that is not backed by a native event.
129   ui::MouseEvent* GenerateSynthesizedMouseEventAt(ui::EventType event_type,
130                                                   const gfx::Point& location) {
131     ui::MouseEvent* event = new ui::MouseEvent(event_type,
132                                                location,
133                                                location,
134                                                ui::EF_LEFT_MOUSE_BUTTON,
135                                                ui::EF_LEFT_MOUSE_BUTTON);
136     ui::Event::DispatcherApi dispatcher(event);
137     dispatcher.set_target(target_);
138     return event;
139   }
140
141   // Creates a synthesized mouse press or release event.
142   ui::MouseEvent* GenerateSynthesizedMouseClickEvent(
143       ui::EventType type,
144       const gfx::Point& location) {
145     return GenerateSynthesizedMouseEventAt(type, location);
146   }
147
148   // Creates a synthesized ET_MOUSE_MOVED event.
149   ui::MouseEvent* GenerateSynthesizedMouseMoveEvent(
150       const gfx::Point& location) {
151     return GenerateSynthesizedMouseEventAt(ui::ET_MOUSE_MOVED, location);
152   }
153
154   // Creates a synthesized MouseWHeel event.
155   ui::MouseWheelEvent* GenerateSynthesizedMouseWheelEvent(int wheel_delta) {
156     scoped_ptr<ui::MouseEvent> mev(
157         GenerateSynthesizedMouseEventAt(ui::ET_MOUSEWHEEL, gfx::Point(0, 0)));
158     ui::MouseWheelEvent* event = new ui::MouseWheelEvent(*mev, 0, wheel_delta);
159     ui::Event::DispatcherApi dispatcher(event);
160     dispatcher.set_target(target_);
161     return event;
162   }
163
164   void SendActivateStickyKeyPattern(StickyKeysHandler* handler,
165                                     ui::KeyboardCode key_code) {
166     bool released = false;
167     int down_flags = 0;
168     scoped_ptr<ui::KeyEvent> ev;
169     ev.reset(GenerateKey(ui::ET_KEY_PRESSED, key_code));
170     handler->HandleKeyEvent(*ev.get(), key_code, &down_flags, &released);
171     ev.reset(GenerateKey(ui::ET_KEY_RELEASED, key_code));
172     handler->HandleKeyEvent(*ev.get(), key_code, &down_flags, &released);
173   }
174
175   bool HandleKeyEvent(const ui::KeyEvent& key_event,
176                       StickyKeysHandler* handler,
177                       int* down,
178                       bool* up) {
179     return handler->HandleKeyEvent(key_event, key_event.key_code(), down, up);
180   }
181
182   int HandleKeyEventForDownFlags(const ui::KeyEvent& key_event,
183                                  StickyKeysHandler* handler) {
184     bool released = false;
185     int down = 0;
186     handler->HandleKeyEvent(key_event, key_event.key_code(), &down, &released);
187     return down;
188   }
189
190   aura::Window* target() { return target_; }
191
192  private:
193   // Owned by root window of shell, but we can still delete |target_| safely.
194   aura::Window* target_;
195   // The root window of |target_|. Not owned.
196   aura::Window* root_window_;
197
198   // Used to construct the various X events.
199   ui::ScopedXI2Event scoped_xevent_;
200
201   DISALLOW_COPY_AND_ASSIGN(StickyKeysTest);
202 };
203
204 TEST_F(StickyKeysTest, BasicOneshotScenarioTest) {
205   scoped_ptr<ui::KeyEvent> ev;
206   StickyKeysHandler sticky_key(ui::EF_SHIFT_DOWN);
207
208   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
209
210   // By typing Shift key, internal state become ENABLED.
211   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
212   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
213
214   ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_A));
215   bool released = false;
216   int mod_down_flags = 0;
217   HandleKeyEvent(*ev.get(), &sticky_key, &mod_down_flags, &released);
218   // Next keyboard event is shift modified.
219   EXPECT_TRUE(mod_down_flags & ui::EF_SHIFT_DOWN);
220   // Modifier release notification happens.
221   EXPECT_TRUE(released);
222
223   ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_A));
224   released = false;
225   mod_down_flags = 0;
226   HandleKeyEvent(*ev.get(), &sticky_key, &mod_down_flags, &released);
227
228   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
229   // Making sure Shift up keyboard event is available.
230   scoped_ptr<ui::Event> up_event;
231   ASSERT_EQ(0, sticky_key.GetModifierUpEvent(&up_event));
232   EXPECT_TRUE(up_event.get());
233   EXPECT_EQ(ui::ET_KEY_RELEASED, up_event->type());
234   EXPECT_EQ(ui::VKEY_SHIFT,
235             static_cast<const ui::KeyEvent*>(up_event.get())->key_code());
236
237   // Enabled state is one shot, so next key event should not be shift modified.
238   ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_A));
239   mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
240   EXPECT_FALSE(mod_down_flags & ui::EF_SHIFT_DOWN);
241
242   ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_A));
243   mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
244   EXPECT_FALSE(mod_down_flags & ui::EF_SHIFT_DOWN);
245 }
246
247 TEST_F(StickyKeysTest, BasicLockedScenarioTest) {
248   scoped_ptr<ui::KeyEvent> ev;
249   StickyKeysHandler sticky_key(ui::EF_SHIFT_DOWN);
250
251   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
252
253   // By typing shift key, internal state become ENABLED.
254   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
255   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
256
257   // By typing shift key again, internal state become LOCKED.
258   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
259   EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
260
261   // All keyboard events including keyUp become shift modified.
262   ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_A));
263   int mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
264   EXPECT_TRUE(mod_down_flags & ui::EF_SHIFT_DOWN);
265
266   ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_A));
267   mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
268   EXPECT_TRUE(mod_down_flags & ui::EF_SHIFT_DOWN);
269
270   // Locked state keeps after normal keyboard event.
271   EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
272
273   ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_B));
274   mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
275   EXPECT_TRUE(mod_down_flags & ui::EF_SHIFT_DOWN);
276
277   ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_B));
278   mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
279   EXPECT_TRUE(mod_down_flags & ui::EF_SHIFT_DOWN);
280
281   EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
282
283   // By typing shift key again, internal state become back to DISABLED.
284   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
285   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
286 }
287
288 TEST_F(StickyKeysTest, NonTargetModifierTest) {
289   scoped_ptr<ui::KeyEvent> ev;
290   StickyKeysHandler sticky_key(ui::EF_SHIFT_DOWN);
291
292   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
293
294   // Non target modifier key does not affect internal state
295   ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_MENU));
296   int mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
297   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
298   EXPECT_EQ(ui::EF_NONE, mod_down_flags);
299
300   ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_MENU));
301   mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
302   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
303   EXPECT_EQ(ui::EF_NONE, mod_down_flags);
304
305   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
306   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
307
308   // Non target modifier key does not affect internal state
309   ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_MENU));
310   mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
311   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
312   EXPECT_EQ(ui::EF_NONE, mod_down_flags);
313
314   ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_MENU));
315   mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
316   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
317   EXPECT_EQ(ui::EF_NONE, mod_down_flags);
318
319   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
320   EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
321
322   // Non target modifier key does not affect internal state
323   ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_MENU));
324   mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
325   EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
326   EXPECT_EQ(ui::EF_NONE, mod_down_flags);
327
328   ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_MENU));
329   mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
330   EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
331   EXPECT_EQ(ui::EF_NONE, mod_down_flags);
332 }
333
334 TEST_F(StickyKeysTest, NormalShortcutTest) {
335   // Sticky keys should not be enabled if we perform a normal shortcut.
336   scoped_ptr<ui::KeyEvent> ev;
337   StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
338
339   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
340
341   // Perform ctrl+n shortcut.
342   ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL));
343   int mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
344   ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_N));
345   mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
346   ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_N));
347   mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
348   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
349   ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL));
350   mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
351
352   // Sticky keys should not be enabled afterwards.
353   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
354   EXPECT_EQ(ui::EF_NONE, mod_down_flags);
355
356   // Perform ctrl+n shortcut, releasing ctrl first.
357   ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL));
358   mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
359   ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_N));
360   mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
361   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
362   ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL));
363   mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
364   ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_N));
365   mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
366
367   // Sticky keys should not be enabled afterwards.
368   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
369   EXPECT_EQ(ui::EF_NONE, mod_down_flags);
370 }
371
372 TEST_F(StickyKeysTest, NormalModifiedClickTest) {
373   scoped_ptr<ui::KeyEvent> kev;
374   scoped_ptr<ui::MouseEvent> mev;
375   StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
376
377   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
378
379   // Perform ctrl+click.
380   kev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL));
381   int mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
382   mev.reset(GenerateMouseEvent(ui::ET_MOUSE_PRESSED));
383   bool released = false;
384   sticky_key.HandleMouseEvent(*mev.get(), &mod_down_flags, &released);
385   mev.reset(GenerateMouseEvent(ui::ET_MOUSE_RELEASED));
386   sticky_key.HandleMouseEvent(*mev.get(), &mod_down_flags, &released);
387
388   // Sticky keys should not be enabled afterwards.
389   kev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL));
390   mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
391   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
392   EXPECT_EQ(ui::EF_NONE, mod_down_flags);
393 }
394
395 TEST_F(StickyKeysTest, MouseMovedModifierTest) {
396   scoped_ptr<ui::KeyEvent> kev;
397   scoped_ptr<ui::MouseEvent> mev;
398   StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
399
400   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
401
402   // Press ctrl and handle mouse move events.
403   kev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL));
404   int mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
405   mev.reset(GenerateSynthesizedMouseMoveEvent(gfx::Point(0, 0)));
406   bool released = false;
407   sticky_key.HandleMouseEvent(*mev.get(), &mod_down_flags, &released);
408   mev.reset(GenerateSynthesizedMouseMoveEvent(gfx::Point(100, 100)));
409   sticky_key.HandleMouseEvent(*mev.get(), &mod_down_flags, &released);
410
411   // Sticky keys should be enabled afterwards.
412   kev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL));
413   mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
414   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
415   EXPECT_EQ(ui::EF_NONE, mod_down_flags);
416 }
417
418 TEST_F(StickyKeysTest, NormalModifiedScrollTest) {
419   scoped_ptr<ui::KeyEvent> kev;
420   scoped_ptr<ui::ScrollEvent> sev;
421   StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
422
423   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
424
425   // Perform ctrl+scroll.
426   kev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL));
427   int mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
428   sev.reset(GenerateFlingScrollEvent(0, true));
429   bool released = false;
430   sticky_key.HandleScrollEvent(*sev.get(), &mod_down_flags, &released);
431   sev.reset(GenerateScrollEvent(10));
432   sticky_key.HandleScrollEvent(*sev.get(), &mod_down_flags, &released);
433   sev.reset(GenerateFlingScrollEvent(10, false));
434   sticky_key.HandleScrollEvent(*sev.get(), &mod_down_flags, &released);
435
436   // Sticky keys should not be enabled afterwards.
437   kev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL));
438   mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
439   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
440   EXPECT_EQ(ui::EF_NONE, mod_down_flags);
441 }
442
443 TEST_F(StickyKeysTest, MouseEventOneshot) {
444   scoped_ptr<ui::MouseEvent> ev;
445   scoped_ptr<ui::KeyEvent> kev;
446   StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
447
448   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
449   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
450   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
451
452   // We should still be in the ENABLED state until we get the mouse
453   // release event.
454   ev.reset(GenerateMouseEvent(ui::ET_MOUSE_PRESSED));
455   bool released = false;
456   int mod_down_flags = 0;
457   sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
458   EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
459   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
460
461   ev.reset(GenerateMouseEvent(ui::ET_MOUSE_RELEASED));
462   released = false;
463   mod_down_flags = 0;
464   sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
465   EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
466   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
467
468   // Making sure modifier key release event is dispatched in the right order.
469   EXPECT_TRUE(released);
470   scoped_ptr<ui::Event> up_event;
471   ASSERT_EQ(0, sticky_key.GetModifierUpEvent(&up_event));
472   EXPECT_TRUE(up_event.get());
473   EXPECT_EQ(ui::ET_KEY_RELEASED, up_event->type());
474   EXPECT_EQ(ui::VKEY_CONTROL,
475             static_cast<const ui::KeyEvent*>(up_event.get())->key_code());
476
477   // Enabled state is one shot, so next click should not be control modified.
478   ev.reset(GenerateMouseEvent(ui::ET_MOUSE_PRESSED));
479   released = false;
480   mod_down_flags = 0;
481   sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
482   EXPECT_FALSE(mod_down_flags & ui::EF_CONTROL_DOWN);
483
484   ev.reset(GenerateMouseEvent(ui::ET_MOUSE_RELEASED));
485   released = false;
486   mod_down_flags = 0;
487   sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
488   EXPECT_FALSE(mod_down_flags & ui::EF_CONTROL_DOWN);
489 }
490
491 TEST_F(StickyKeysTest, MouseEventLocked) {
492   scoped_ptr<ui::MouseEvent> ev;
493   scoped_ptr<ui::KeyEvent> kev;
494   StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
495
496   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
497
498   // Pressing modifier key twice should make us enter lock state.
499   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
500   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
501   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
502   EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
503
504   // Mouse events should not disable locked mode.
505   for (int i = 0; i < 3; ++i) {
506     bool released = false;
507     int mod_down_flags = 0;
508     ev.reset(GenerateMouseEvent(ui::ET_MOUSE_PRESSED));
509     sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
510     EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
511     ev.reset(GenerateMouseEvent(ui::ET_MOUSE_RELEASED));
512     released = false;
513   mod_down_flags = 0;
514     sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
515     EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
516     EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
517   }
518
519   // Test with mouse wheel.
520   for (int i = 0; i < 3; ++i) {
521     bool released = false;
522     int mod_down_flags = 0;
523     ev.reset(GenerateMouseWheelEvent(ui::MouseWheelEvent::kWheelDelta));
524     sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
525     ev.reset(GenerateMouseWheelEvent(-ui::MouseWheelEvent::kWheelDelta));
526     released = false;
527   mod_down_flags = 0;
528     sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
529     EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
530     EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
531   }
532
533   // Test mixed case with mouse events and key events.
534   ev.reset(GenerateMouseWheelEvent(ui::MouseWheelEvent::kWheelDelta));
535   bool released = false;
536   int mod_down_flags = 0;
537   sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
538   EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
539   kev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_N));
540   mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
541   EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
542   mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
543   EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
544
545   EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
546 }
547
548 TEST_F(StickyKeysTest, ScrollEventOneshot) {
549   scoped_ptr<ui::ScrollEvent> ev;
550   scoped_ptr<ui::KeyEvent> kev;
551   StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
552
553   int scroll_deltas[] = {-10, 10};
554   for (int i = 0; i < 2; ++i) {
555     // Enable sticky keys.
556     EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
557     SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
558     EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
559
560     // Test a scroll sequence. Sticky keys should only be disabled at the end
561     // of the scroll sequence. Fling cancel event starts the scroll sequence.
562     ev.reset(GenerateFlingScrollEvent(0, true));
563     bool released = false;
564     int mod_down_flags = 0;
565     sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
566     EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
567     EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
568
569     // Scrolls should all be modified but not disable sticky keys.
570     for (int j = 0; j < 3; ++j) {
571       ev.reset(GenerateScrollEvent(scroll_deltas[i]));
572       released = false;
573   mod_down_flags = 0;
574       sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
575       EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
576       EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
577     }
578
579     // Fling start event ends scroll sequence.
580     ev.reset(GenerateFlingScrollEvent(scroll_deltas[i], false));
581     released = false;
582   mod_down_flags = 0;
583     sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
584     EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
585     EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
586
587     scoped_ptr<ui::Event> up_event;
588     EXPECT_TRUE(released);
589     ASSERT_EQ(0, sticky_key.GetModifierUpEvent(&up_event));
590     EXPECT_TRUE(up_event.get());
591     EXPECT_EQ(ui::ET_KEY_RELEASED, up_event->type());
592     EXPECT_EQ(ui::VKEY_CONTROL,
593               static_cast<const ui::KeyEvent*>(up_event.get())->key_code());
594   }
595 }
596
597 TEST_F(StickyKeysTest, ScrollDirectionChanged) {
598   scoped_ptr<ui::ScrollEvent> ev;
599   scoped_ptr<ui::KeyEvent> kev;
600   StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
601
602   // Test direction change with both boundary value and negative value.
603   const int direction_change_values[2] = {0, -10};
604   for (int i = 0; i < 2; ++i) {
605     SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
606     EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
607
608     // Fling cancel starts scroll sequence.
609     ev.reset(GenerateFlingScrollEvent(0, true));
610     bool released = false;
611     int mod_down_flags = 0;
612     sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
613     EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
614
615     // Test that changing directions in a scroll sequence will
616     // return sticky keys to DISABLED state.
617     for (int j = 0; j < 3; ++j) {
618       ev.reset(GenerateScrollEvent(10));
619       released = false;
620   mod_down_flags = 0;
621       sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
622       EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
623       EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
624     }
625
626     ev.reset(GenerateScrollEvent(direction_change_values[i]));
627     released = false;
628   mod_down_flags = 0;
629     sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
630     EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
631   }
632 }
633
634 TEST_F(StickyKeysTest, ScrollEventLocked) {
635   scoped_ptr<ui::ScrollEvent> ev;
636   scoped_ptr<ui::KeyEvent> kev;
637   StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
638
639   // Lock sticky keys.
640   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
641   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
642   EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
643
644   // Test scroll events are correctly modified in locked state.
645   for (int i = 0; i < 5; ++i) {
646     // Fling cancel starts scroll sequence.
647     ev.reset(GenerateFlingScrollEvent(0, true));
648     bool released = false;
649     int mod_down_flags = 0;
650     sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
651
652     ev.reset(GenerateScrollEvent(10));
653     released = false;
654   mod_down_flags = 0;
655     sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
656     EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
657     ev.reset(GenerateScrollEvent(-10));
658     sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
659     EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
660
661     // Fling start ends scroll sequence.
662     ev.reset(GenerateFlingScrollEvent(-10, false));
663     sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
664   }
665
666   EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
667 }
668
669 TEST_F(StickyKeysTest, SynthesizedEvents) {
670   // Non-native, internally generated events should be properly handled
671   // by sticky keys.
672   StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
673
674   // Test non-native key events.
675   scoped_ptr<ui::KeyEvent> kev;
676   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
677   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
678
679   kev.reset(GenerateSynthesizedKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_K));
680   int mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
681   EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
682   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
683
684   kev.reset(GenerateSynthesizedKeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_K));
685   mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
686   EXPECT_FALSE(mod_down_flags & ui::EF_CONTROL_DOWN);
687   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
688
689   // Test non-native mouse events.
690   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
691   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
692
693   scoped_ptr<ui::MouseEvent> mev;
694   mev.reset(GenerateSynthesizedMouseClickEvent(ui::ET_MOUSE_PRESSED,
695                                                gfx::Point(0, 0)));
696   bool released = false;
697   sticky_key.HandleMouseEvent(*mev.get(), &mod_down_flags, &released);
698   EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
699   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
700
701   mev.reset(GenerateSynthesizedMouseClickEvent(ui::ET_MOUSE_RELEASED,
702                                                gfx::Point(0, 0)));
703   released = false;
704   mod_down_flags = 0;
705   sticky_key.HandleMouseEvent(*mev.get(), &mod_down_flags, &released);
706   EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
707   EXPECT_TRUE(released);
708   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
709 }
710
711 }  // namespace ash