Home | History | Annotate | Download | only in sticky_keys
      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   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 
    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 
    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 
    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 
    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 
    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 
    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 
    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