Upstream version 7.35.139.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_handler.h"
20 #include "ui/events/event_processor.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 touchpad device.
29 const unsigned int kTouchPadDeviceId = 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));
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     ui::SetUpTouchPadForTest(kTouchPadDeviceId);
148   }
149
150   virtual void TearDown() OVERRIDE {
151     test::AshTestBase::TearDown();
152   }
153
154   // Overridden from MockStickyKeysHandlerDelegate::Delegate:
155   virtual aura::Window* GetExpectedTarget() OVERRIDE {
156     return target_ ? target_ : root_window_;
157   }
158
159   virtual void OnShortcutPressed() OVERRIDE {
160     if (target_) {
161       delete target_;
162       target_ = NULL;
163     }
164   }
165
166   ui::KeyEvent* GenerateKey(bool is_key_press, ui::KeyboardCode code) {
167     scoped_xevent_.InitKeyEvent(
168         is_key_press ? ui::ET_KEY_PRESSED : ui::ET_KEY_RELEASED,
169         code,
170         0);
171     ui::KeyEvent* event =  new ui::KeyEvent(scoped_xevent_, false);
172     ui::Event::DispatcherApi dispatcher(event);
173     dispatcher.set_target(target_);
174     return event;
175   }
176
177   // Creates a mouse event backed by a native XInput2 generic button event.
178   // This is the standard native event on Chromebooks.
179   ui::MouseEvent* GenerateMouseEvent(bool is_button_press) {
180     return GenerateMouseEventAt(is_button_press, gfx::Point());
181   }
182
183   // Creates a mouse event backed by a native XInput2 generic button event.
184   // The |location| should be in physical pixels.
185   ui::MouseEvent* GenerateMouseEventAt(bool is_button_press,
186                                        const gfx::Point& location) {
187     scoped_xevent_.InitGenericButtonEvent(
188         kTouchPadDeviceId,
189         is_button_press ? ui::ET_MOUSE_PRESSED : ui::ET_MOUSE_RELEASED,
190         location,
191         0);
192     ui::MouseEvent* event = new ui::MouseEvent(scoped_xevent_);
193     ui::Event::DispatcherApi dispatcher(event);
194     dispatcher.set_target(target_);
195     return event;
196   }
197
198   ui::MouseWheelEvent* GenerateMouseWheelEvent(int wheel_delta) {
199     EXPECT_NE(0, wheel_delta);
200     scoped_xevent_.InitGenericMouseWheelEvent(
201         kTouchPadDeviceId, wheel_delta, 0);
202     ui::MouseWheelEvent* event = new ui::MouseWheelEvent(scoped_xevent_);
203     ui::Event::DispatcherApi dispatcher(event);
204     dispatcher.set_target(target_);
205     return event;
206   }
207
208   ui::ScrollEvent* GenerateScrollEvent(int scroll_delta) {
209     scoped_xevent_.InitScrollEvent(kTouchPadDeviceId, // deviceid
210                                    0,               // x_offset
211                                    scroll_delta,    // y_offset
212                                    0,               // x_offset_ordinal
213                                    scroll_delta,    // y_offset_ordinal
214                                    2);              // finger_count
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   ui::ScrollEvent* GenerateFlingScrollEvent(int fling_delta,
222                                             bool is_cancel) {
223     scoped_xevent_.InitFlingScrollEvent(
224         kTouchPadDeviceId, // deviceid
225         0,               // x_velocity
226         fling_delta,     // y_velocity
227         0,               // x_velocity_ordinal
228         fling_delta,     // y_velocity_ordinal
229         is_cancel);      // is_cancel
230     ui::ScrollEvent* event = new ui::ScrollEvent(scoped_xevent_);
231     ui::Event::DispatcherApi dispatcher(event);
232     dispatcher.set_target(target_);
233     return event;
234   }
235
236   // Creates a synthesized KeyEvent that is not backed by a native event.
237   ui::KeyEvent* GenerateSynthesizedKeyEvent(
238       bool is_key_press, ui::KeyboardCode code) {
239     ui::KeyEvent* event = new ui::KeyEvent(
240         is_key_press ? ui::ET_KEY_PRESSED : ui::ET_MOUSE_RELEASED,
241         code, 0, true);
242     ui::Event::DispatcherApi dispatcher(event);
243     dispatcher.set_target(target_);
244     return event;
245   }
246
247   // Creates a synthesized MouseEvent that is not backed by a native event.
248   ui::MouseEvent* GenerateSynthesizedMouseEventAt(ui::EventType event_type,
249                                                   const gfx::Point& location) {
250     ui::MouseEvent* event = new ui::MouseEvent(event_type,
251                                                location,
252                                                location,
253                                                ui::EF_LEFT_MOUSE_BUTTON,
254                                                ui::EF_LEFT_MOUSE_BUTTON);
255     ui::Event::DispatcherApi dispatcher(event);
256     dispatcher.set_target(target_);
257     return event;
258   }
259
260   // Creates a synthesized mouse press or release event.
261   ui::MouseEvent* GenerateSynthesizedMouseClickEvent(
262       bool is_button_press,
263       const gfx::Point& location) {
264     return GenerateSynthesizedMouseEventAt(
265         is_button_press ? ui::ET_MOUSE_PRESSED : ui::ET_MOUSE_RELEASED,
266         location);
267   }
268
269   // Creates a synthesized ET_MOUSE_MOVED event.
270   ui::MouseEvent* GenerateSynthesizedMouseMoveEvent(
271       const gfx::Point& location) {
272     return GenerateSynthesizedMouseEventAt(ui::ET_MOUSE_MOVED, location);
273   }
274
275   // Creates a synthesized MouseWHeel event.
276   ui::MouseWheelEvent* GenerateSynthesizedMouseWheelEvent(int wheel_delta) {
277     scoped_ptr<ui::MouseEvent> mev(
278         GenerateSynthesizedMouseEventAt(ui::ET_MOUSEWHEEL, gfx::Point(0, 0)));
279     ui::MouseWheelEvent* event = new ui::MouseWheelEvent(*mev, 0, wheel_delta);
280     ui::Event::DispatcherApi dispatcher(event);
281     dispatcher.set_target(target_);
282     return event;
283   }
284
285   void SendActivateStickyKeyPattern(StickyKeysHandler* handler,
286                                     ui::KeyboardCode key_code) {
287     scoped_ptr<ui::KeyEvent> ev;
288     ev.reset(GenerateKey(true, key_code));
289     handler->HandleKeyEvent(ev.get());
290     ev.reset(GenerateKey(false, key_code));
291     handler->HandleKeyEvent(ev.get());
292   }
293
294   void SendActivateStickyKeyPattern(ui::EventProcessor* dispatcher,
295                                     ui::KeyboardCode key_code) {
296     scoped_ptr<ui::KeyEvent> ev;
297     ev.reset(GenerateKey(true, key_code));
298     ui::EventDispatchDetails details = dispatcher->OnEventFromSource(ev.get());
299     CHECK(!details.dispatcher_destroyed);
300     ev.reset(GenerateKey(false, key_code));
301     details = dispatcher->OnEventFromSource(ev.get());
302     CHECK(!details.dispatcher_destroyed);
303   }
304
305   aura::Window* target() { return target_; }
306
307  private:
308   // Owned by root window of shell, but we can still delete |target_| safely.
309   aura::Window* target_;
310   // The root window of |target_|. Not owned.
311   aura::Window* root_window_;
312
313   // Used to construct the various X events.
314   ui::ScopedXI2Event scoped_xevent_;
315
316   DISALLOW_COPY_AND_ASSIGN(StickyKeysTest);
317 };
318
319 TEST_F(StickyKeysTest, BasicOneshotScenarioTest) {
320   scoped_ptr<ui::KeyEvent> ev;
321   MockStickyKeysHandlerDelegate* mock_delegate =
322       new MockStickyKeysHandlerDelegate(this);
323   StickyKeysHandler sticky_key(ui::EF_SHIFT_DOWN, mock_delegate);
324
325   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
326
327   // By typing Shift key, internal state become ENABLED.
328   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
329   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
330
331   ev.reset(GenerateKey(true, ui::VKEY_A));
332   sticky_key.HandleKeyEvent(ev.get());
333
334   // Next keyboard event is shift modified.
335   EXPECT_TRUE(ev->flags() & ui::EF_SHIFT_DOWN);
336
337   ev.reset(GenerateKey(false, ui::VKEY_A));
338   sticky_key.HandleKeyEvent(ev.get());
339
340   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
341   // Making sure Shift up keyboard event is dispatched.
342   ASSERT_EQ(2U, mock_delegate->GetEventCount());
343   EXPECT_EQ(ui::ET_KEY_PRESSED, mock_delegate->GetEvent(0)->type());
344   EXPECT_EQ(ui::VKEY_A,
345             static_cast<const ui::KeyEvent*>(mock_delegate->GetEvent(0))
346                 ->key_code());
347   EXPECT_EQ(ui::ET_KEY_RELEASED, mock_delegate->GetEvent(1)->type());
348   EXPECT_EQ(ui::VKEY_SHIFT,
349             static_cast<const ui::KeyEvent*>(mock_delegate->GetEvent(1))
350                 ->key_code());
351
352   // Enabled state is one shot, so next key event should not be shift modified.
353   ev.reset(GenerateKey(true, ui::VKEY_A));
354   sticky_key.HandleKeyEvent(ev.get());
355   EXPECT_FALSE(ev->flags() & ui::EF_SHIFT_DOWN);
356
357   ev.reset(GenerateKey(false, ui::VKEY_A));
358   sticky_key.HandleKeyEvent(ev.get());
359   EXPECT_FALSE(ev->flags() & ui::EF_SHIFT_DOWN);
360 }
361
362 TEST_F(StickyKeysTest, BasicLockedScenarioTest) {
363   scoped_ptr<ui::KeyEvent> ev;
364   MockStickyKeysHandlerDelegate* mock_delegate =
365       new MockStickyKeysHandlerDelegate(this);
366   StickyKeysHandler sticky_key(ui::EF_SHIFT_DOWN, mock_delegate);
367
368   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
369
370   // By typing shift key, internal state become ENABLED.
371   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
372   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
373
374   // By typing shift key again, internal state become LOCKED.
375   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
376   EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
377
378   // All keyboard events including keyUp become shift modified.
379   ev.reset(GenerateKey(true, ui::VKEY_A));
380   sticky_key.HandleKeyEvent(ev.get());
381   EXPECT_TRUE(ev->flags() & ui::EF_SHIFT_DOWN);
382
383   ev.reset(GenerateKey(false, ui::VKEY_A));
384   sticky_key.HandleKeyEvent(ev.get());
385   EXPECT_TRUE(ev->flags() & ui::EF_SHIFT_DOWN);
386
387   // Locked state keeps after normal keyboard event.
388   EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
389
390   ev.reset(GenerateKey(true, ui::VKEY_B));
391   sticky_key.HandleKeyEvent(ev.get());
392   EXPECT_TRUE(ev->flags() & ui::EF_SHIFT_DOWN);
393
394   ev.reset(GenerateKey(false, ui::VKEY_B));
395   sticky_key.HandleKeyEvent(ev.get());
396   EXPECT_TRUE(ev->flags() & ui::EF_SHIFT_DOWN);
397
398   EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
399
400   // By typing shift key again, internal state become back to DISABLED.
401   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
402   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
403 }
404
405 TEST_F(StickyKeysTest, NonTargetModifierTest) {
406   scoped_ptr<ui::KeyEvent> ev;
407   MockStickyKeysHandlerDelegate* mock_delegate =
408       new MockStickyKeysHandlerDelegate(this);
409   StickyKeysHandler sticky_key(ui::EF_SHIFT_DOWN, mock_delegate);
410
411   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
412
413   // Non target modifier key does not affect internal state
414   ev.reset(GenerateKey(true, ui::VKEY_MENU));
415   sticky_key.HandleKeyEvent(ev.get());
416   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
417
418   ev.reset(GenerateKey(false, ui::VKEY_MENU));
419   sticky_key.HandleKeyEvent(ev.get());
420   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
421
422   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
423   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
424
425   // Non target modifier key does not affect internal state
426   ev.reset(GenerateKey(true, ui::VKEY_MENU));
427   sticky_key.HandleKeyEvent(ev.get());
428   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
429
430   ev.reset(GenerateKey(false, ui::VKEY_MENU));
431   sticky_key.HandleKeyEvent(ev.get());
432   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
433
434   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
435   EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
436
437   // Non target modifier key does not affect internal state
438   ev.reset(GenerateKey(true, ui::VKEY_MENU));
439   sticky_key.HandleKeyEvent(ev.get());
440   EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
441
442   ev.reset(GenerateKey(false, ui::VKEY_MENU));
443   sticky_key.HandleKeyEvent(ev.get());
444   EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
445 }
446
447 TEST_F(StickyKeysTest, NormalShortcutTest) {
448   // Sticky keys should not be enabled if we perform a normal shortcut.
449   scoped_ptr<ui::KeyEvent> ev;
450   MockStickyKeysHandlerDelegate* mock_delegate =
451       new MockStickyKeysHandlerDelegate(this);
452   StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
453
454   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
455
456   // Perform ctrl+n shortcut.
457   ev.reset(GenerateKey(true, ui::VKEY_CONTROL));
458   sticky_key.HandleKeyEvent(ev.get());
459   ev.reset(GenerateKey(true, ui::VKEY_N));
460   sticky_key.HandleKeyEvent(ev.get());
461   ev.reset(GenerateKey(false, ui::VKEY_N));
462   sticky_key.HandleKeyEvent(ev.get());
463   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
464
465   // Sticky keys should not be enabled afterwards.
466   ev.reset(GenerateKey(false, ui::VKEY_CONTROL));
467   sticky_key.HandleKeyEvent(ev.get());
468   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
469 }
470
471 TEST_F(StickyKeysTest, NormalModifiedClickTest) {
472   scoped_ptr<ui::KeyEvent> kev;
473   scoped_ptr<ui::MouseEvent> mev;
474   MockStickyKeysHandlerDelegate* mock_delegate =
475       new MockStickyKeysHandlerDelegate(this);
476   StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
477
478   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
479
480   // Perform ctrl+click.
481   kev.reset(GenerateKey(true, ui::VKEY_CONTROL));
482   sticky_key.HandleKeyEvent(kev.get());
483   mev.reset(GenerateMouseEvent(true));
484   sticky_key.HandleMouseEvent(mev.get());
485   mev.reset(GenerateMouseEvent(false));
486   sticky_key.HandleMouseEvent(mev.get());
487
488   // Sticky keys should not be enabled afterwards.
489   kev.reset(GenerateKey(false, ui::VKEY_CONTROL));
490   sticky_key.HandleKeyEvent(kev.get());
491   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
492 }
493
494 TEST_F(StickyKeysTest, MouseMovedModifierTest) {
495   scoped_ptr<ui::KeyEvent> kev;
496   scoped_ptr<ui::MouseEvent> mev;
497   MockStickyKeysHandlerDelegate* mock_delegate =
498       new MockStickyKeysHandlerDelegate(this);
499   StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
500
501   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
502
503   // Press ctrl and handle mouse move events.
504   kev.reset(GenerateKey(true, ui::VKEY_CONTROL));
505   sticky_key.HandleKeyEvent(kev.get());
506   mev.reset(GenerateSynthesizedMouseMoveEvent(gfx::Point(0, 0)));
507   sticky_key.HandleMouseEvent(mev.get());
508   mev.reset(GenerateSynthesizedMouseMoveEvent(gfx::Point(100, 100)));
509   sticky_key.HandleMouseEvent(mev.get());
510
511   // Sticky keys should be enabled afterwards.
512   kev.reset(GenerateKey(false, ui::VKEY_CONTROL));
513   sticky_key.HandleKeyEvent(kev.get());
514   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
515 }
516
517 TEST_F(StickyKeysTest, NormalModifiedScrollTest) {
518   scoped_ptr<ui::KeyEvent> kev;
519   scoped_ptr<ui::ScrollEvent> sev;
520   MockStickyKeysHandlerDelegate* mock_delegate =
521       new MockStickyKeysHandlerDelegate(this);
522   StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
523
524   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
525
526   // Perform ctrl+scroll.
527   kev.reset(GenerateKey(true, ui::VKEY_CONTROL));
528   sev.reset(GenerateFlingScrollEvent(0, true));
529   sticky_key.HandleScrollEvent(sev.get());
530   sev.reset(GenerateScrollEvent(10));
531   sticky_key.HandleScrollEvent(sev.get());
532   sev.reset(GenerateFlingScrollEvent(10, false));
533   sticky_key.HandleScrollEvent(sev.get());
534
535   // Sticky keys should not be enabled afterwards.
536   kev.reset(GenerateKey(false, ui::VKEY_CONTROL));
537   sticky_key.HandleKeyEvent(kev.get());
538   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
539 }
540
541 TEST_F(StickyKeysTest, MouseEventOneshot) {
542   scoped_ptr<ui::MouseEvent> ev;
543   scoped_ptr<ui::KeyEvent> kev;
544   MockStickyKeysHandlerDelegate* mock_delegate =
545       new MockStickyKeysHandlerDelegate(this);
546   StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
547
548   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
549   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
550   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
551
552   // We should still be in the ENABLED state until we get the mouse
553   // release event.
554   ev.reset(GenerateMouseEvent(true));
555   sticky_key.HandleMouseEvent(ev.get());
556   EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
557   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
558
559   ev.reset(GenerateMouseEvent(false));
560   sticky_key.HandleMouseEvent(ev.get());
561   EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
562   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
563
564   // Making sure modifier key release event is dispatched in the right order.
565   ASSERT_EQ(2u, mock_delegate->GetEventCount());
566   EXPECT_EQ(ui::ET_MOUSE_RELEASED, mock_delegate->GetEvent(0)->type());
567   EXPECT_EQ(ui::ET_KEY_RELEASED, mock_delegate->GetEvent(1)->type());
568   EXPECT_EQ(ui::VKEY_CONTROL,
569             static_cast<const ui::KeyEvent*>(mock_delegate->GetEvent(1))
570                 ->key_code());
571
572   // Enabled state is one shot, so next click should not be control modified.
573   ev.reset(GenerateMouseEvent(true));
574   sticky_key.HandleMouseEvent(ev.get());
575   EXPECT_FALSE(ev->flags() & ui::EF_CONTROL_DOWN);
576
577   ev.reset(GenerateMouseEvent(false));
578   sticky_key.HandleMouseEvent(ev.get());
579   EXPECT_FALSE(ev->flags() & ui::EF_CONTROL_DOWN);
580 }
581
582 TEST_F(StickyKeysTest, MouseEventLocked) {
583   scoped_ptr<ui::MouseEvent> ev;
584   scoped_ptr<ui::KeyEvent> kev;
585   MockStickyKeysHandlerDelegate* mock_delegate =
586       new MockStickyKeysHandlerDelegate(this);
587   StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
588
589   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
590
591   // Pressing modifier key twice should make us enter lock state.
592   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
593   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
594   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
595   EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
596
597   // Mouse events should not disable locked mode.
598   for (int i = 0; i < 3; ++i) {
599     ev.reset(GenerateMouseEvent(true));
600     sticky_key.HandleMouseEvent(ev.get());
601     EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
602     ev.reset(GenerateMouseEvent(false));
603     sticky_key.HandleMouseEvent(ev.get());
604     EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
605     EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
606   }
607
608   // Test with mouse wheel.
609   for (int i = 0; i < 3; ++i) {
610     ev.reset(GenerateMouseWheelEvent(ui::MouseWheelEvent::kWheelDelta));
611     sticky_key.HandleMouseEvent(ev.get());
612     ev.reset(GenerateMouseWheelEvent(-ui::MouseWheelEvent::kWheelDelta));
613     sticky_key.HandleMouseEvent(ev.get());
614     EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
615     EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
616   }
617
618   // Test mixed case with mouse events and key events.
619   ev.reset(GenerateMouseWheelEvent(ui::MouseWheelEvent::kWheelDelta));
620   sticky_key.HandleMouseEvent(ev.get());
621   EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
622   kev.reset(GenerateKey(true, ui::VKEY_N));
623   sticky_key.HandleKeyEvent(kev.get());
624   EXPECT_TRUE(kev->flags() & ui::EF_CONTROL_DOWN);
625   kev.reset(GenerateKey(false, ui::VKEY_N));
626   sticky_key.HandleKeyEvent(kev.get());
627   EXPECT_TRUE(kev->flags() & ui::EF_CONTROL_DOWN);
628
629   EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
630 }
631
632 TEST_F(StickyKeysTest, ScrollEventOneshot) {
633   // Disable Australlian scrolling.
634   ui::DeviceDataManager::GetInstance()->set_natural_scroll_enabled(true);
635
636   scoped_ptr<ui::ScrollEvent> ev;
637   scoped_ptr<ui::KeyEvent> kev;
638   MockStickyKeysHandlerDelegate* mock_delegate =
639       new MockStickyKeysHandlerDelegate(this);
640   StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
641
642   int scroll_deltas[] = {-10, 10};
643   for (int i = 0; i < 2; ++i) {
644     mock_delegate->ClearEvents();
645
646     // Enable sticky keys.
647     EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
648     SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
649     EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
650
651     // Test a scroll sequence. Sticky keys should only be disabled at the end
652     // of the scroll sequence. Fling cancel event starts the scroll sequence.
653     ev.reset(GenerateFlingScrollEvent(0, true));
654     sticky_key.HandleScrollEvent(ev.get());
655     EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
656     EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
657
658     // Scrolls should all be modified but not disable sticky keys.
659     for (int j = 0; j < 3; ++j) {
660       ev.reset(GenerateScrollEvent(scroll_deltas[i]));
661       sticky_key.HandleScrollEvent(ev.get());
662       EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
663       EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
664     }
665
666     // Fling start event ends scroll sequence.
667     ev.reset(GenerateFlingScrollEvent(scroll_deltas[i], false));
668     sticky_key.HandleScrollEvent(ev.get());
669     EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
670     EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
671
672     ASSERT_EQ(2U, mock_delegate->GetEventCount());
673     EXPECT_EQ(ui::ET_SCROLL_FLING_START, mock_delegate->GetEvent(0)->type());
674     EXPECT_FLOAT_EQ(scroll_deltas[i],
675                     static_cast<const ui::ScrollEvent*>(
676                         mock_delegate->GetEvent(0))->y_offset());
677     EXPECT_EQ(ui::ET_KEY_RELEASED, mock_delegate->GetEvent(1)->type());
678     EXPECT_EQ(ui::VKEY_CONTROL,
679               static_cast<const ui::KeyEvent*>(mock_delegate->GetEvent(1))
680                   ->key_code());
681   }
682 }
683
684 TEST_F(StickyKeysTest, ScrollDirectionChanged) {
685   // Disable Australlian scrolling.
686   ui::DeviceDataManager::GetInstance()->set_natural_scroll_enabled(true);
687
688   scoped_ptr<ui::ScrollEvent> ev;
689   scoped_ptr<ui::KeyEvent> kev;
690   MockStickyKeysHandlerDelegate* mock_delegate =
691       new MockStickyKeysHandlerDelegate(this);
692   StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
693
694   // Test direction change with both boundary value and negative value.
695   const int direction_change_values[2] = {0, -10};
696   for (int i = 0; i < 2; ++i) {
697     SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
698     EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
699
700     // Fling cancel starts scroll sequence.
701     ev.reset(GenerateFlingScrollEvent(0, true));
702     sticky_key.HandleScrollEvent(ev.get());
703     EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
704
705     // Test that changing directions in a scroll sequence will
706     // return sticky keys to DISABLED state.
707     for (int j = 0; j < 3; ++j) {
708       ev.reset(GenerateScrollEvent(10));
709       sticky_key.HandleScrollEvent(ev.get());
710       EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
711       EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
712     }
713
714     ev.reset(GenerateScrollEvent(direction_change_values[i]));
715     sticky_key.HandleScrollEvent(ev.get());
716     EXPECT_FALSE(ev->flags() & ui::EF_CONTROL_DOWN);
717     EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
718   }
719 }
720
721 TEST_F(StickyKeysTest, ScrollEventLocked) {
722   // Disable Australlian scrolling.
723   ui::DeviceDataManager::GetInstance()->set_natural_scroll_enabled(true);
724
725   scoped_ptr<ui::ScrollEvent> ev;
726   scoped_ptr<ui::KeyEvent> kev;
727   MockStickyKeysHandlerDelegate* mock_delegate =
728       new MockStickyKeysHandlerDelegate(this);
729   StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
730
731   // Lock sticky keys.
732   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
733   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
734   EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
735
736   // Test scroll events are correctly modified in locked state.
737   for (int i = 0; i < 5; ++i) {
738     // Fling cancel starts scroll sequence.
739     ev.reset(GenerateFlingScrollEvent(0, true));
740     sticky_key.HandleScrollEvent(ev.get());
741
742     ev.reset(GenerateScrollEvent(10));
743     sticky_key.HandleScrollEvent(ev.get());
744     EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
745     ev.reset(GenerateScrollEvent(-10));
746     sticky_key.HandleScrollEvent(ev.get());
747     EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
748
749     // Fling start ends scroll sequence.
750     ev.reset(GenerateFlingScrollEvent(-10, false));
751     sticky_key.HandleScrollEvent(ev.get());
752   }
753
754   EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
755 }
756
757 TEST_F(StickyKeysTest, EventTargetDestroyed) {
758   scoped_ptr<ui::KeyEvent> ev;
759   MockStickyKeysHandlerDelegate* mock_delegate =
760       new MockStickyKeysHandlerDelegate(this);
761   StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
762
763   target()->Focus();
764
765   // Go into ENABLED state.
766   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
767   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
768   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
769
770   // CTRL+J is a special shortcut that will destroy the event target.
771   ev.reset(GenerateKey(true, ui::VKEY_J));
772   sticky_key.HandleKeyEvent(ev.get());
773   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
774   EXPECT_FALSE(target());
775 }
776
777 TEST_F(StickyKeysTest, SynthesizedEvents) {
778   // Non-native, internally generated events should be properly handled
779   // by sticky keys.
780   MockStickyKeysHandlerDelegate* mock_delegate =
781       new MockStickyKeysHandlerDelegate(this);
782   StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
783
784   // Test non-native key events.
785   scoped_ptr<ui::KeyEvent> kev;
786   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
787   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
788
789   kev.reset(GenerateSynthesizedKeyEvent(true, ui::VKEY_K));
790   sticky_key.HandleKeyEvent(kev.get());
791   EXPECT_TRUE(kev->flags() & ui::EF_CONTROL_DOWN);
792   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
793
794   kev.reset(GenerateSynthesizedKeyEvent(false, ui::VKEY_K));
795   sticky_key.HandleKeyEvent(kev.get());
796   EXPECT_FALSE(kev->flags() & ui::EF_CONTROL_DOWN);
797   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
798
799   // Test non-native mouse events.
800   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
801   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
802
803   scoped_ptr<ui::MouseEvent> mev;
804   mev.reset(GenerateSynthesizedMouseClickEvent(true, gfx::Point(0, 0)));
805   sticky_key.HandleMouseEvent(mev.get());
806   EXPECT_TRUE(mev->flags() & ui::EF_CONTROL_DOWN);
807   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
808
809   mev.reset(GenerateSynthesizedMouseClickEvent(false, gfx::Point(0, 0)));
810   sticky_key.HandleMouseEvent(mev.get());
811   EXPECT_TRUE(mev->flags() & ui::EF_CONTROL_DOWN);
812   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
813 }
814
815 TEST_F(StickyKeysTest, KeyEventDispatchImpl) {
816   // Test the actual key event dispatch implementation.
817   EventBuffer buffer;
818   ScopedVector<ui::Event> events;
819   ui::EventProcessor* dispatcher =
820       Shell::GetPrimaryRootWindow()->GetHost()->event_processor();
821   Shell::GetInstance()->AddPreTargetHandler(&buffer);
822   Shell::GetInstance()->sticky_keys_controller()->Enable(true);
823
824   SendActivateStickyKeyPattern(dispatcher, ui::VKEY_CONTROL);
825   scoped_ptr<ui::KeyEvent> ev;
826   buffer.PopEvents(&events);
827
828   // Test key press event is correctly modified and modifier release
829   // event is sent.
830   ev.reset(GenerateKey(true, ui::VKEY_C));
831   ui::EventDispatchDetails details = dispatcher->OnEventFromSource(ev.get());
832   buffer.PopEvents(&events);
833   EXPECT_EQ(2u, events.size());
834   EXPECT_EQ(ui::ET_KEY_PRESSED, events[0]->type());
835   EXPECT_EQ(ui::VKEY_C, static_cast<ui::KeyEvent*>(events[0])->key_code());
836   EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
837   EXPECT_EQ(ui::ET_KEY_RELEASED, events[1]->type());
838   EXPECT_EQ(ui::VKEY_CONTROL,
839             static_cast<ui::KeyEvent*>(events[1])->key_code());
840
841   // Test key release event is not modified.
842   ev.reset(GenerateKey(false, ui::VKEY_C));
843   details = dispatcher->OnEventFromSource(ev.get());
844   ASSERT_FALSE(details.dispatcher_destroyed);
845   buffer.PopEvents(&events);
846   EXPECT_EQ(1u, events.size());
847   EXPECT_EQ(ui::ET_KEY_RELEASED, events[0]->type());
848   EXPECT_EQ(ui::VKEY_C,
849             static_cast<ui::KeyEvent*>(events[0])->key_code());
850   EXPECT_FALSE(events[0]->flags() & ui::EF_CONTROL_DOWN);
851
852   // Test that synthesized key events are dispatched correctly.
853   SendActivateStickyKeyPattern(dispatcher, ui::VKEY_CONTROL);
854   buffer.PopEvents(&events);
855   scoped_ptr<ui::KeyEvent> kev;
856   kev.reset(GenerateSynthesizedKeyEvent(true, ui::VKEY_K));
857   dispatcher->OnEventFromSource(kev.get());
858   buffer.PopEvents(&events);
859   EXPECT_EQ(2u, events.size());
860   EXPECT_EQ(ui::ET_KEY_PRESSED, events[0]->type());
861   EXPECT_EQ(ui::VKEY_K, static_cast<ui::KeyEvent*>(events[0])->key_code());
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 class StickyKeysMouseDispatchTest
871     : public StickyKeysTest,
872       public ::testing::WithParamInterface<int> {
873 };
874
875 TEST_P(StickyKeysMouseDispatchTest, MouseEventDispatchImpl) {
876   int scale_factor = GetParam();
877   std::ostringstream display_specs;
878   display_specs << "1280x1024*" << scale_factor;
879   UpdateDisplay(display_specs.str());
880
881   EventBuffer buffer;
882   ScopedVector<ui::Event> events;
883   ui::EventProcessor* dispatcher =
884       Shell::GetPrimaryRootWindow()->GetHost()->event_processor();
885   Shell::GetInstance()->AddPreTargetHandler(&buffer);
886   Shell::GetInstance()->sticky_keys_controller()->Enable(true);
887
888   scoped_ptr<ui::MouseEvent> ev;
889   SendActivateStickyKeyPattern(dispatcher, ui::VKEY_CONTROL);
890   buffer.PopEvents(&events);
891
892   // Test mouse press event is correctly modified and has correct DIP location.
893   gfx::Point physical_location(400, 400);
894   gfx::Point dip_location(physical_location.x() / scale_factor,
895                           physical_location.y() / scale_factor);
896   ev.reset(GenerateMouseEventAt(true, physical_location));
897   ui::EventDispatchDetails details = dispatcher->OnEventFromSource(ev.get());
898   buffer.PopEvents(&events);
899   EXPECT_EQ(1u, events.size());
900   EXPECT_EQ(ui::ET_MOUSE_PRESSED, events[0]->type());
901   EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
902   EXPECT_EQ(dip_location.ToString(),
903             static_cast<ui::MouseEvent*>(events[0])->location().ToString());
904
905   // Test mouse release event is correctly modified and modifier release
906   // event is sent. The mouse event should have the correct DIP location.
907   ev.reset(GenerateMouseEventAt(false, physical_location));
908   details = dispatcher->OnEventFromSource(ev.get());
909   ASSERT_FALSE(details.dispatcher_destroyed);
910   buffer.PopEvents(&events);
911   EXPECT_EQ(2u, events.size());
912   EXPECT_EQ(ui::ET_MOUSE_RELEASED, events[0]->type());
913   EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
914   EXPECT_EQ(ui::ET_KEY_RELEASED, events[1]->type());
915   EXPECT_EQ(dip_location.ToString(),
916             static_cast<ui::MouseEvent*>(events[0])->location().ToString());
917   EXPECT_EQ(ui::VKEY_CONTROL,
918             static_cast<ui::KeyEvent*>(events[1])->key_code());
919
920   // Test synthesized mouse events are dispatched correctly.
921   SendActivateStickyKeyPattern(dispatcher, ui::VKEY_CONTROL);
922   buffer.PopEvents(&events);
923   ev.reset(GenerateSynthesizedMouseClickEvent(false, physical_location));
924   dispatcher->OnEventFromSource(ev.get());
925   buffer.PopEvents(&events);
926   EXPECT_EQ(2u, events.size());
927   EXPECT_EQ(ui::ET_MOUSE_RELEASED, events[0]->type());
928   EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
929   EXPECT_EQ(dip_location.ToString(),
930             static_cast<ui::MouseEvent*>(events[0])->location().ToString());
931   EXPECT_EQ(ui::ET_KEY_RELEASED, events[1]->type());
932   EXPECT_EQ(ui::VKEY_CONTROL,
933             static_cast<ui::KeyEvent*>(events[1])->key_code());
934
935   Shell::GetInstance()->RemovePreTargetHandler(&buffer);
936 }
937
938 TEST_P(StickyKeysMouseDispatchTest, MouseWheelEventDispatchImpl) {
939   int scale_factor = GetParam();
940   std::ostringstream display_specs;
941   display_specs << "1280x1024*" << scale_factor;
942   UpdateDisplay(display_specs.str());
943
944   // Test the actual mouse wheel event dispatch implementation.
945   EventBuffer buffer;
946   ScopedVector<ui::Event> events;
947   ui::EventProcessor* dispatcher =
948       Shell::GetPrimaryRootWindow()->GetHost()->event_processor();
949   Shell::GetInstance()->AddPreTargetHandler(&buffer);
950   Shell::GetInstance()->sticky_keys_controller()->Enable(true);
951
952   scoped_ptr<ui::MouseWheelEvent> ev;
953   SendActivateStickyKeyPattern(dispatcher, ui::VKEY_CONTROL);
954   buffer.PopEvents(&events);
955
956   // Test positive mouse wheel event is correctly modified and modifier release
957   // event is sent.
958   ev.reset(GenerateMouseWheelEvent(ui::MouseWheelEvent::kWheelDelta));
959   ui::EventDispatchDetails details = dispatcher->OnEventFromSource(ev.get());
960   ASSERT_FALSE(details.dispatcher_destroyed);
961   buffer.PopEvents(&events);
962   EXPECT_EQ(2u, events.size());
963   EXPECT_TRUE(events[0]->IsMouseWheelEvent());
964   EXPECT_EQ(ui::MouseWheelEvent::kWheelDelta / scale_factor,
965             static_cast<ui::MouseWheelEvent*>(events[0])->y_offset());
966   EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
967   EXPECT_EQ(ui::ET_KEY_RELEASED, events[1]->type());
968   EXPECT_EQ(ui::VKEY_CONTROL,
969             static_cast<ui::KeyEvent*>(events[1])->key_code());
970
971   // Test negative mouse wheel event is correctly modified and modifier release
972   // event is sent.
973   SendActivateStickyKeyPattern(dispatcher, ui::VKEY_CONTROL);
974   buffer.PopEvents(&events);
975
976   ev.reset(GenerateMouseWheelEvent(-ui::MouseWheelEvent::kWheelDelta));
977   details = dispatcher->OnEventFromSource(ev.get());
978   ASSERT_FALSE(details.dispatcher_destroyed);
979   buffer.PopEvents(&events);
980   EXPECT_EQ(2u, events.size());
981   EXPECT_TRUE(events[0]->IsMouseWheelEvent());
982   EXPECT_EQ(-ui::MouseWheelEvent::kWheelDelta / scale_factor,
983             static_cast<ui::MouseWheelEvent*>(events[0])->y_offset());
984   EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
985   EXPECT_EQ(ui::ET_KEY_RELEASED, events[1]->type());
986   EXPECT_EQ(ui::VKEY_CONTROL,
987             static_cast<ui::KeyEvent*>(events[1])->key_code());
988
989   // Test synthesized mouse wheel events are dispatched correctly.
990   SendActivateStickyKeyPattern(dispatcher, ui::VKEY_CONTROL);
991   buffer.PopEvents(&events);
992   ev.reset(
993       GenerateSynthesizedMouseWheelEvent(ui::MouseWheelEvent::kWheelDelta));
994   dispatcher->OnEventFromSource(ev.get());
995   buffer.PopEvents(&events);
996   EXPECT_EQ(2u, events.size());
997   EXPECT_TRUE(events[0]->IsMouseWheelEvent());
998   EXPECT_EQ(ui::MouseWheelEvent::kWheelDelta / scale_factor,
999             static_cast<ui::MouseWheelEvent*>(events[0])->y_offset());
1000   EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
1001   EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
1002   EXPECT_EQ(ui::ET_KEY_RELEASED, events[1]->type());
1003   EXPECT_EQ(ui::VKEY_CONTROL,
1004             static_cast<ui::KeyEvent*>(events[1])->key_code());
1005
1006   Shell::GetInstance()->RemovePreTargetHandler(&buffer);
1007 }
1008
1009 INSTANTIATE_TEST_CASE_P(DPIScaleFactors,
1010                         StickyKeysMouseDispatchTest,
1011                         ::testing::Values(1, 2));
1012
1013 }  // namespace ash