Revert "Reland c91b178b07b0d - Delete dead signin code (SigninGlobalError)"
[chromium-blink-merge.git] / ash / sticky_keys / sticky_keys_unittest.cc
blob87d32065ce223bc39fa5a8cfdce40d354d6abcf0
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.
5 #include "ash/sticky_keys/sticky_keys_controller.h"
7 #include "ash/shell.h"
8 #include "ash/test/ash_test_base.h"
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/memory/scoped_vector.h"
12 #include "ui/aura/window.h"
13 #include "ui/aura/window_tree_host.h"
14 #include "ui/events/event_source.h"
15 #include "ui/events/event_utils.h"
17 #if defined(USE_X11)
18 #include <X11/Xlib.h>
19 #undef None
20 #undef Bool
21 #undef RootWindow
22 #include "ui/events/test/events_test_utils_x11.h"
23 #endif // USE_X11
25 namespace ash {
27 namespace {
29 #if defined(USE_X11)
30 // The device id of the test touchpad device.
31 const unsigned int kTouchPadDeviceId = 1;
32 #endif
34 } // namespace
36 class StickyKeysTest : public test::AshTestBase {
37 protected:
38 StickyKeysTest()
39 : target_(NULL),
40 root_window_(NULL) {}
42 void SetUp() override {
43 test::AshTestBase::SetUp();
45 // |target_| owned by root window of shell. It is still safe to delete
46 // it ourselves.
47 target_ = CreateTestWindowInShellWithId(0);
48 root_window_ = target_->GetRootWindow();
50 #if defined(USE_X11)
51 ui::SetUpTouchPadForTest(kTouchPadDeviceId);
52 #endif
55 void TearDown() override { test::AshTestBase::TearDown(); }
57 virtual void OnShortcutPressed() {
58 if (target_) {
59 delete target_;
60 target_ = NULL;
64 ui::KeyEvent* GenerateKey(ui::EventType type, ui::KeyboardCode code) {
65 #if defined(USE_X11)
66 scoped_xevent_.InitKeyEvent(type, code, 0);
67 return new ui::KeyEvent(scoped_xevent_);
68 #else
69 return GenerateSynthesizedKeyEvent(type, code);
70 #endif
73 // Creates a mouse event backed by a native XInput2 generic button event.
74 // This is the standard native event on Chromebooks.
75 ui::MouseEvent* GenerateMouseEvent(ui::EventType type) {
76 return GenerateMouseEventAt(type, gfx::Point());
79 // Creates a mouse event backed by a native XInput2 generic button event.
80 // The |location| should be in physical pixels.
81 ui::MouseEvent* GenerateMouseEventAt(ui::EventType type,
82 const gfx::Point& location) {
83 #if defined(USE_X11)
84 scoped_xevent_.InitGenericButtonEvent(
85 kTouchPadDeviceId,
86 type,
87 location,
88 0);
89 return new ui::MouseEvent(scoped_xevent_);
90 #else
91 return GenerateSynthesizedMouseEventAt(type, location);
92 #endif
95 ui::MouseWheelEvent* GenerateMouseWheelEvent(int wheel_delta) {
96 #if defined(USE_X11)
97 EXPECT_NE(0, wheel_delta);
98 scoped_xevent_.InitGenericMouseWheelEvent(
99 kTouchPadDeviceId, wheel_delta, 0);
100 ui::MouseWheelEvent* event = new ui::MouseWheelEvent(scoped_xevent_);
101 ui::Event::DispatcherApi dispatcher(event);
102 dispatcher.set_target(target_);
103 return event;
104 #else
105 return GenerateSynthesizedMouseWheelEvent(wheel_delta);
106 #endif
109 ui::ScrollEvent* GenerateScrollEvent(int scroll_delta) {
110 #if defined(USE_X11)
111 scoped_xevent_.InitScrollEvent(kTouchPadDeviceId, // deviceid
112 0, // x_offset
113 scroll_delta, // y_offset
114 0, // x_offset_ordinal
115 scroll_delta, // y_offset_ordinal
116 2); // finger_count
117 ui::ScrollEvent* event = new ui::ScrollEvent(scoped_xevent_);
118 ui::Event::DispatcherApi dispatcher(event);
119 dispatcher.set_target(target_);
120 return event;
121 #else
122 ui::ScrollEvent* event = new ui::ScrollEvent(
123 ui::ET_SCROLL, gfx::Point(0, 0), ui::EventTimeForNow(), ui::EF_NONE,
124 0, // x_offset
125 scroll_delta, // y_offset
126 0, // x_offset_ordinal
127 scroll_delta, // y_offset_ordinal
128 2); // finger_count
129 ui::Event::DispatcherApi dispatcher(event);
130 dispatcher.set_target(target_);
131 return event;
132 #endif
135 ui::ScrollEvent* GenerateFlingScrollEvent(int fling_delta,
136 bool is_cancel) {
137 #if defined(USE_X11)
138 scoped_xevent_.InitFlingScrollEvent(
139 kTouchPadDeviceId, // deviceid
140 0, // x_velocity
141 fling_delta, // y_velocity
142 0, // x_velocity_ordinal
143 fling_delta, // y_velocity_ordinal
144 is_cancel); // is_cancel
145 ui::ScrollEvent* event = new ui::ScrollEvent(scoped_xevent_);
146 ui::Event::DispatcherApi dispatcher(event);
147 dispatcher.set_target(target_);
148 return event;
149 #else
150 ui::ScrollEvent* event = new ui::ScrollEvent(
151 is_cancel ? ui::ET_SCROLL_FLING_CANCEL : ui::ET_SCROLL_FLING_START,
152 gfx::Point(0, 0), ui::EventTimeForNow(), ui::EF_NONE,
153 0, // x_velocity
154 fling_delta, // y_velocity
155 0, // x_velocity_ordinal
156 fling_delta, // y_velocity_ordinal
157 11); // finger_count
158 ui::Event::DispatcherApi dispatcher(event);
159 dispatcher.set_target(target_);
160 return event;
161 #endif
164 // Creates a synthesized KeyEvent that is not backed by a native event.
165 ui::KeyEvent* GenerateSynthesizedKeyEvent(ui::EventType type,
166 ui::KeyboardCode code) {
167 return new ui::KeyEvent(type, code, ui::EF_NONE);
170 // Creates a synthesized MouseEvent that is not backed by a native event.
171 ui::MouseEvent* GenerateSynthesizedMouseEventAt(ui::EventType event_type,
172 const gfx::Point& location) {
173 ui::MouseEvent* event = new ui::MouseEvent(
174 event_type, location, location, ui::EventTimeForNow(),
175 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
176 ui::Event::DispatcherApi dispatcher(event);
177 dispatcher.set_target(target_);
178 return event;
181 // Creates a synthesized mouse press or release event.
182 ui::MouseEvent* GenerateSynthesizedMouseClickEvent(
183 ui::EventType type,
184 const gfx::Point& location) {
185 return GenerateSynthesizedMouseEventAt(type, location);
188 // Creates a synthesized ET_MOUSE_MOVED event.
189 ui::MouseEvent* GenerateSynthesizedMouseMoveEvent(
190 const gfx::Point& location) {
191 return GenerateSynthesizedMouseEventAt(ui::ET_MOUSE_MOVED, location);
194 // Creates a synthesized MouseWHeel event.
195 ui::MouseWheelEvent* GenerateSynthesizedMouseWheelEvent(int wheel_delta) {
196 scoped_ptr<ui::MouseEvent> mev(
197 GenerateSynthesizedMouseEventAt(ui::ET_MOUSEWHEEL, gfx::Point(0, 0)));
198 ui::MouseWheelEvent* event = new ui::MouseWheelEvent(*mev, 0, wheel_delta);
199 ui::Event::DispatcherApi dispatcher(event);
200 dispatcher.set_target(target_);
201 return event;
204 void SendActivateStickyKeyPattern(StickyKeysHandler* handler,
205 ui::KeyboardCode key_code) {
206 bool released = false;
207 int down_flags = 0;
208 scoped_ptr<ui::KeyEvent> ev;
209 ev.reset(GenerateKey(ui::ET_KEY_PRESSED, key_code));
210 handler->HandleKeyEvent(*ev.get(), key_code, &down_flags, &released);
211 ev.reset(GenerateKey(ui::ET_KEY_RELEASED, key_code));
212 handler->HandleKeyEvent(*ev.get(), key_code, &down_flags, &released);
215 bool HandleKeyEvent(const ui::KeyEvent& key_event,
216 StickyKeysHandler* handler,
217 int* down,
218 bool* up) {
219 return handler->HandleKeyEvent(key_event, key_event.key_code(), down, up);
222 int HandleKeyEventForDownFlags(const ui::KeyEvent& key_event,
223 StickyKeysHandler* handler) {
224 bool released = false;
225 int down = 0;
226 handler->HandleKeyEvent(key_event, key_event.key_code(), &down, &released);
227 return down;
230 aura::Window* target() { return target_; }
232 private:
233 // Owned by root window of shell, but we can still delete |target_| safely.
234 aura::Window* target_;
235 // The root window of |target_|. Not owned.
236 aura::Window* root_window_;
238 #if defined(USE_X11)
239 // Used to construct the various X events.
240 ui::ScopedXI2Event scoped_xevent_;
241 #endif
243 DISALLOW_COPY_AND_ASSIGN(StickyKeysTest);
246 TEST_F(StickyKeysTest, BasicOneshotScenarioTest) {
247 scoped_ptr<ui::KeyEvent> ev;
248 StickyKeysHandler sticky_key(ui::EF_SHIFT_DOWN);
250 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
252 // By typing Shift key, internal state become ENABLED.
253 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
254 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
256 ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_A));
257 bool released = false;
258 int mod_down_flags = 0;
259 HandleKeyEvent(*ev.get(), &sticky_key, &mod_down_flags, &released);
260 // Next keyboard event is shift modified.
261 EXPECT_TRUE(mod_down_flags & ui::EF_SHIFT_DOWN);
262 // Modifier release notification happens.
263 EXPECT_TRUE(released);
265 ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_A));
266 released = false;
267 mod_down_flags = 0;
268 HandleKeyEvent(*ev.get(), &sticky_key, &mod_down_flags, &released);
270 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
271 // Making sure Shift up keyboard event is available.
272 scoped_ptr<ui::Event> up_event;
273 ASSERT_EQ(0, sticky_key.GetModifierUpEvent(&up_event));
274 EXPECT_TRUE(up_event.get());
275 EXPECT_EQ(ui::ET_KEY_RELEASED, up_event->type());
276 EXPECT_EQ(ui::VKEY_SHIFT,
277 static_cast<const ui::KeyEvent*>(up_event.get())->key_code());
279 // Enabled state is one shot, so next key event should not be shift modified.
280 ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_A));
281 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
282 EXPECT_FALSE(mod_down_flags & ui::EF_SHIFT_DOWN);
284 ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_A));
285 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
286 EXPECT_FALSE(mod_down_flags & ui::EF_SHIFT_DOWN);
289 TEST_F(StickyKeysTest, BasicLockedScenarioTest) {
290 scoped_ptr<ui::KeyEvent> ev;
291 StickyKeysHandler sticky_key(ui::EF_SHIFT_DOWN);
293 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
295 // By typing shift key, internal state become ENABLED.
296 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
297 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
299 // By typing shift key again, internal state become LOCKED.
300 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
301 EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
303 // All keyboard events including keyUp become shift modified.
304 ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_A));
305 int mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
306 EXPECT_TRUE(mod_down_flags & ui::EF_SHIFT_DOWN);
308 ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_A));
309 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
310 EXPECT_TRUE(mod_down_flags & ui::EF_SHIFT_DOWN);
312 // Locked state keeps after normal keyboard event.
313 EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
315 ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_B));
316 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
317 EXPECT_TRUE(mod_down_flags & ui::EF_SHIFT_DOWN);
319 ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_B));
320 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
321 EXPECT_TRUE(mod_down_flags & ui::EF_SHIFT_DOWN);
323 EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
325 // By typing shift key again, internal state become back to DISABLED.
326 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
327 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
330 TEST_F(StickyKeysTest, NonTargetModifierTest) {
331 scoped_ptr<ui::KeyEvent> ev;
332 StickyKeysHandler sticky_key(ui::EF_SHIFT_DOWN);
334 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
336 // Non target modifier key does not affect internal state
337 ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_MENU));
338 int mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
339 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
340 EXPECT_EQ(ui::EF_NONE, mod_down_flags);
342 ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_MENU));
343 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
344 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
345 EXPECT_EQ(ui::EF_NONE, mod_down_flags);
347 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
348 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
350 // Non target modifier key does not affect internal state
351 ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_MENU));
352 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
353 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
354 EXPECT_EQ(ui::EF_NONE, mod_down_flags);
356 ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_MENU));
357 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
358 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
359 EXPECT_EQ(ui::EF_NONE, mod_down_flags);
361 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
362 EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
364 // Non target modifier key does not affect internal state
365 ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_MENU));
366 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
367 EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
368 EXPECT_EQ(ui::EF_NONE, mod_down_flags);
370 ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_MENU));
371 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
372 EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
373 EXPECT_EQ(ui::EF_NONE, mod_down_flags);
376 TEST_F(StickyKeysTest, NormalShortcutTest) {
377 // Sticky keys should not be enabled if we perform a normal shortcut.
378 scoped_ptr<ui::KeyEvent> ev;
379 StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
381 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
383 // Perform ctrl+n shortcut.
384 ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL));
385 int mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
386 ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_N));
387 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
388 ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_N));
389 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
390 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
391 ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL));
392 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
394 // Sticky keys should not be enabled afterwards.
395 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
396 EXPECT_EQ(ui::EF_NONE, mod_down_flags);
398 // Perform ctrl+n shortcut, releasing ctrl first.
399 ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL));
400 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
401 ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_N));
402 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
403 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
404 ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL));
405 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
406 ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_N));
407 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
409 // Sticky keys should not be enabled afterwards.
410 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
411 EXPECT_EQ(ui::EF_NONE, mod_down_flags);
414 TEST_F(StickyKeysTest, NormalModifiedClickTest) {
415 scoped_ptr<ui::KeyEvent> kev;
416 scoped_ptr<ui::MouseEvent> mev;
417 StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
419 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
421 // Perform ctrl+click.
422 kev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL));
423 int mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
424 mev.reset(GenerateMouseEvent(ui::ET_MOUSE_PRESSED));
425 bool released = false;
426 sticky_key.HandleMouseEvent(*mev.get(), &mod_down_flags, &released);
427 mev.reset(GenerateMouseEvent(ui::ET_MOUSE_RELEASED));
428 sticky_key.HandleMouseEvent(*mev.get(), &mod_down_flags, &released);
430 // Sticky keys should not be enabled afterwards.
431 kev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL));
432 mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
433 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
434 EXPECT_EQ(ui::EF_NONE, mod_down_flags);
437 TEST_F(StickyKeysTest, MouseMovedModifierTest) {
438 scoped_ptr<ui::KeyEvent> kev;
439 scoped_ptr<ui::MouseEvent> mev;
440 StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
442 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
444 // Press ctrl and handle mouse move events.
445 kev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL));
446 int mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
447 mev.reset(GenerateSynthesizedMouseMoveEvent(gfx::Point(0, 0)));
448 bool released = false;
449 sticky_key.HandleMouseEvent(*mev.get(), &mod_down_flags, &released);
450 mev.reset(GenerateSynthesizedMouseMoveEvent(gfx::Point(100, 100)));
451 sticky_key.HandleMouseEvent(*mev.get(), &mod_down_flags, &released);
453 // Sticky keys should be enabled afterwards.
454 kev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL));
455 mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
456 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
457 EXPECT_EQ(ui::EF_NONE, mod_down_flags);
460 TEST_F(StickyKeysTest, NormalModifiedScrollTest) {
461 scoped_ptr<ui::KeyEvent> kev;
462 scoped_ptr<ui::ScrollEvent> sev;
463 StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
465 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
467 // Perform ctrl+scroll.
468 kev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL));
469 int mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
470 sev.reset(GenerateFlingScrollEvent(0, true));
471 bool released = false;
472 sticky_key.HandleScrollEvent(*sev.get(), &mod_down_flags, &released);
473 sev.reset(GenerateScrollEvent(10));
474 sticky_key.HandleScrollEvent(*sev.get(), &mod_down_flags, &released);
475 sev.reset(GenerateFlingScrollEvent(10, false));
476 sticky_key.HandleScrollEvent(*sev.get(), &mod_down_flags, &released);
478 // Sticky keys should not be enabled afterwards.
479 kev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL));
480 mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
481 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
482 EXPECT_EQ(ui::EF_NONE, mod_down_flags);
485 TEST_F(StickyKeysTest, MouseEventOneshot) {
486 scoped_ptr<ui::MouseEvent> ev;
487 scoped_ptr<ui::KeyEvent> kev;
488 StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
490 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
491 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
492 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
494 // We should still be in the ENABLED state until we get the mouse
495 // release event.
496 ev.reset(GenerateMouseEvent(ui::ET_MOUSE_PRESSED));
497 bool released = false;
498 int mod_down_flags = 0;
499 sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
500 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
501 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
503 ev.reset(GenerateMouseEvent(ui::ET_MOUSE_RELEASED));
504 released = false;
505 mod_down_flags = 0;
506 sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
507 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
508 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
510 // Making sure modifier key release event is dispatched in the right order.
511 EXPECT_TRUE(released);
512 scoped_ptr<ui::Event> up_event;
513 ASSERT_EQ(0, sticky_key.GetModifierUpEvent(&up_event));
514 EXPECT_TRUE(up_event.get());
515 EXPECT_EQ(ui::ET_KEY_RELEASED, up_event->type());
516 EXPECT_EQ(ui::VKEY_CONTROL,
517 static_cast<const ui::KeyEvent*>(up_event.get())->key_code());
519 // Enabled state is one shot, so next click should not be control modified.
520 ev.reset(GenerateMouseEvent(ui::ET_MOUSE_PRESSED));
521 released = false;
522 mod_down_flags = 0;
523 sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
524 EXPECT_FALSE(mod_down_flags & ui::EF_CONTROL_DOWN);
526 ev.reset(GenerateMouseEvent(ui::ET_MOUSE_RELEASED));
527 released = false;
528 mod_down_flags = 0;
529 sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
530 EXPECT_FALSE(mod_down_flags & ui::EF_CONTROL_DOWN);
533 TEST_F(StickyKeysTest, MouseEventLocked) {
534 scoped_ptr<ui::MouseEvent> ev;
535 scoped_ptr<ui::KeyEvent> kev;
536 StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
538 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
540 // Pressing modifier key twice should make us enter lock state.
541 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
542 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
543 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
544 EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
546 // Mouse events should not disable locked mode.
547 for (int i = 0; i < 3; ++i) {
548 bool released = false;
549 int mod_down_flags = 0;
550 ev.reset(GenerateMouseEvent(ui::ET_MOUSE_PRESSED));
551 sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
552 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
553 ev.reset(GenerateMouseEvent(ui::ET_MOUSE_RELEASED));
554 released = false;
555 mod_down_flags = 0;
556 sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
557 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
558 EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
561 // Test with mouse wheel.
562 for (int i = 0; i < 3; ++i) {
563 bool released = false;
564 int mod_down_flags = 0;
565 ev.reset(GenerateMouseWheelEvent(ui::MouseWheelEvent::kWheelDelta));
566 sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
567 ev.reset(GenerateMouseWheelEvent(-ui::MouseWheelEvent::kWheelDelta));
568 released = false;
569 mod_down_flags = 0;
570 sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
571 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
572 EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
575 // Test mixed case with mouse events and key events.
576 ev.reset(GenerateMouseWheelEvent(ui::MouseWheelEvent::kWheelDelta));
577 bool released = false;
578 int mod_down_flags = 0;
579 sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
580 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
581 kev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_N));
582 mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
583 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
584 mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
585 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
587 EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
590 TEST_F(StickyKeysTest, ScrollEventOneshot) {
591 scoped_ptr<ui::ScrollEvent> ev;
592 scoped_ptr<ui::KeyEvent> kev;
593 StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
595 int scroll_deltas[] = {-10, 10};
596 for (int i = 0; i < 2; ++i) {
597 // Enable sticky keys.
598 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
599 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
600 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
602 // Test a scroll sequence. Sticky keys should only be disabled at the end
603 // of the scroll sequence. Fling cancel event starts the scroll sequence.
604 ev.reset(GenerateFlingScrollEvent(0, true));
605 bool released = false;
606 int mod_down_flags = 0;
607 sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
608 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
609 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
611 // Scrolls should all be modified but not disable sticky keys.
612 for (int j = 0; j < 3; ++j) {
613 ev.reset(GenerateScrollEvent(scroll_deltas[i]));
614 released = false;
615 mod_down_flags = 0;
616 sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
617 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
618 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
621 // Fling start event ends scroll sequence.
622 ev.reset(GenerateFlingScrollEvent(scroll_deltas[i], false));
623 released = false;
624 mod_down_flags = 0;
625 sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
626 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
627 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
629 scoped_ptr<ui::Event> up_event;
630 EXPECT_TRUE(released);
631 ASSERT_EQ(0, sticky_key.GetModifierUpEvent(&up_event));
632 EXPECT_TRUE(up_event.get());
633 EXPECT_EQ(ui::ET_KEY_RELEASED, up_event->type());
634 EXPECT_EQ(ui::VKEY_CONTROL,
635 static_cast<const ui::KeyEvent*>(up_event.get())->key_code());
639 TEST_F(StickyKeysTest, ScrollDirectionChanged) {
640 scoped_ptr<ui::ScrollEvent> ev;
641 scoped_ptr<ui::KeyEvent> kev;
642 StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
644 // Test direction change with both boundary value and negative value.
645 const int direction_change_values[2] = {0, -10};
646 for (int i = 0; i < 2; ++i) {
647 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
648 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
650 // Fling cancel starts scroll sequence.
651 ev.reset(GenerateFlingScrollEvent(0, true));
652 bool released = false;
653 int mod_down_flags = 0;
654 sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
655 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
657 // Test that changing directions in a scroll sequence will
658 // return sticky keys to DISABLED state.
659 for (int j = 0; j < 3; ++j) {
660 ev.reset(GenerateScrollEvent(10));
661 released = false;
662 mod_down_flags = 0;
663 sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
664 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
665 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
668 ev.reset(GenerateScrollEvent(direction_change_values[i]));
669 released = false;
670 mod_down_flags = 0;
671 sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
672 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
676 TEST_F(StickyKeysTest, ScrollEventLocked) {
677 scoped_ptr<ui::ScrollEvent> ev;
678 scoped_ptr<ui::KeyEvent> kev;
679 StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
681 // Lock sticky keys.
682 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
683 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
684 EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
686 // Test scroll events are correctly modified in locked state.
687 for (int i = 0; i < 5; ++i) {
688 // Fling cancel starts scroll sequence.
689 ev.reset(GenerateFlingScrollEvent(0, true));
690 bool released = false;
691 int mod_down_flags = 0;
692 sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
694 ev.reset(GenerateScrollEvent(10));
695 released = false;
696 mod_down_flags = 0;
697 sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
698 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
699 ev.reset(GenerateScrollEvent(-10));
700 sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
701 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
703 // Fling start ends scroll sequence.
704 ev.reset(GenerateFlingScrollEvent(-10, false));
705 sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
708 EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
711 TEST_F(StickyKeysTest, SynthesizedEvents) {
712 // Non-native, internally generated events should be properly handled
713 // by sticky keys.
714 StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
716 // Test non-native key events.
717 scoped_ptr<ui::KeyEvent> kev;
718 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
719 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
721 kev.reset(GenerateSynthesizedKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_K));
722 int mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
723 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
724 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
726 kev.reset(GenerateSynthesizedKeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_K));
727 mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
728 EXPECT_FALSE(mod_down_flags & ui::EF_CONTROL_DOWN);
729 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
731 // Test non-native mouse events.
732 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
733 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
735 scoped_ptr<ui::MouseEvent> mev;
736 mev.reset(GenerateSynthesizedMouseClickEvent(ui::ET_MOUSE_PRESSED,
737 gfx::Point(0, 0)));
738 bool released = false;
739 sticky_key.HandleMouseEvent(*mev.get(), &mod_down_flags, &released);
740 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
741 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
743 mev.reset(GenerateSynthesizedMouseClickEvent(ui::ET_MOUSE_RELEASED,
744 gfx::Point(0, 0)));
745 released = false;
746 mod_down_flags = 0;
747 sticky_key.HandleMouseEvent(*mev.get(), &mod_down_flags, &released);
748 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
749 EXPECT_TRUE(released);
750 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
753 } // namespace ash