Upstream version 5.34.104.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/root_window.h"
18 #include "ui/aura/window.h"
19 #include "ui/aura/window_tree_host_delegate.h"
20 #include "ui/events/event_handler.h"
21 #include "ui/events/test/events_test_utils_x11.h"
22 #include "ui/events/x/device_data_manager.h"
23
24 namespace ash {
25
26 namespace {
27
28 // The device id of the test scroll device.
29 const unsigned int kScrollDeviceId = 1;
30
31 }  // namespace
32
33 // Keeps a buffer of handled events.
34 class EventBuffer : public ui::EventHandler {
35  public:
36   EventBuffer() {}
37   virtual ~EventBuffer() {}
38
39   void PopEvents(ScopedVector<ui::Event>* events) {
40     events->clear();
41     events->swap(events_);
42   }
43
44  private:
45   // ui::EventHandler overrides:
46   virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE {
47     events_.push_back(new ui::KeyEvent(*event));
48   }
49
50   virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
51     if (event->IsMouseWheelEvent()) {
52       events_.push_back(
53           new ui::MouseWheelEvent(*static_cast<ui::MouseWheelEvent*>(event)));
54     } else {
55       events_.push_back(new ui::MouseEvent(event->native_event()));
56     }
57   }
58
59   ScopedVector<ui::Event> events_;
60
61   DISALLOW_COPY_AND_ASSIGN(EventBuffer);
62 };
63
64 // A testable and StickyKeysHandler.
65 class MockStickyKeysHandlerDelegate :
66     public StickyKeysHandler::StickyKeysHandlerDelegate {
67  public:
68   class Delegate {
69    public:
70     virtual aura::Window* GetExpectedTarget() = 0;
71     virtual void OnShortcutPressed() = 0;
72
73    protected:
74     virtual ~Delegate() {}
75   };
76
77   MockStickyKeysHandlerDelegate(Delegate* delegate) : delegate_(delegate) {}
78
79   virtual ~MockStickyKeysHandlerDelegate() {}
80
81   // StickyKeysHandler override.
82   virtual void DispatchKeyEvent(ui::KeyEvent* event,
83                                 aura::Window* target) OVERRIDE {
84     ASSERT_EQ(delegate_->GetExpectedTarget(), target);
85
86     // Detect a special shortcut when it is dispatched. This shortcut will
87     // not be hit in the LOCKED state as this case does not involve the
88     // delegate.
89     if (event->type() == ui::ET_KEY_PRESSED &&
90         event->key_code() == ui::VKEY_J &&
91         event->flags() | ui::EF_CONTROL_DOWN) {
92       delegate_->OnShortcutPressed();
93     }
94
95     events_.push_back(new ui::KeyEvent(*event));
96   }
97
98   virtual void DispatchMouseEvent(ui::MouseEvent* event,
99                                   aura::Window* target) OVERRIDE {
100     ASSERT_EQ(delegate_->GetExpectedTarget(), target);
101     events_.push_back(
102         new ui::MouseEvent(*event, target, target->GetRootWindow()));
103   }
104
105   virtual void DispatchScrollEvent(ui::ScrollEvent* event,
106                                    aura::Window* target) OVERRIDE {
107     events_.push_back(new ui::ScrollEvent(event->native_event()));
108   }
109
110   // Returns the count of dispatched events.
111   size_t GetEventCount() const {
112     return events_.size();
113   }
114
115   // Returns the |index|-th dispatched event.
116   const ui::Event* GetEvent(size_t index) const {
117     return events_[index];
118   }
119
120   // Clears all previously dispatched events.
121   void ClearEvents() {
122     events_.clear();
123   }
124
125  private:
126   ScopedVector<ui::Event> events_;
127   Delegate* delegate_;
128
129   DISALLOW_COPY_AND_ASSIGN(MockStickyKeysHandlerDelegate);
130 };
131
132 class StickyKeysTest : public test::AshTestBase,
133                        public MockStickyKeysHandlerDelegate::Delegate {
134  protected:
135   StickyKeysTest()
136       : target_(NULL),
137         root_window_(NULL) {}
138
139   virtual void SetUp() OVERRIDE {
140     test::AshTestBase::SetUp();
141
142     // |target_| owned by root window of shell. It is still safe to delete
143     // it ourselves.
144     target_ = CreateTestWindowInShellWithId(0);
145     root_window_ = target_->GetRootWindow();
146   }
147
148   virtual void TearDown() OVERRIDE {
149     test::AshTestBase::TearDown();
150   }
151
152   // Overridden from MockStickyKeysHandlerDelegate::Delegate:
153   virtual aura::Window* GetExpectedTarget() OVERRIDE {
154     return target_ ? target_ : root_window_;
155   }
156
157   virtual void OnShortcutPressed() OVERRIDE {
158     if (target_) {
159       delete target_;
160       target_ = NULL;
161     }
162   }
163
164   ui::KeyEvent* GenerateKey(bool is_key_press, ui::KeyboardCode code) {
165     scoped_xevent_.InitKeyEvent(
166         is_key_press ? ui::ET_KEY_PRESSED : ui::ET_KEY_RELEASED,
167         code,
168         0);
169     ui::KeyEvent* event =  new ui::KeyEvent(scoped_xevent_, false);
170     ui::Event::DispatcherApi dispatcher(event);
171     dispatcher.set_target(target_);
172     return event;
173   }
174
175   ui::MouseEvent* GenerateMouseEvent(bool is_button_press) {
176     scoped_xevent_.InitButtonEvent(
177         is_button_press ? ui::ET_MOUSE_PRESSED : ui::ET_MOUSE_RELEASED, 0);
178     ui::MouseEvent* event = new ui::MouseEvent(scoped_xevent_);
179     ui::Event::DispatcherApi dispatcher(event);
180     dispatcher.set_target(target_);
181     return event;
182   }
183
184   ui::MouseWheelEvent* GenerateMouseWheelEvent(int wheel_delta) {
185     EXPECT_NE(0, wheel_delta);
186     scoped_xevent_.InitMouseWheelEvent(wheel_delta, 0);
187     ui::MouseWheelEvent* event = new ui::MouseWheelEvent(scoped_xevent_);
188     ui::Event::DispatcherApi dispatcher(event);
189     dispatcher.set_target(target_);
190     return event;
191   }
192
193   ui::ScrollEvent* GenerateScrollEvent(int scroll_delta) {
194     scoped_xevent_.InitScrollEvent(kScrollDeviceId, // deviceid
195                                    0,               // x_offset
196                                    scroll_delta,    // y_offset
197                                    0,               // x_offset_ordinal
198                                    scroll_delta,    // y_offset_ordinal
199                                    2);              // finger_count
200     ui::ScrollEvent* event = new ui::ScrollEvent(scoped_xevent_);
201     ui::Event::DispatcherApi dispatcher(event);
202     dispatcher.set_target(target_);
203     return event;
204   }
205
206   ui::ScrollEvent* GenerateFlingScrollEvent(int fling_delta,
207                                             bool is_cancel) {
208     scoped_xevent_.InitFlingScrollEvent(
209         kScrollDeviceId, // deviceid
210         0,               // x_velocity
211         fling_delta,     // y_velocity
212         0,               // x_velocity_ordinal
213         fling_delta,     // y_velocity_ordinal
214         is_cancel);      // is_cancel
215     ui::ScrollEvent* event = new ui::ScrollEvent(scoped_xevent_);
216     ui::Event::DispatcherApi dispatcher(event);
217     dispatcher.set_target(target_);
218     return event;
219   }
220
221   // Creates a synthesized KeyEvent that is not backed by a native event.
222   ui::KeyEvent* GenerateSynthesizedKeyEvent(
223       bool is_key_press, ui::KeyboardCode code) {
224     ui::KeyEvent* event = new ui::KeyEvent(
225         is_key_press ? ui::ET_KEY_PRESSED : ui::ET_MOUSE_RELEASED,
226         code, 0, true);
227     ui::Event::DispatcherApi dispatcher(event);
228     dispatcher.set_target(target_);
229     return event;
230   }
231
232   // Creates a synthesized MouseEvent that is not backed by a native event.
233   ui::MouseEvent* GenerateSynthesizedMouseEvent(bool is_button_press) {
234     ui::MouseEvent* event = new ui::MouseEvent(
235         is_button_press ? ui::ET_MOUSE_PRESSED : ui::ET_MOUSE_RELEASED,
236         gfx::Point(0, 0),
237         gfx::Point(0, 0),
238         ui::EF_LEFT_MOUSE_BUTTON,
239         ui::EF_LEFT_MOUSE_BUTTON);
240     ui::Event::DispatcherApi dispatcher(event);
241     dispatcher.set_target(target_);
242     return event;
243   }
244
245   // Creates a synthesized ET_MOUSE_MOVED event.
246   ui::MouseEvent* GenerateSynthesizedMouseEvent(int x, int y) {
247     ui::MouseEvent* event = new ui::MouseEvent(
248         ui::ET_MOUSE_MOVED,
249         gfx::Point(x, y),
250         gfx::Point(x, y),
251         ui::EF_LEFT_MOUSE_BUTTON,
252         ui::EF_LEFT_MOUSE_BUTTON);
253     ui::Event::DispatcherApi dispatcher(event);
254     dispatcher.set_target(target_);
255     return event;
256   }
257
258   void SendActivateStickyKeyPattern(StickyKeysHandler* handler,
259                                     ui::KeyboardCode key_code) {
260     scoped_ptr<ui::KeyEvent> ev;
261     ev.reset(GenerateKey(true, key_code));
262     handler->HandleKeyEvent(ev.get());
263     ev.reset(GenerateKey(false, key_code));
264     handler->HandleKeyEvent(ev.get());
265   }
266
267   void SendActivateStickyKeyPattern(aura::WindowEventDispatcher* dispatcher,
268                                     ui::KeyboardCode key_code) {
269     scoped_ptr<ui::KeyEvent> ev;
270     ev.reset(GenerateKey(true, key_code));
271     ui::EventDispatchDetails details = dispatcher->OnEventFromSource(ev.get());
272     CHECK(!details.dispatcher_destroyed);
273     ev.reset(GenerateKey(false, key_code));
274     details = dispatcher->OnEventFromSource(ev.get());
275     CHECK(!details.dispatcher_destroyed);
276   }
277
278   aura::Window* target() { return target_; }
279
280  private:
281   // Owned by root window of shell, but we can still delete |target_| safely.
282   aura::Window* target_;
283   // The root window of |target_|. Not owned.
284   aura::Window* root_window_;
285
286   // Used to construct the various X events.
287   ui::ScopedXI2Event scoped_xevent_;
288
289   DISALLOW_COPY_AND_ASSIGN(StickyKeysTest);
290 };
291
292 TEST_F(StickyKeysTest, BasicOneshotScenarioTest) {
293   scoped_ptr<ui::KeyEvent> ev;
294   MockStickyKeysHandlerDelegate* mock_delegate =
295       new MockStickyKeysHandlerDelegate(this);
296   StickyKeysHandler sticky_key(ui::EF_SHIFT_DOWN, mock_delegate);
297
298   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
299
300   // By typing Shift key, internal state become ENABLED.
301   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
302   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
303
304   ev.reset(GenerateKey(true, ui::VKEY_A));
305   sticky_key.HandleKeyEvent(ev.get());
306
307   // Next keyboard event is shift modified.
308   EXPECT_TRUE(ev->flags() & ui::EF_SHIFT_DOWN);
309
310   ev.reset(GenerateKey(false, ui::VKEY_A));
311   sticky_key.HandleKeyEvent(ev.get());
312
313   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
314   // Making sure Shift up keyboard event is dispatched.
315   ASSERT_EQ(2U, mock_delegate->GetEventCount());
316   EXPECT_EQ(ui::ET_KEY_PRESSED, mock_delegate->GetEvent(0)->type());
317   EXPECT_EQ(ui::VKEY_A,
318             static_cast<const ui::KeyEvent*>(mock_delegate->GetEvent(0))
319                 ->key_code());
320   EXPECT_EQ(ui::ET_KEY_RELEASED, mock_delegate->GetEvent(1)->type());
321   EXPECT_EQ(ui::VKEY_SHIFT,
322             static_cast<const ui::KeyEvent*>(mock_delegate->GetEvent(1))
323                 ->key_code());
324
325   // Enabled state is one shot, so next key event should not be shift modified.
326   ev.reset(GenerateKey(true, ui::VKEY_A));
327   sticky_key.HandleKeyEvent(ev.get());
328   EXPECT_FALSE(ev->flags() & ui::EF_SHIFT_DOWN);
329
330   ev.reset(GenerateKey(false, ui::VKEY_A));
331   sticky_key.HandleKeyEvent(ev.get());
332   EXPECT_FALSE(ev->flags() & ui::EF_SHIFT_DOWN);
333 }
334
335 TEST_F(StickyKeysTest, BasicLockedScenarioTest) {
336   scoped_ptr<ui::KeyEvent> ev;
337   MockStickyKeysHandlerDelegate* mock_delegate =
338       new MockStickyKeysHandlerDelegate(this);
339   StickyKeysHandler sticky_key(ui::EF_SHIFT_DOWN, mock_delegate);
340
341   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
342
343   // By typing shift key, internal state become ENABLED.
344   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
345   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
346
347   // By typing shift key again, internal state become LOCKED.
348   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
349   EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
350
351   // All keyboard events including keyUp become shift modified.
352   ev.reset(GenerateKey(true, ui::VKEY_A));
353   sticky_key.HandleKeyEvent(ev.get());
354   EXPECT_TRUE(ev->flags() & ui::EF_SHIFT_DOWN);
355
356   ev.reset(GenerateKey(false, ui::VKEY_A));
357   sticky_key.HandleKeyEvent(ev.get());
358   EXPECT_TRUE(ev->flags() & ui::EF_SHIFT_DOWN);
359
360   // Locked state keeps after normal keyboard event.
361   EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
362
363   ev.reset(GenerateKey(true, ui::VKEY_B));
364   sticky_key.HandleKeyEvent(ev.get());
365   EXPECT_TRUE(ev->flags() & ui::EF_SHIFT_DOWN);
366
367   ev.reset(GenerateKey(false, ui::VKEY_B));
368   sticky_key.HandleKeyEvent(ev.get());
369   EXPECT_TRUE(ev->flags() & ui::EF_SHIFT_DOWN);
370
371   EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
372
373   // By typing shift key again, internal state become back to DISABLED.
374   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
375   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
376 }
377
378 TEST_F(StickyKeysTest, NonTargetModifierTest) {
379   scoped_ptr<ui::KeyEvent> ev;
380   MockStickyKeysHandlerDelegate* mock_delegate =
381       new MockStickyKeysHandlerDelegate(this);
382   StickyKeysHandler sticky_key(ui::EF_SHIFT_DOWN, mock_delegate);
383
384   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
385
386   // Non target modifier key does not affect internal state
387   ev.reset(GenerateKey(true, ui::VKEY_MENU));
388   sticky_key.HandleKeyEvent(ev.get());
389   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
390
391   ev.reset(GenerateKey(false, ui::VKEY_MENU));
392   sticky_key.HandleKeyEvent(ev.get());
393   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
394
395   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
396   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
397
398   // Non target modifier key does not affect internal state
399   ev.reset(GenerateKey(true, ui::VKEY_MENU));
400   sticky_key.HandleKeyEvent(ev.get());
401   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
402
403   ev.reset(GenerateKey(false, ui::VKEY_MENU));
404   sticky_key.HandleKeyEvent(ev.get());
405   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
406
407   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
408   EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
409
410   // Non target modifier key does not affect internal state
411   ev.reset(GenerateKey(true, ui::VKEY_MENU));
412   sticky_key.HandleKeyEvent(ev.get());
413   EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
414
415   ev.reset(GenerateKey(false, ui::VKEY_MENU));
416   sticky_key.HandleKeyEvent(ev.get());
417   EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
418 }
419
420 TEST_F(StickyKeysTest, NormalShortcutTest) {
421   // Sticky keys should not be enabled if we perform a normal shortcut.
422   scoped_ptr<ui::KeyEvent> ev;
423   MockStickyKeysHandlerDelegate* mock_delegate =
424       new MockStickyKeysHandlerDelegate(this);
425   StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
426
427   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
428
429   // Perform ctrl+n shortcut.
430   ev.reset(GenerateKey(true, ui::VKEY_CONTROL));
431   sticky_key.HandleKeyEvent(ev.get());
432   ev.reset(GenerateKey(true, ui::VKEY_N));
433   sticky_key.HandleKeyEvent(ev.get());
434   ev.reset(GenerateKey(false, ui::VKEY_N));
435   sticky_key.HandleKeyEvent(ev.get());
436   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
437
438   // Sticky keys should not be enabled afterwards.
439   ev.reset(GenerateKey(false, ui::VKEY_CONTROL));
440   sticky_key.HandleKeyEvent(ev.get());
441   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
442 }
443
444 TEST_F(StickyKeysTest, NormalModifiedClickTest) {
445   scoped_ptr<ui::KeyEvent> kev;
446   scoped_ptr<ui::MouseEvent> mev;
447   MockStickyKeysHandlerDelegate* mock_delegate =
448       new MockStickyKeysHandlerDelegate(this);
449   StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
450
451   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
452
453   // Perform ctrl+click.
454   kev.reset(GenerateKey(true, ui::VKEY_CONTROL));
455   sticky_key.HandleKeyEvent(kev.get());
456   mev.reset(GenerateMouseEvent(true));
457   sticky_key.HandleMouseEvent(mev.get());
458   mev.reset(GenerateMouseEvent(false));
459   sticky_key.HandleMouseEvent(mev.get());
460
461   // Sticky keys should not be enabled afterwards.
462   kev.reset(GenerateKey(false, ui::VKEY_CONTROL));
463   sticky_key.HandleKeyEvent(kev.get());
464   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
465 }
466
467 TEST_F(StickyKeysTest, MouseMovedModifierTest) {
468   scoped_ptr<ui::KeyEvent> kev;
469   scoped_ptr<ui::MouseEvent> mev;
470   MockStickyKeysHandlerDelegate* mock_delegate =
471       new MockStickyKeysHandlerDelegate(this);
472   StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
473
474   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
475
476   // Press ctrl and handle mouse move events.
477   kev.reset(GenerateKey(true, ui::VKEY_CONTROL));
478   sticky_key.HandleKeyEvent(kev.get());
479   mev.reset(GenerateSynthesizedMouseEvent(0, 0));
480   sticky_key.HandleMouseEvent(mev.get());
481   mev.reset(GenerateSynthesizedMouseEvent(100, 100));
482   sticky_key.HandleMouseEvent(mev.get());
483
484   // Sticky keys should be enabled afterwards.
485   kev.reset(GenerateKey(false, ui::VKEY_CONTROL));
486   sticky_key.HandleKeyEvent(kev.get());
487   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
488 }
489
490 TEST_F(StickyKeysTest, NormalModifiedScrollTest) {
491   ui::SetUpScrollDeviceForTest(kScrollDeviceId);
492
493   scoped_ptr<ui::KeyEvent> kev;
494   scoped_ptr<ui::ScrollEvent> sev;
495   MockStickyKeysHandlerDelegate* mock_delegate =
496       new MockStickyKeysHandlerDelegate(this);
497   StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
498
499   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
500
501   // Perform ctrl+scroll.
502   kev.reset(GenerateKey(true, ui::VKEY_CONTROL));
503   sev.reset(GenerateFlingScrollEvent(0, true));
504   sticky_key.HandleScrollEvent(sev.get());
505   sev.reset(GenerateScrollEvent(10));
506   sticky_key.HandleScrollEvent(sev.get());
507   sev.reset(GenerateFlingScrollEvent(10, false));
508   sticky_key.HandleScrollEvent(sev.get());
509
510   // Sticky keys should not be enabled afterwards.
511   kev.reset(GenerateKey(false, ui::VKEY_CONTROL));
512   sticky_key.HandleKeyEvent(kev.get());
513   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
514 }
515
516 TEST_F(StickyKeysTest, MouseEventOneshot) {
517   scoped_ptr<ui::MouseEvent> ev;
518   scoped_ptr<ui::KeyEvent> kev;
519   MockStickyKeysHandlerDelegate* mock_delegate =
520       new MockStickyKeysHandlerDelegate(this);
521   StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
522
523   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
524   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
525   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
526
527   // We should still be in the ENABLED state until we get the mouse
528   // release event.
529   ev.reset(GenerateMouseEvent(true));
530   sticky_key.HandleMouseEvent(ev.get());
531   EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
532   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
533
534   ev.reset(GenerateMouseEvent(false));
535   sticky_key.HandleMouseEvent(ev.get());
536   EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
537   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
538
539   // Making sure modifier key release event is dispatched in the right order.
540   ASSERT_EQ(2u, mock_delegate->GetEventCount());
541   EXPECT_EQ(ui::ET_MOUSE_RELEASED, mock_delegate->GetEvent(0)->type());
542   EXPECT_EQ(ui::ET_KEY_RELEASED, mock_delegate->GetEvent(1)->type());
543   EXPECT_EQ(ui::VKEY_CONTROL,
544             static_cast<const ui::KeyEvent*>(mock_delegate->GetEvent(1))
545                 ->key_code());
546
547   // Enabled state is one shot, so next click should not be control modified.
548   ev.reset(GenerateMouseEvent(true));
549   sticky_key.HandleMouseEvent(ev.get());
550   EXPECT_FALSE(ev->flags() & ui::EF_CONTROL_DOWN);
551
552   ev.reset(GenerateMouseEvent(false));
553   sticky_key.HandleMouseEvent(ev.get());
554   EXPECT_FALSE(ev->flags() & ui::EF_CONTROL_DOWN);
555 }
556
557 TEST_F(StickyKeysTest, MouseEventLocked) {
558   scoped_ptr<ui::MouseEvent> ev;
559   scoped_ptr<ui::KeyEvent> kev;
560   MockStickyKeysHandlerDelegate* mock_delegate =
561       new MockStickyKeysHandlerDelegate(this);
562   StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
563
564   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
565
566   // Pressing modifier key twice should make us enter lock state.
567   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
568   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
569   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
570   EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
571
572   // Mouse events should not disable locked mode.
573   for (int i = 0; i < 3; ++i) {
574     ev.reset(GenerateMouseEvent(true));
575     sticky_key.HandleMouseEvent(ev.get());
576     EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
577     ev.reset(GenerateMouseEvent(false));
578     sticky_key.HandleMouseEvent(ev.get());
579     EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
580     EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
581   }
582
583   // Test with mouse wheel.
584   for (int i = 0; i < 3; ++i) {
585     ev.reset(GenerateMouseWheelEvent(ui::MouseWheelEvent::kWheelDelta));
586     sticky_key.HandleMouseEvent(ev.get());
587     ev.reset(GenerateMouseWheelEvent(-ui::MouseWheelEvent::kWheelDelta));
588     sticky_key.HandleMouseEvent(ev.get());
589     EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
590     EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
591   }
592
593   // Test mixed case with mouse events and key events.
594   ev.reset(GenerateMouseWheelEvent(ui::MouseWheelEvent::kWheelDelta));
595   sticky_key.HandleMouseEvent(ev.get());
596   EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
597   kev.reset(GenerateKey(true, ui::VKEY_N));
598   sticky_key.HandleKeyEvent(kev.get());
599   EXPECT_TRUE(kev->flags() & ui::EF_CONTROL_DOWN);
600   kev.reset(GenerateKey(false, ui::VKEY_N));
601   sticky_key.HandleKeyEvent(kev.get());
602   EXPECT_TRUE(kev->flags() & ui::EF_CONTROL_DOWN);
603
604   EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
605 }
606
607 TEST_F(StickyKeysTest, ScrollEventOneshot) {
608   ui::SetUpScrollDeviceForTest(kScrollDeviceId);
609   // Disable Australlian scrolling.
610   ui::DeviceDataManager::GetInstance()->set_natural_scroll_enabled(true);
611
612   scoped_ptr<ui::ScrollEvent> ev;
613   scoped_ptr<ui::KeyEvent> kev;
614   MockStickyKeysHandlerDelegate* mock_delegate =
615       new MockStickyKeysHandlerDelegate(this);
616   StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
617
618   int scroll_deltas[] = {-10, 10};
619   for (int i = 0; i < 2; ++i) {
620     mock_delegate->ClearEvents();
621
622     // Enable sticky keys.
623     EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
624     SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
625     EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
626
627     // Test a scroll sequence. Sticky keys should only be disabled at the end
628     // of the scroll sequence. Fling cancel event starts the scroll sequence.
629     ev.reset(GenerateFlingScrollEvent(0, true));
630     sticky_key.HandleScrollEvent(ev.get());
631     EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
632     EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
633
634     // Scrolls should all be modified but not disable sticky keys.
635     for (int j = 0; j < 3; ++j) {
636       ev.reset(GenerateScrollEvent(scroll_deltas[i]));
637       sticky_key.HandleScrollEvent(ev.get());
638       EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
639       EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
640     }
641
642     // Fling start event ends scroll sequence.
643     ev.reset(GenerateFlingScrollEvent(scroll_deltas[i], false));
644     sticky_key.HandleScrollEvent(ev.get());
645     EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
646     EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
647
648     ASSERT_EQ(2U, mock_delegate->GetEventCount());
649     EXPECT_EQ(ui::ET_SCROLL_FLING_START, mock_delegate->GetEvent(0)->type());
650     EXPECT_FLOAT_EQ(scroll_deltas[i],
651                     static_cast<const ui::ScrollEvent*>(
652                         mock_delegate->GetEvent(0))->y_offset());
653     EXPECT_EQ(ui::ET_KEY_RELEASED, mock_delegate->GetEvent(1)->type());
654     EXPECT_EQ(ui::VKEY_CONTROL,
655               static_cast<const ui::KeyEvent*>(mock_delegate->GetEvent(1))
656                   ->key_code());
657   }
658 }
659
660 TEST_F(StickyKeysTest, ScrollDirectionChanged) {
661   ui::SetUpScrollDeviceForTest(kScrollDeviceId);
662   // Disable Australlian scrolling.
663   ui::DeviceDataManager::GetInstance()->set_natural_scroll_enabled(true);
664
665   scoped_ptr<ui::ScrollEvent> ev;
666   scoped_ptr<ui::KeyEvent> kev;
667   MockStickyKeysHandlerDelegate* mock_delegate =
668       new MockStickyKeysHandlerDelegate(this);
669   StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
670
671   // Test direction change with both boundary value and negative value.
672   const int direction_change_values[2] = {0, -10};
673   for (int i = 0; i < 2; ++i) {
674     SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
675     EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
676
677     // Fling cancel starts scroll sequence.
678     ev.reset(GenerateFlingScrollEvent(0, true));
679     sticky_key.HandleScrollEvent(ev.get());
680     EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
681
682     // Test that changing directions in a scroll sequence will
683     // return sticky keys to DISABLED state.
684     for (int j = 0; j < 3; ++j) {
685       ev.reset(GenerateScrollEvent(10));
686       sticky_key.HandleScrollEvent(ev.get());
687       EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
688       EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
689     }
690
691     ev.reset(GenerateScrollEvent(direction_change_values[i]));
692     sticky_key.HandleScrollEvent(ev.get());
693     EXPECT_FALSE(ev->flags() & ui::EF_CONTROL_DOWN);
694     EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
695   }
696 }
697
698 TEST_F(StickyKeysTest, ScrollEventLocked) {
699   ui::SetUpScrollDeviceForTest(kScrollDeviceId);
700   // Disable Australlian scrolling.
701   ui::DeviceDataManager::GetInstance()->set_natural_scroll_enabled(true);
702
703   scoped_ptr<ui::ScrollEvent> ev;
704   scoped_ptr<ui::KeyEvent> kev;
705   MockStickyKeysHandlerDelegate* mock_delegate =
706       new MockStickyKeysHandlerDelegate(this);
707   StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
708
709   // Lock sticky keys.
710   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
711   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
712   EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
713
714   // Test scroll events are correctly modified in locked state.
715   for (int i = 0; i < 5; ++i) {
716     // Fling cancel starts scroll sequence.
717     ev.reset(GenerateFlingScrollEvent(0, true));
718     sticky_key.HandleScrollEvent(ev.get());
719
720     ev.reset(GenerateScrollEvent(10));
721     sticky_key.HandleScrollEvent(ev.get());
722     EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
723     ev.reset(GenerateScrollEvent(-10));
724     sticky_key.HandleScrollEvent(ev.get());
725     EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
726
727     // Fling start ends scroll sequence.
728     ev.reset(GenerateFlingScrollEvent(-10, false));
729     sticky_key.HandleScrollEvent(ev.get());
730   }
731
732   EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
733 }
734
735 TEST_F(StickyKeysTest, EventTargetDestroyed) {
736   scoped_ptr<ui::KeyEvent> ev;
737   MockStickyKeysHandlerDelegate* mock_delegate =
738       new MockStickyKeysHandlerDelegate(this);
739   StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
740
741   target()->Focus();
742
743   // Go into ENABLED state.
744   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
745   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
746   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
747
748   // CTRL+J is a special shortcut that will destroy the event target.
749   ev.reset(GenerateKey(true, ui::VKEY_J));
750   sticky_key.HandleKeyEvent(ev.get());
751   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
752   EXPECT_FALSE(target());
753 }
754
755 TEST_F(StickyKeysTest, SynthesizedEvents) {
756   // Non-native, internally generated events should be properly handled
757   // by sticky keys.
758   MockStickyKeysHandlerDelegate* mock_delegate =
759       new MockStickyKeysHandlerDelegate(this);
760   StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
761
762   // Test non-native key events.
763   scoped_ptr<ui::KeyEvent> kev;
764   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
765   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
766
767   kev.reset(GenerateSynthesizedKeyEvent(true, ui::VKEY_K));
768   sticky_key.HandleKeyEvent(kev.get());
769   EXPECT_TRUE(kev->flags() & ui::EF_CONTROL_DOWN);
770   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
771
772   kev.reset(GenerateSynthesizedKeyEvent(false, ui::VKEY_K));
773   sticky_key.HandleKeyEvent(kev.get());
774   EXPECT_FALSE(kev->flags() & ui::EF_CONTROL_DOWN);
775   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
776
777   // Test non-native mouse events.
778   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
779   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
780
781   scoped_ptr<ui::MouseEvent> mev;
782   mev.reset(GenerateSynthesizedMouseEvent(true));
783   sticky_key.HandleMouseEvent(mev.get());
784   EXPECT_TRUE(mev->flags() & ui::EF_CONTROL_DOWN);
785   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
786
787   mev.reset(GenerateSynthesizedMouseEvent(false));
788   sticky_key.HandleMouseEvent(mev.get());
789   EXPECT_TRUE(mev->flags() & ui::EF_CONTROL_DOWN);
790   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
791 }
792
793 TEST_F(StickyKeysTest, KeyEventDispatchImpl) {
794   // Test the actual key event dispatch implementation.
795   EventBuffer buffer;
796   ScopedVector<ui::Event> events;
797   aura::WindowEventDispatcher* dispatcher = Shell::GetPrimaryRootWindow()
798       ->GetDispatcher();
799   Shell::GetInstance()->AddPreTargetHandler(&buffer);
800   Shell::GetInstance()->sticky_keys_controller()->Enable(true);
801
802   SendActivateStickyKeyPattern(dispatcher, ui::VKEY_CONTROL);
803   scoped_ptr<ui::KeyEvent> ev;
804   buffer.PopEvents(&events);
805
806   // Test key press event is correctly modified and modifier release
807   // event is sent.
808   ev.reset(GenerateKey(true, ui::VKEY_C));
809   ui::EventDispatchDetails details = dispatcher->OnEventFromSource(ev.get());
810   buffer.PopEvents(&events);
811   EXPECT_EQ(2u, events.size());
812   EXPECT_EQ(ui::ET_KEY_PRESSED, events[0]->type());
813   EXPECT_EQ(ui::VKEY_C, static_cast<ui::KeyEvent*>(events[0])->key_code());
814   EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
815   EXPECT_EQ(ui::ET_KEY_RELEASED, events[1]->type());
816   EXPECT_EQ(ui::VKEY_CONTROL,
817             static_cast<ui::KeyEvent*>(events[1])->key_code());
818
819   // Test key release event is not modified.
820   ev.reset(GenerateKey(false, ui::VKEY_C));
821   details = dispatcher->OnEventFromSource(ev.get());
822   ASSERT_FALSE(details.dispatcher_destroyed);
823   buffer.PopEvents(&events);
824   EXPECT_EQ(1u, events.size());
825   EXPECT_EQ(ui::ET_KEY_RELEASED, events[0]->type());
826   EXPECT_EQ(ui::VKEY_C,
827             static_cast<ui::KeyEvent*>(events[0])->key_code());
828   EXPECT_FALSE(events[0]->flags() & ui::EF_CONTROL_DOWN);
829
830   Shell::GetInstance()->RemovePreTargetHandler(&buffer);
831 }
832
833 TEST_F(StickyKeysTest, MouseEventDispatchImpl) {
834   // Test the actual sticky mouse event dispatch implementation.
835   EventBuffer buffer;
836   ScopedVector<ui::Event> events;
837   aura::WindowEventDispatcher* dispatcher = Shell::GetPrimaryRootWindow()
838       ->GetDispatcher();
839   Shell::GetInstance()->AddPreTargetHandler(&buffer);
840   Shell::GetInstance()->sticky_keys_controller()->Enable(true);
841
842   scoped_ptr<ui::MouseEvent> ev;
843   SendActivateStickyKeyPattern(dispatcher, ui::VKEY_CONTROL);
844   buffer.PopEvents(&events);
845
846   // Test mouse press event is correctly modified.
847   ev.reset(GenerateMouseEvent(true));
848   ui::EventDispatchDetails details = dispatcher->OnEventFromSource(ev.get());
849   buffer.PopEvents(&events);
850   EXPECT_EQ(1u, events.size());
851   EXPECT_EQ(ui::ET_MOUSE_PRESSED, events[0]->type());
852   EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
853
854   // Test mouse release event is correctly modified and modifier release
855   // event is sent.
856   ev.reset(GenerateMouseEvent(false));
857   details = dispatcher->OnEventFromSource(ev.get());
858   ASSERT_FALSE(details.dispatcher_destroyed);
859   buffer.PopEvents(&events);
860   EXPECT_EQ(2u, events.size());
861   EXPECT_EQ(ui::ET_MOUSE_RELEASED, events[0]->type());
862   EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
863   EXPECT_EQ(ui::ET_KEY_RELEASED, events[1]->type());
864   EXPECT_EQ(ui::VKEY_CONTROL,
865             static_cast<ui::KeyEvent*>(events[1])->key_code());
866
867   Shell::GetInstance()->RemovePreTargetHandler(&buffer);
868 }
869
870 TEST_F(StickyKeysTest, MouseWheelEventDispatchImpl) {
871   // Test the actual mouse wheel event dispatch implementation.
872   EventBuffer buffer;
873   ScopedVector<ui::Event> events;
874   aura::WindowEventDispatcher* dispatcher = Shell::GetPrimaryRootWindow()
875       ->GetDispatcher();
876   Shell::GetInstance()->AddPreTargetHandler(&buffer);
877   Shell::GetInstance()->sticky_keys_controller()->Enable(true);
878
879   scoped_ptr<ui::MouseWheelEvent> ev;
880   SendActivateStickyKeyPattern(dispatcher, ui::VKEY_CONTROL);
881   buffer.PopEvents(&events);
882
883   // Test positive mouse wheel event is correctly modified and modifier release
884   // event is sent.
885   ev.reset(GenerateMouseWheelEvent(ui::MouseWheelEvent::kWheelDelta));
886   ui::EventDispatchDetails details = dispatcher->OnEventFromSource(ev.get());
887   ASSERT_FALSE(details.dispatcher_destroyed);
888   buffer.PopEvents(&events);
889   EXPECT_EQ(2u, events.size());
890   EXPECT_TRUE(events[0]->IsMouseWheelEvent());
891   EXPECT_EQ(ui::MouseWheelEvent::kWheelDelta,
892             static_cast<ui::MouseWheelEvent*>(events[0])->y_offset());
893   EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
894   EXPECT_EQ(ui::ET_KEY_RELEASED, events[1]->type());
895   EXPECT_EQ(ui::VKEY_CONTROL,
896             static_cast<ui::KeyEvent*>(events[1])->key_code());
897
898   // Test negative mouse wheel event is correctly modified and modifier release
899   // event is sent.
900   SendActivateStickyKeyPattern(dispatcher, ui::VKEY_CONTROL);
901   buffer.PopEvents(&events);
902
903   ev.reset(GenerateMouseWheelEvent(-ui::MouseWheelEvent::kWheelDelta));
904   details = dispatcher->OnEventFromSource(ev.get());
905   ASSERT_FALSE(details.dispatcher_destroyed);
906   buffer.PopEvents(&events);
907   EXPECT_EQ(2u, events.size());
908   EXPECT_TRUE(events[0]->IsMouseWheelEvent());
909   EXPECT_EQ(-ui::MouseWheelEvent::kWheelDelta,
910             static_cast<ui::MouseWheelEvent*>(events[0])->y_offset());
911   EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
912   EXPECT_EQ(ui::ET_KEY_RELEASED, events[1]->type());
913   EXPECT_EQ(ui::VKEY_CONTROL,
914             static_cast<ui::KeyEvent*>(events[1])->key_code());
915
916   Shell::GetInstance()->RemovePreTargetHandler(&buffer);
917 }
918
919 }  // namespace ash