Implement listing tests to a JSON file for iOS gtest test launcher
[chromium-blink-merge.git] / ash / sticky_keys / sticky_keys_unittest.cc
blobfeb56ad3e70264d00727488ea050ab26c90ee1b8
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 <X11/Xlib.h>
8 #undef None
9 #undef Bool
10 #undef RootWindow
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_source.h"
20 #include "ui/events/test/events_test_utils_x11.h"
22 namespace ash {
24 namespace {
26 // The device id of the test touchpad device.
27 const unsigned int kTouchPadDeviceId = 1;
29 } // namespace
31 class StickyKeysTest : public test::AshTestBase {
32 protected:
33 StickyKeysTest()
34 : target_(NULL),
35 root_window_(NULL) {}
37 virtual void SetUp() override {
38 test::AshTestBase::SetUp();
40 // |target_| owned by root window of shell. It is still safe to delete
41 // it ourselves.
42 target_ = CreateTestWindowInShellWithId(0);
43 root_window_ = target_->GetRootWindow();
45 ui::SetUpTouchPadForTest(kTouchPadDeviceId);
48 virtual void TearDown() override {
49 test::AshTestBase::TearDown();
52 virtual void OnShortcutPressed() {
53 if (target_) {
54 delete target_;
55 target_ = NULL;
59 ui::KeyEvent* GenerateKey(ui::EventType type, ui::KeyboardCode code) {
60 scoped_xevent_.InitKeyEvent(type, code, 0);
61 ui::KeyEvent* event = new ui::KeyEvent(scoped_xevent_);
62 return event;
65 // Creates a mouse event backed by a native XInput2 generic button event.
66 // This is the standard native event on Chromebooks.
67 ui::MouseEvent* GenerateMouseEvent(ui::EventType type) {
68 return GenerateMouseEventAt(type, gfx::Point());
71 // Creates a mouse event backed by a native XInput2 generic button event.
72 // The |location| should be in physical pixels.
73 ui::MouseEvent* GenerateMouseEventAt(ui::EventType type,
74 const gfx::Point& location) {
75 scoped_xevent_.InitGenericButtonEvent(
76 kTouchPadDeviceId,
77 type,
78 location,
79 0);
80 ui::MouseEvent* event = new ui::MouseEvent(scoped_xevent_);
81 return event;
84 ui::MouseWheelEvent* GenerateMouseWheelEvent(int wheel_delta) {
85 EXPECT_NE(0, wheel_delta);
86 scoped_xevent_.InitGenericMouseWheelEvent(
87 kTouchPadDeviceId, wheel_delta, 0);
88 ui::MouseWheelEvent* event = new ui::MouseWheelEvent(scoped_xevent_);
89 ui::Event::DispatcherApi dispatcher(event);
90 dispatcher.set_target(target_);
91 return event;
94 ui::ScrollEvent* GenerateScrollEvent(int scroll_delta) {
95 scoped_xevent_.InitScrollEvent(kTouchPadDeviceId, // deviceid
96 0, // x_offset
97 scroll_delta, // y_offset
98 0, // x_offset_ordinal
99 scroll_delta, // y_offset_ordinal
100 2); // finger_count
101 ui::ScrollEvent* event = new ui::ScrollEvent(scoped_xevent_);
102 ui::Event::DispatcherApi dispatcher(event);
103 dispatcher.set_target(target_);
104 return event;
107 ui::ScrollEvent* GenerateFlingScrollEvent(int fling_delta,
108 bool is_cancel) {
109 scoped_xevent_.InitFlingScrollEvent(
110 kTouchPadDeviceId, // deviceid
111 0, // x_velocity
112 fling_delta, // y_velocity
113 0, // x_velocity_ordinal
114 fling_delta, // y_velocity_ordinal
115 is_cancel); // is_cancel
116 ui::ScrollEvent* event = new ui::ScrollEvent(scoped_xevent_);
117 ui::Event::DispatcherApi dispatcher(event);
118 dispatcher.set_target(target_);
119 return event;
122 // Creates a synthesized KeyEvent that is not backed by a native event.
123 ui::KeyEvent* GenerateSynthesizedKeyEvent(ui::EventType type,
124 ui::KeyboardCode code) {
125 return new ui::KeyEvent(type, code, ui::EF_NONE);
128 // Creates a synthesized MouseEvent that is not backed by a native event.
129 ui::MouseEvent* GenerateSynthesizedMouseEventAt(ui::EventType event_type,
130 const gfx::Point& location) {
131 ui::MouseEvent* event = new ui::MouseEvent(event_type,
132 location,
133 location,
134 ui::EF_LEFT_MOUSE_BUTTON,
135 ui::EF_LEFT_MOUSE_BUTTON);
136 ui::Event::DispatcherApi dispatcher(event);
137 dispatcher.set_target(target_);
138 return event;
141 // Creates a synthesized mouse press or release event.
142 ui::MouseEvent* GenerateSynthesizedMouseClickEvent(
143 ui::EventType type,
144 const gfx::Point& location) {
145 return GenerateSynthesizedMouseEventAt(type, location);
148 // Creates a synthesized ET_MOUSE_MOVED event.
149 ui::MouseEvent* GenerateSynthesizedMouseMoveEvent(
150 const gfx::Point& location) {
151 return GenerateSynthesizedMouseEventAt(ui::ET_MOUSE_MOVED, location);
154 // Creates a synthesized MouseWHeel event.
155 ui::MouseWheelEvent* GenerateSynthesizedMouseWheelEvent(int wheel_delta) {
156 scoped_ptr<ui::MouseEvent> mev(
157 GenerateSynthesizedMouseEventAt(ui::ET_MOUSEWHEEL, gfx::Point(0, 0)));
158 ui::MouseWheelEvent* event = new ui::MouseWheelEvent(*mev, 0, wheel_delta);
159 ui::Event::DispatcherApi dispatcher(event);
160 dispatcher.set_target(target_);
161 return event;
164 void SendActivateStickyKeyPattern(StickyKeysHandler* handler,
165 ui::KeyboardCode key_code) {
166 bool released = false;
167 int down_flags = 0;
168 scoped_ptr<ui::KeyEvent> ev;
169 ev.reset(GenerateKey(ui::ET_KEY_PRESSED, key_code));
170 handler->HandleKeyEvent(*ev.get(), key_code, &down_flags, &released);
171 ev.reset(GenerateKey(ui::ET_KEY_RELEASED, key_code));
172 handler->HandleKeyEvent(*ev.get(), key_code, &down_flags, &released);
175 bool HandleKeyEvent(const ui::KeyEvent& key_event,
176 StickyKeysHandler* handler,
177 int* down,
178 bool* up) {
179 return handler->HandleKeyEvent(key_event, key_event.key_code(), down, up);
182 int HandleKeyEventForDownFlags(const ui::KeyEvent& key_event,
183 StickyKeysHandler* handler) {
184 bool released = false;
185 int down = 0;
186 handler->HandleKeyEvent(key_event, key_event.key_code(), &down, &released);
187 return down;
190 aura::Window* target() { return target_; }
192 private:
193 // Owned by root window of shell, but we can still delete |target_| safely.
194 aura::Window* target_;
195 // The root window of |target_|. Not owned.
196 aura::Window* root_window_;
198 // Used to construct the various X events.
199 ui::ScopedXI2Event scoped_xevent_;
201 DISALLOW_COPY_AND_ASSIGN(StickyKeysTest);
204 TEST_F(StickyKeysTest, BasicOneshotScenarioTest) {
205 scoped_ptr<ui::KeyEvent> ev;
206 StickyKeysHandler sticky_key(ui::EF_SHIFT_DOWN);
208 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
210 // By typing Shift key, internal state become ENABLED.
211 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
212 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
214 ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_A));
215 bool released = false;
216 int mod_down_flags = 0;
217 HandleKeyEvent(*ev.get(), &sticky_key, &mod_down_flags, &released);
218 // Next keyboard event is shift modified.
219 EXPECT_TRUE(mod_down_flags & ui::EF_SHIFT_DOWN);
220 // Modifier release notification happens.
221 EXPECT_TRUE(released);
223 ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_A));
224 released = false;
225 mod_down_flags = 0;
226 HandleKeyEvent(*ev.get(), &sticky_key, &mod_down_flags, &released);
228 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
229 // Making sure Shift up keyboard event is available.
230 scoped_ptr<ui::Event> up_event;
231 ASSERT_EQ(0, sticky_key.GetModifierUpEvent(&up_event));
232 EXPECT_TRUE(up_event.get());
233 EXPECT_EQ(ui::ET_KEY_RELEASED, up_event->type());
234 EXPECT_EQ(ui::VKEY_SHIFT,
235 static_cast<const ui::KeyEvent*>(up_event.get())->key_code());
237 // Enabled state is one shot, so next key event should not be shift modified.
238 ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_A));
239 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
240 EXPECT_FALSE(mod_down_flags & ui::EF_SHIFT_DOWN);
242 ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_A));
243 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
244 EXPECT_FALSE(mod_down_flags & ui::EF_SHIFT_DOWN);
247 TEST_F(StickyKeysTest, BasicLockedScenarioTest) {
248 scoped_ptr<ui::KeyEvent> ev;
249 StickyKeysHandler sticky_key(ui::EF_SHIFT_DOWN);
251 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
253 // By typing shift key, internal state become ENABLED.
254 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
255 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
257 // By typing shift key again, internal state become LOCKED.
258 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
259 EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
261 // All keyboard events including keyUp become shift modified.
262 ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_A));
263 int mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
264 EXPECT_TRUE(mod_down_flags & ui::EF_SHIFT_DOWN);
266 ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_A));
267 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
268 EXPECT_TRUE(mod_down_flags & ui::EF_SHIFT_DOWN);
270 // Locked state keeps after normal keyboard event.
271 EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
273 ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_B));
274 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
275 EXPECT_TRUE(mod_down_flags & ui::EF_SHIFT_DOWN);
277 ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_B));
278 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
279 EXPECT_TRUE(mod_down_flags & ui::EF_SHIFT_DOWN);
281 EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
283 // By typing shift key again, internal state become back to DISABLED.
284 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
285 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
288 TEST_F(StickyKeysTest, NonTargetModifierTest) {
289 scoped_ptr<ui::KeyEvent> ev;
290 StickyKeysHandler sticky_key(ui::EF_SHIFT_DOWN);
292 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
294 // Non target modifier key does not affect internal state
295 ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_MENU));
296 int mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
297 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
298 EXPECT_EQ(ui::EF_NONE, mod_down_flags);
300 ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_MENU));
301 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
302 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
303 EXPECT_EQ(ui::EF_NONE, mod_down_flags);
305 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
306 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
308 // Non target modifier key does not affect internal state
309 ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_MENU));
310 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
311 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
312 EXPECT_EQ(ui::EF_NONE, mod_down_flags);
314 ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_MENU));
315 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
316 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
317 EXPECT_EQ(ui::EF_NONE, mod_down_flags);
319 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
320 EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
322 // Non target modifier key does not affect internal state
323 ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_MENU));
324 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
325 EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
326 EXPECT_EQ(ui::EF_NONE, mod_down_flags);
328 ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_MENU));
329 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
330 EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
331 EXPECT_EQ(ui::EF_NONE, mod_down_flags);
334 TEST_F(StickyKeysTest, NormalShortcutTest) {
335 // Sticky keys should not be enabled if we perform a normal shortcut.
336 scoped_ptr<ui::KeyEvent> ev;
337 StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
339 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
341 // Perform ctrl+n shortcut.
342 ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL));
343 int mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
344 ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_N));
345 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
346 ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_N));
347 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
348 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
349 ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL));
350 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
352 // Sticky keys should not be enabled afterwards.
353 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
354 EXPECT_EQ(ui::EF_NONE, mod_down_flags);
356 // Perform ctrl+n shortcut, releasing ctrl first.
357 ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL));
358 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
359 ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_N));
360 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
361 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
362 ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL));
363 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
364 ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_N));
365 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
367 // Sticky keys should not be enabled afterwards.
368 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
369 EXPECT_EQ(ui::EF_NONE, mod_down_flags);
372 TEST_F(StickyKeysTest, NormalModifiedClickTest) {
373 scoped_ptr<ui::KeyEvent> kev;
374 scoped_ptr<ui::MouseEvent> mev;
375 StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
377 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
379 // Perform ctrl+click.
380 kev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL));
381 int mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
382 mev.reset(GenerateMouseEvent(ui::ET_MOUSE_PRESSED));
383 bool released = false;
384 sticky_key.HandleMouseEvent(*mev.get(), &mod_down_flags, &released);
385 mev.reset(GenerateMouseEvent(ui::ET_MOUSE_RELEASED));
386 sticky_key.HandleMouseEvent(*mev.get(), &mod_down_flags, &released);
388 // Sticky keys should not be enabled afterwards.
389 kev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL));
390 mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
391 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
392 EXPECT_EQ(ui::EF_NONE, mod_down_flags);
395 TEST_F(StickyKeysTest, MouseMovedModifierTest) {
396 scoped_ptr<ui::KeyEvent> kev;
397 scoped_ptr<ui::MouseEvent> mev;
398 StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
400 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
402 // Press ctrl and handle mouse move events.
403 kev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL));
404 int mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
405 mev.reset(GenerateSynthesizedMouseMoveEvent(gfx::Point(0, 0)));
406 bool released = false;
407 sticky_key.HandleMouseEvent(*mev.get(), &mod_down_flags, &released);
408 mev.reset(GenerateSynthesizedMouseMoveEvent(gfx::Point(100, 100)));
409 sticky_key.HandleMouseEvent(*mev.get(), &mod_down_flags, &released);
411 // Sticky keys should be enabled afterwards.
412 kev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL));
413 mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
414 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
415 EXPECT_EQ(ui::EF_NONE, mod_down_flags);
418 TEST_F(StickyKeysTest, NormalModifiedScrollTest) {
419 scoped_ptr<ui::KeyEvent> kev;
420 scoped_ptr<ui::ScrollEvent> sev;
421 StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
423 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
425 // Perform ctrl+scroll.
426 kev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL));
427 int mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
428 sev.reset(GenerateFlingScrollEvent(0, true));
429 bool released = false;
430 sticky_key.HandleScrollEvent(*sev.get(), &mod_down_flags, &released);
431 sev.reset(GenerateScrollEvent(10));
432 sticky_key.HandleScrollEvent(*sev.get(), &mod_down_flags, &released);
433 sev.reset(GenerateFlingScrollEvent(10, false));
434 sticky_key.HandleScrollEvent(*sev.get(), &mod_down_flags, &released);
436 // Sticky keys should not be enabled afterwards.
437 kev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL));
438 mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
439 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
440 EXPECT_EQ(ui::EF_NONE, mod_down_flags);
443 TEST_F(StickyKeysTest, MouseEventOneshot) {
444 scoped_ptr<ui::MouseEvent> ev;
445 scoped_ptr<ui::KeyEvent> kev;
446 StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
448 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
449 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
450 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
452 // We should still be in the ENABLED state until we get the mouse
453 // release event.
454 ev.reset(GenerateMouseEvent(ui::ET_MOUSE_PRESSED));
455 bool released = false;
456 int mod_down_flags = 0;
457 sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
458 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
459 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
461 ev.reset(GenerateMouseEvent(ui::ET_MOUSE_RELEASED));
462 released = false;
463 mod_down_flags = 0;
464 sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
465 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
466 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
468 // Making sure modifier key release event is dispatched in the right order.
469 EXPECT_TRUE(released);
470 scoped_ptr<ui::Event> up_event;
471 ASSERT_EQ(0, sticky_key.GetModifierUpEvent(&up_event));
472 EXPECT_TRUE(up_event.get());
473 EXPECT_EQ(ui::ET_KEY_RELEASED, up_event->type());
474 EXPECT_EQ(ui::VKEY_CONTROL,
475 static_cast<const ui::KeyEvent*>(up_event.get())->key_code());
477 // Enabled state is one shot, so next click should not be control modified.
478 ev.reset(GenerateMouseEvent(ui::ET_MOUSE_PRESSED));
479 released = false;
480 mod_down_flags = 0;
481 sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
482 EXPECT_FALSE(mod_down_flags & ui::EF_CONTROL_DOWN);
484 ev.reset(GenerateMouseEvent(ui::ET_MOUSE_RELEASED));
485 released = false;
486 mod_down_flags = 0;
487 sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
488 EXPECT_FALSE(mod_down_flags & ui::EF_CONTROL_DOWN);
491 TEST_F(StickyKeysTest, MouseEventLocked) {
492 scoped_ptr<ui::MouseEvent> ev;
493 scoped_ptr<ui::KeyEvent> kev;
494 StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
496 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
498 // Pressing modifier key twice should make us enter lock state.
499 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
500 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
501 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
502 EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
504 // Mouse events should not disable locked mode.
505 for (int i = 0; i < 3; ++i) {
506 bool released = false;
507 int mod_down_flags = 0;
508 ev.reset(GenerateMouseEvent(ui::ET_MOUSE_PRESSED));
509 sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
510 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
511 ev.reset(GenerateMouseEvent(ui::ET_MOUSE_RELEASED));
512 released = false;
513 mod_down_flags = 0;
514 sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
515 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
516 EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
519 // Test with mouse wheel.
520 for (int i = 0; i < 3; ++i) {
521 bool released = false;
522 int mod_down_flags = 0;
523 ev.reset(GenerateMouseWheelEvent(ui::MouseWheelEvent::kWheelDelta));
524 sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
525 ev.reset(GenerateMouseWheelEvent(-ui::MouseWheelEvent::kWheelDelta));
526 released = false;
527 mod_down_flags = 0;
528 sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
529 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
530 EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
533 // Test mixed case with mouse events and key events.
534 ev.reset(GenerateMouseWheelEvent(ui::MouseWheelEvent::kWheelDelta));
535 bool released = false;
536 int mod_down_flags = 0;
537 sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
538 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
539 kev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_N));
540 mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
541 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
542 mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
543 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
545 EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
548 TEST_F(StickyKeysTest, ScrollEventOneshot) {
549 scoped_ptr<ui::ScrollEvent> ev;
550 scoped_ptr<ui::KeyEvent> kev;
551 StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
553 int scroll_deltas[] = {-10, 10};
554 for (int i = 0; i < 2; ++i) {
555 // Enable sticky keys.
556 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
557 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
558 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
560 // Test a scroll sequence. Sticky keys should only be disabled at the end
561 // of the scroll sequence. Fling cancel event starts the scroll sequence.
562 ev.reset(GenerateFlingScrollEvent(0, true));
563 bool released = false;
564 int mod_down_flags = 0;
565 sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
566 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
567 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
569 // Scrolls should all be modified but not disable sticky keys.
570 for (int j = 0; j < 3; ++j) {
571 ev.reset(GenerateScrollEvent(scroll_deltas[i]));
572 released = false;
573 mod_down_flags = 0;
574 sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
575 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
576 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
579 // Fling start event ends scroll sequence.
580 ev.reset(GenerateFlingScrollEvent(scroll_deltas[i], false));
581 released = false;
582 mod_down_flags = 0;
583 sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
584 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
585 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
587 scoped_ptr<ui::Event> up_event;
588 EXPECT_TRUE(released);
589 ASSERT_EQ(0, sticky_key.GetModifierUpEvent(&up_event));
590 EXPECT_TRUE(up_event.get());
591 EXPECT_EQ(ui::ET_KEY_RELEASED, up_event->type());
592 EXPECT_EQ(ui::VKEY_CONTROL,
593 static_cast<const ui::KeyEvent*>(up_event.get())->key_code());
597 TEST_F(StickyKeysTest, ScrollDirectionChanged) {
598 scoped_ptr<ui::ScrollEvent> ev;
599 scoped_ptr<ui::KeyEvent> kev;
600 StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
602 // Test direction change with both boundary value and negative value.
603 const int direction_change_values[2] = {0, -10};
604 for (int i = 0; i < 2; ++i) {
605 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
606 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
608 // Fling cancel starts scroll sequence.
609 ev.reset(GenerateFlingScrollEvent(0, true));
610 bool released = false;
611 int mod_down_flags = 0;
612 sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
613 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
615 // Test that changing directions in a scroll sequence will
616 // return sticky keys to DISABLED state.
617 for (int j = 0; j < 3; ++j) {
618 ev.reset(GenerateScrollEvent(10));
619 released = false;
620 mod_down_flags = 0;
621 sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
622 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
623 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
626 ev.reset(GenerateScrollEvent(direction_change_values[i]));
627 released = false;
628 mod_down_flags = 0;
629 sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
630 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
634 TEST_F(StickyKeysTest, ScrollEventLocked) {
635 scoped_ptr<ui::ScrollEvent> ev;
636 scoped_ptr<ui::KeyEvent> kev;
637 StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
639 // Lock sticky keys.
640 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
641 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
642 EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
644 // Test scroll events are correctly modified in locked state.
645 for (int i = 0; i < 5; ++i) {
646 // Fling cancel starts scroll sequence.
647 ev.reset(GenerateFlingScrollEvent(0, true));
648 bool released = false;
649 int mod_down_flags = 0;
650 sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
652 ev.reset(GenerateScrollEvent(10));
653 released = false;
654 mod_down_flags = 0;
655 sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
656 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
657 ev.reset(GenerateScrollEvent(-10));
658 sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
659 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
661 // Fling start ends scroll sequence.
662 ev.reset(GenerateFlingScrollEvent(-10, false));
663 sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
666 EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
669 TEST_F(StickyKeysTest, SynthesizedEvents) {
670 // Non-native, internally generated events should be properly handled
671 // by sticky keys.
672 StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
674 // Test non-native key events.
675 scoped_ptr<ui::KeyEvent> kev;
676 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
677 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
679 kev.reset(GenerateSynthesizedKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_K));
680 int mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
681 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
682 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
684 kev.reset(GenerateSynthesizedKeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_K));
685 mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
686 EXPECT_FALSE(mod_down_flags & ui::EF_CONTROL_DOWN);
687 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
689 // Test non-native mouse events.
690 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
691 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
693 scoped_ptr<ui::MouseEvent> mev;
694 mev.reset(GenerateSynthesizedMouseClickEvent(ui::ET_MOUSE_PRESSED,
695 gfx::Point(0, 0)));
696 bool released = false;
697 sticky_key.HandleMouseEvent(*mev.get(), &mod_down_flags, &released);
698 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
699 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
701 mev.reset(GenerateSynthesizedMouseClickEvent(ui::ET_MOUSE_RELEASED,
702 gfx::Point(0, 0)));
703 released = false;
704 mod_down_flags = 0;
705 sticky_key.HandleMouseEvent(*mev.get(), &mod_down_flags, &released);
706 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
707 EXPECT_TRUE(released);
708 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
711 } // namespace ash