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