• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
EventBuffer()36   EventBuffer() {}
~EventBuffer()37   virtual ~EventBuffer() {}
38 
PopEvents(ScopedVector<ui::Event> * events)39   void PopEvents(ScopedVector<ui::Event>* events) {
40     events->clear();
41     events->swap(events_);
42   }
43 
44  private:
45   // ui::EventHandler overrides:
OnKeyEvent(ui::KeyEvent * event)46   virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE {
47     events_.push_back(new ui::KeyEvent(*event));
48   }
49 
OnMouseEvent(ui::MouseEvent * event)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:
~Delegate()74     virtual ~Delegate() {}
75   };
76 
MockStickyKeysHandlerDelegate(Delegate * delegate)77   MockStickyKeysHandlerDelegate(Delegate* delegate) : delegate_(delegate) {}
78 
~MockStickyKeysHandlerDelegate()79   virtual ~MockStickyKeysHandlerDelegate() {}
80 
81   // StickyKeysHandler override.
DispatchKeyEvent(ui::KeyEvent * event,aura::Window * target)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 
DispatchMouseEvent(ui::MouseEvent * event,aura::Window * target)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 
DispatchScrollEvent(ui::ScrollEvent * event,aura::Window * target)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.
GetEventCount() const111   size_t GetEventCount() const {
112     return events_.size();
113   }
114 
115   // Returns the |index|-th dispatched event.
GetEvent(size_t index) const116   const ui::Event* GetEvent(size_t index) const {
117     return events_[index];
118   }
119 
120   // Clears all previously dispatched events.
ClearEvents()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:
StickyKeysTest()135   StickyKeysTest()
136       : target_(NULL),
137         root_window_(NULL) {}
138 
SetUp()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 
TearDown()150   virtual void TearDown() OVERRIDE {
151     test::AshTestBase::TearDown();
152   }
153 
154   // Overridden from MockStickyKeysHandlerDelegate::Delegate:
GetExpectedTarget()155   virtual aura::Window* GetExpectedTarget() OVERRIDE {
156     return target_ ? target_ : root_window_;
157   }
158 
OnShortcutPressed()159   virtual void OnShortcutPressed() OVERRIDE {
160     if (target_) {
161       delete target_;
162       target_ = NULL;
163     }
164   }
165 
GenerateKey(bool is_key_press,ui::KeyboardCode code)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.
GenerateMouseEvent(bool is_button_press)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.
GenerateMouseEventAt(bool is_button_press,const gfx::Point & location)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 
GenerateMouseWheelEvent(int wheel_delta)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 
GenerateScrollEvent(int scroll_delta)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 
GenerateFlingScrollEvent(int fling_delta,bool is_cancel)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.
GenerateSynthesizedKeyEvent(bool is_key_press,ui::KeyboardCode code)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.
GenerateSynthesizedMouseEventAt(ui::EventType event_type,const gfx::Point & location)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.
GenerateSynthesizedMouseClickEvent(bool is_button_press,const gfx::Point & location)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.
GenerateSynthesizedMouseMoveEvent(const gfx::Point & location)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.
GenerateSynthesizedMouseWheelEvent(int wheel_delta)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 
SendActivateStickyKeyPattern(StickyKeysHandler * handler,ui::KeyboardCode key_code)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 
SendActivateStickyKeyPattern(ui::EventProcessor * dispatcher,ui::KeyboardCode key_code)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 
target()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 
TEST_F(StickyKeysTest,BasicOneshotScenarioTest)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 
TEST_F(StickyKeysTest,BasicLockedScenarioTest)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 
TEST_F(StickyKeysTest,NonTargetModifierTest)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 
TEST_F(StickyKeysTest,NormalShortcutTest)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 
TEST_F(StickyKeysTest,NormalModifiedClickTest)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 
TEST_F(StickyKeysTest,MouseMovedModifierTest)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 
TEST_F(StickyKeysTest,NormalModifiedScrollTest)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 
TEST_F(StickyKeysTest,MouseEventOneshot)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 
TEST_F(StickyKeysTest,MouseEventLocked)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 
TEST_F(StickyKeysTest,ScrollEventOneshot)632 TEST_F(StickyKeysTest, ScrollEventOneshot) {
633   scoped_ptr<ui::ScrollEvent> ev;
634   scoped_ptr<ui::KeyEvent> kev;
635   MockStickyKeysHandlerDelegate* mock_delegate =
636       new MockStickyKeysHandlerDelegate(this);
637   StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
638 
639   int scroll_deltas[] = {-10, 10};
640   for (int i = 0; i < 2; ++i) {
641     mock_delegate->ClearEvents();
642 
643     // Enable sticky keys.
644     EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
645     SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
646     EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
647 
648     // Test a scroll sequence. Sticky keys should only be disabled at the end
649     // of the scroll sequence. Fling cancel event starts the scroll sequence.
650     ev.reset(GenerateFlingScrollEvent(0, true));
651     sticky_key.HandleScrollEvent(ev.get());
652     EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
653     EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
654 
655     // Scrolls should all be modified but not disable sticky keys.
656     for (int j = 0; j < 3; ++j) {
657       ev.reset(GenerateScrollEvent(scroll_deltas[i]));
658       sticky_key.HandleScrollEvent(ev.get());
659       EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
660       EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
661     }
662 
663     // Fling start event ends scroll sequence.
664     ev.reset(GenerateFlingScrollEvent(scroll_deltas[i], false));
665     sticky_key.HandleScrollEvent(ev.get());
666     EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
667     EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
668 
669     ASSERT_EQ(2U, mock_delegate->GetEventCount());
670     EXPECT_EQ(ui::ET_SCROLL_FLING_START, mock_delegate->GetEvent(0)->type());
671     EXPECT_FLOAT_EQ(scroll_deltas[i],
672                     static_cast<const ui::ScrollEvent*>(
673                         mock_delegate->GetEvent(0))->y_offset());
674     EXPECT_EQ(ui::ET_KEY_RELEASED, mock_delegate->GetEvent(1)->type());
675     EXPECT_EQ(ui::VKEY_CONTROL,
676               static_cast<const ui::KeyEvent*>(mock_delegate->GetEvent(1))
677                   ->key_code());
678   }
679 }
680 
TEST_F(StickyKeysTest,ScrollDirectionChanged)681 TEST_F(StickyKeysTest, ScrollDirectionChanged) {
682   scoped_ptr<ui::ScrollEvent> ev;
683   scoped_ptr<ui::KeyEvent> kev;
684   MockStickyKeysHandlerDelegate* mock_delegate =
685       new MockStickyKeysHandlerDelegate(this);
686   StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
687 
688   // Test direction change with both boundary value and negative value.
689   const int direction_change_values[2] = {0, -10};
690   for (int i = 0; i < 2; ++i) {
691     SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
692     EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
693 
694     // Fling cancel starts scroll sequence.
695     ev.reset(GenerateFlingScrollEvent(0, true));
696     sticky_key.HandleScrollEvent(ev.get());
697     EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
698 
699     // Test that changing directions in a scroll sequence will
700     // return sticky keys to DISABLED state.
701     for (int j = 0; j < 3; ++j) {
702       ev.reset(GenerateScrollEvent(10));
703       sticky_key.HandleScrollEvent(ev.get());
704       EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
705       EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
706     }
707 
708     ev.reset(GenerateScrollEvent(direction_change_values[i]));
709     sticky_key.HandleScrollEvent(ev.get());
710     EXPECT_FALSE(ev->flags() & ui::EF_CONTROL_DOWN);
711     EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
712   }
713 }
714 
TEST_F(StickyKeysTest,ScrollEventLocked)715 TEST_F(StickyKeysTest, ScrollEventLocked) {
716   scoped_ptr<ui::ScrollEvent> ev;
717   scoped_ptr<ui::KeyEvent> kev;
718   MockStickyKeysHandlerDelegate* mock_delegate =
719       new MockStickyKeysHandlerDelegate(this);
720   StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
721 
722   // Lock sticky keys.
723   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
724   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
725   EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
726 
727   // Test scroll events are correctly modified in locked state.
728   for (int i = 0; i < 5; ++i) {
729     // Fling cancel starts scroll sequence.
730     ev.reset(GenerateFlingScrollEvent(0, true));
731     sticky_key.HandleScrollEvent(ev.get());
732 
733     ev.reset(GenerateScrollEvent(10));
734     sticky_key.HandleScrollEvent(ev.get());
735     EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
736     ev.reset(GenerateScrollEvent(-10));
737     sticky_key.HandleScrollEvent(ev.get());
738     EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
739 
740     // Fling start ends scroll sequence.
741     ev.reset(GenerateFlingScrollEvent(-10, false));
742     sticky_key.HandleScrollEvent(ev.get());
743   }
744 
745   EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
746 }
747 
TEST_F(StickyKeysTest,EventTargetDestroyed)748 TEST_F(StickyKeysTest, EventTargetDestroyed) {
749   scoped_ptr<ui::KeyEvent> ev;
750   MockStickyKeysHandlerDelegate* mock_delegate =
751       new MockStickyKeysHandlerDelegate(this);
752   StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
753 
754   target()->Focus();
755 
756   // Go into ENABLED state.
757   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
758   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
759   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
760 
761   // CTRL+J is a special shortcut that will destroy the event target.
762   ev.reset(GenerateKey(true, ui::VKEY_J));
763   sticky_key.HandleKeyEvent(ev.get());
764   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
765   EXPECT_FALSE(target());
766 }
767 
TEST_F(StickyKeysTest,SynthesizedEvents)768 TEST_F(StickyKeysTest, SynthesizedEvents) {
769   // Non-native, internally generated events should be properly handled
770   // by sticky keys.
771   MockStickyKeysHandlerDelegate* mock_delegate =
772       new MockStickyKeysHandlerDelegate(this);
773   StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
774 
775   // Test non-native key events.
776   scoped_ptr<ui::KeyEvent> kev;
777   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
778   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
779 
780   kev.reset(GenerateSynthesizedKeyEvent(true, ui::VKEY_K));
781   sticky_key.HandleKeyEvent(kev.get());
782   EXPECT_TRUE(kev->flags() & ui::EF_CONTROL_DOWN);
783   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
784 
785   kev.reset(GenerateSynthesizedKeyEvent(false, ui::VKEY_K));
786   sticky_key.HandleKeyEvent(kev.get());
787   EXPECT_FALSE(kev->flags() & ui::EF_CONTROL_DOWN);
788   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
789 
790   // Test non-native mouse events.
791   SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
792   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
793 
794   scoped_ptr<ui::MouseEvent> mev;
795   mev.reset(GenerateSynthesizedMouseClickEvent(true, gfx::Point(0, 0)));
796   sticky_key.HandleMouseEvent(mev.get());
797   EXPECT_TRUE(mev->flags() & ui::EF_CONTROL_DOWN);
798   EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
799 
800   mev.reset(GenerateSynthesizedMouseClickEvent(false, gfx::Point(0, 0)));
801   sticky_key.HandleMouseEvent(mev.get());
802   EXPECT_TRUE(mev->flags() & ui::EF_CONTROL_DOWN);
803   EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
804 }
805 
TEST_F(StickyKeysTest,KeyEventDispatchImpl)806 TEST_F(StickyKeysTest, KeyEventDispatchImpl) {
807   // Test the actual key event dispatch implementation.
808   EventBuffer buffer;
809   ScopedVector<ui::Event> events;
810   ui::EventProcessor* dispatcher =
811       Shell::GetPrimaryRootWindow()->GetHost()->event_processor();
812   Shell::GetInstance()->AddPreTargetHandler(&buffer);
813   Shell::GetInstance()->sticky_keys_controller()->Enable(true);
814 
815   SendActivateStickyKeyPattern(dispatcher, ui::VKEY_CONTROL);
816   scoped_ptr<ui::KeyEvent> ev;
817   buffer.PopEvents(&events);
818 
819   // Test key press event is correctly modified and modifier release
820   // event is sent.
821   ev.reset(GenerateKey(true, ui::VKEY_C));
822   ui::EventDispatchDetails details = dispatcher->OnEventFromSource(ev.get());
823   buffer.PopEvents(&events);
824   EXPECT_EQ(2u, events.size());
825   EXPECT_EQ(ui::ET_KEY_PRESSED, events[0]->type());
826   EXPECT_EQ(ui::VKEY_C, static_cast<ui::KeyEvent*>(events[0])->key_code());
827   EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
828   EXPECT_EQ(ui::ET_KEY_RELEASED, events[1]->type());
829   EXPECT_EQ(ui::VKEY_CONTROL,
830             static_cast<ui::KeyEvent*>(events[1])->key_code());
831 
832   // Test key release event is not modified.
833   ev.reset(GenerateKey(false, ui::VKEY_C));
834   details = dispatcher->OnEventFromSource(ev.get());
835   ASSERT_FALSE(details.dispatcher_destroyed);
836   buffer.PopEvents(&events);
837   EXPECT_EQ(1u, events.size());
838   EXPECT_EQ(ui::ET_KEY_RELEASED, events[0]->type());
839   EXPECT_EQ(ui::VKEY_C,
840             static_cast<ui::KeyEvent*>(events[0])->key_code());
841   EXPECT_FALSE(events[0]->flags() & ui::EF_CONTROL_DOWN);
842 
843   // Test that synthesized key events are dispatched correctly.
844   SendActivateStickyKeyPattern(dispatcher, ui::VKEY_CONTROL);
845   buffer.PopEvents(&events);
846   scoped_ptr<ui::KeyEvent> kev;
847   kev.reset(GenerateSynthesizedKeyEvent(true, ui::VKEY_K));
848   details = dispatcher->OnEventFromSource(kev.get());
849   ASSERT_FALSE(details.dispatcher_destroyed);
850   buffer.PopEvents(&events);
851   EXPECT_EQ(2u, events.size());
852   EXPECT_EQ(ui::ET_KEY_PRESSED, events[0]->type());
853   EXPECT_EQ(ui::VKEY_K, static_cast<ui::KeyEvent*>(events[0])->key_code());
854   EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
855   EXPECT_EQ(ui::ET_KEY_RELEASED, events[1]->type());
856   EXPECT_EQ(ui::VKEY_CONTROL,
857             static_cast<ui::KeyEvent*>(events[1])->key_code());
858 
859   Shell::GetInstance()->RemovePreTargetHandler(&buffer);
860 }
861 
862 class StickyKeysMouseDispatchTest
863     : public StickyKeysTest,
864       public ::testing::WithParamInterface<int> {
865 };
866 
TEST_P(StickyKeysMouseDispatchTest,MouseEventDispatchImpl)867 TEST_P(StickyKeysMouseDispatchTest, MouseEventDispatchImpl) {
868   int scale_factor = GetParam();
869   std::ostringstream display_specs;
870   display_specs << "1280x1024*" << scale_factor;
871   UpdateDisplay(display_specs.str());
872 
873   EventBuffer buffer;
874   ScopedVector<ui::Event> events;
875   ui::EventProcessor* dispatcher =
876       Shell::GetPrimaryRootWindow()->GetHost()->event_processor();
877   Shell::GetInstance()->AddPreTargetHandler(&buffer);
878   Shell::GetInstance()->sticky_keys_controller()->Enable(true);
879 
880   scoped_ptr<ui::MouseEvent> ev;
881   SendActivateStickyKeyPattern(dispatcher, ui::VKEY_CONTROL);
882   buffer.PopEvents(&events);
883 
884   // Test mouse press event is correctly modified and has correct DIP location.
885   gfx::Point physical_location(400, 400);
886   gfx::Point dip_location(physical_location.x() / scale_factor,
887                           physical_location.y() / scale_factor);
888   ev.reset(GenerateMouseEventAt(true, physical_location));
889   ui::EventDispatchDetails details = dispatcher->OnEventFromSource(ev.get());
890   buffer.PopEvents(&events);
891   EXPECT_EQ(1u, events.size());
892   EXPECT_EQ(ui::ET_MOUSE_PRESSED, events[0]->type());
893   EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
894   EXPECT_EQ(dip_location.ToString(),
895             static_cast<ui::MouseEvent*>(events[0])->location().ToString());
896 
897   // Test mouse release event is correctly modified and modifier release
898   // event is sent. The mouse event should have the correct DIP location.
899   ev.reset(GenerateMouseEventAt(false, physical_location));
900   details = dispatcher->OnEventFromSource(ev.get());
901   ASSERT_FALSE(details.dispatcher_destroyed);
902   buffer.PopEvents(&events);
903   EXPECT_EQ(2u, events.size());
904   EXPECT_EQ(ui::ET_MOUSE_RELEASED, events[0]->type());
905   EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
906   EXPECT_EQ(ui::ET_KEY_RELEASED, events[1]->type());
907   EXPECT_EQ(dip_location.ToString(),
908             static_cast<ui::MouseEvent*>(events[0])->location().ToString());
909   EXPECT_EQ(ui::VKEY_CONTROL,
910             static_cast<ui::KeyEvent*>(events[1])->key_code());
911 
912   // Test synthesized mouse events are dispatched correctly.
913   SendActivateStickyKeyPattern(dispatcher, ui::VKEY_CONTROL);
914   buffer.PopEvents(&events);
915   ev.reset(GenerateSynthesizedMouseClickEvent(false, physical_location));
916   details = dispatcher->OnEventFromSource(ev.get());
917   ASSERT_FALSE(details.dispatcher_destroyed);
918   buffer.PopEvents(&events);
919   EXPECT_EQ(2u, events.size());
920   EXPECT_EQ(ui::ET_MOUSE_RELEASED, events[0]->type());
921   EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
922   EXPECT_EQ(dip_location.ToString(),
923             static_cast<ui::MouseEvent*>(events[0])->location().ToString());
924   EXPECT_EQ(ui::ET_KEY_RELEASED, events[1]->type());
925   EXPECT_EQ(ui::VKEY_CONTROL,
926             static_cast<ui::KeyEvent*>(events[1])->key_code());
927 
928   Shell::GetInstance()->RemovePreTargetHandler(&buffer);
929 }
930 
TEST_P(StickyKeysMouseDispatchTest,MouseWheelEventDispatchImpl)931 TEST_P(StickyKeysMouseDispatchTest, MouseWheelEventDispatchImpl) {
932   int scale_factor = GetParam();
933   std::ostringstream display_specs;
934   display_specs << "1280x1024*" << scale_factor;
935   UpdateDisplay(display_specs.str());
936 
937   // Test the actual mouse wheel event dispatch implementation.
938   EventBuffer buffer;
939   ScopedVector<ui::Event> events;
940   ui::EventProcessor* dispatcher =
941       Shell::GetPrimaryRootWindow()->GetHost()->event_processor();
942   Shell::GetInstance()->AddPreTargetHandler(&buffer);
943   Shell::GetInstance()->sticky_keys_controller()->Enable(true);
944 
945   scoped_ptr<ui::MouseWheelEvent> ev;
946   SendActivateStickyKeyPattern(dispatcher, ui::VKEY_CONTROL);
947   buffer.PopEvents(&events);
948 
949   // Test positive mouse wheel event is correctly modified and modifier release
950   // event is sent.
951   ev.reset(GenerateMouseWheelEvent(ui::MouseWheelEvent::kWheelDelta));
952   ui::EventDispatchDetails details = dispatcher->OnEventFromSource(ev.get());
953   ASSERT_FALSE(details.dispatcher_destroyed);
954   buffer.PopEvents(&events);
955   EXPECT_EQ(2u, events.size());
956   EXPECT_TRUE(events[0]->IsMouseWheelEvent());
957   EXPECT_EQ(ui::MouseWheelEvent::kWheelDelta / scale_factor,
958             static_cast<ui::MouseWheelEvent*>(events[0])->y_offset());
959   EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
960   EXPECT_EQ(ui::ET_KEY_RELEASED, events[1]->type());
961   EXPECT_EQ(ui::VKEY_CONTROL,
962             static_cast<ui::KeyEvent*>(events[1])->key_code());
963 
964   // Test negative mouse wheel event is correctly modified and modifier release
965   // event is sent.
966   SendActivateStickyKeyPattern(dispatcher, ui::VKEY_CONTROL);
967   buffer.PopEvents(&events);
968 
969   ev.reset(GenerateMouseWheelEvent(-ui::MouseWheelEvent::kWheelDelta));
970   details = dispatcher->OnEventFromSource(ev.get());
971   ASSERT_FALSE(details.dispatcher_destroyed);
972   buffer.PopEvents(&events);
973   EXPECT_EQ(2u, events.size());
974   EXPECT_TRUE(events[0]->IsMouseWheelEvent());
975   EXPECT_EQ(-ui::MouseWheelEvent::kWheelDelta / scale_factor,
976             static_cast<ui::MouseWheelEvent*>(events[0])->y_offset());
977   EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
978   EXPECT_EQ(ui::ET_KEY_RELEASED, events[1]->type());
979   EXPECT_EQ(ui::VKEY_CONTROL,
980             static_cast<ui::KeyEvent*>(events[1])->key_code());
981 
982   // Test synthesized mouse wheel events are dispatched correctly.
983   SendActivateStickyKeyPattern(dispatcher, ui::VKEY_CONTROL);
984   buffer.PopEvents(&events);
985   ev.reset(
986       GenerateSynthesizedMouseWheelEvent(ui::MouseWheelEvent::kWheelDelta));
987   details = dispatcher->OnEventFromSource(ev.get());
988   ASSERT_FALSE(details.dispatcher_destroyed);
989   buffer.PopEvents(&events);
990   EXPECT_EQ(2u, events.size());
991   EXPECT_TRUE(events[0]->IsMouseWheelEvent());
992   EXPECT_EQ(ui::MouseWheelEvent::kWheelDelta / scale_factor,
993             static_cast<ui::MouseWheelEvent*>(events[0])->y_offset());
994   EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
995   EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
996   EXPECT_EQ(ui::ET_KEY_RELEASED, events[1]->type());
997   EXPECT_EQ(ui::VKEY_CONTROL,
998             static_cast<ui::KeyEvent*>(events[1])->key_code());
999 
1000   Shell::GetInstance()->RemovePreTargetHandler(&buffer);
1001 }
1002 
1003 INSTANTIATE_TEST_CASE_P(DPIScaleFactors,
1004                         StickyKeysMouseDispatchTest,
1005                         ::testing::Values(1, 2));
1006 
1007 }  // namespace ash
1008