Switch global error menu icon to vectorized MD asset
[chromium-blink-merge.git] / ash / sticky_keys / sticky_keys_unittest.cc
blobb50a6d3104578ce37ecc89aa8ee225d39c2a9ecf
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 "ui/aura/window.h"
12 #include "ui/aura/window_tree_host.h"
13 #include "ui/events/event_source.h"
14 #include "ui/events/event_utils.h"
16 #if defined(USE_X11)
17 #include <X11/Xlib.h>
18 #undef None
19 #undef Bool
20 #undef RootWindow
21 #include "ui/events/test/events_test_utils_x11.h"
22 #endif // USE_X11
24 namespace ash {
26 namespace {
28 #if defined(USE_X11)
29 // The device id of the test touchpad device.
30 const unsigned int kTouchPadDeviceId = 1;
31 #endif
33 } // namespace
35 class StickyKeysTest : public test::AshTestBase {
36 protected:
37 StickyKeysTest()
38 : target_(NULL),
39 root_window_(NULL) {}
41 void SetUp() override {
42 test::AshTestBase::SetUp();
44 // |target_| owned by root window of shell. It is still safe to delete
45 // it ourselves.
46 target_ = CreateTestWindowInShellWithId(0);
47 root_window_ = target_->GetRootWindow();
49 #if defined(USE_X11)
50 ui::SetUpTouchPadForTest(kTouchPadDeviceId);
51 #endif
54 void TearDown() override { test::AshTestBase::TearDown(); }
56 virtual void OnShortcutPressed() {
57 if (target_) {
58 delete target_;
59 target_ = NULL;
63 ui::KeyEvent* GenerateKey(ui::EventType type, ui::KeyboardCode code) {
64 #if defined(USE_X11)
65 scoped_xevent_.InitKeyEvent(type, code, 0);
66 return new ui::KeyEvent(scoped_xevent_);
67 #else
68 return GenerateSynthesizedKeyEvent(type, code);
69 #endif
72 // Creates a mouse event backed by a native XInput2 generic button event.
73 // This is the standard native event on Chromebooks.
74 ui::MouseEvent* GenerateMouseEvent(ui::EventType type) {
75 return GenerateMouseEventAt(type, gfx::Point());
78 // Creates a mouse event backed by a native XInput2 generic button event.
79 // The |location| should be in physical pixels.
80 ui::MouseEvent* GenerateMouseEventAt(ui::EventType type,
81 const gfx::Point& location) {
82 #if defined(USE_X11)
83 scoped_xevent_.InitGenericButtonEvent(
84 kTouchPadDeviceId,
85 type,
86 location,
87 0);
88 return new ui::MouseEvent(scoped_xevent_);
89 #else
90 return GenerateSynthesizedMouseEventAt(type, location);
91 #endif
94 ui::MouseWheelEvent* GenerateMouseWheelEvent(int wheel_delta) {
95 #if defined(USE_X11)
96 EXPECT_NE(0, wheel_delta);
97 scoped_xevent_.InitGenericMouseWheelEvent(
98 kTouchPadDeviceId, wheel_delta, 0);
99 ui::MouseWheelEvent* event = new ui::MouseWheelEvent(scoped_xevent_);
100 ui::Event::DispatcherApi dispatcher(event);
101 dispatcher.set_target(target_);
102 return event;
103 #else
104 return GenerateSynthesizedMouseWheelEvent(wheel_delta);
105 #endif
108 ui::ScrollEvent* GenerateScrollEvent(int scroll_delta) {
109 #if defined(USE_X11)
110 scoped_xevent_.InitScrollEvent(kTouchPadDeviceId, // deviceid
111 0, // x_offset
112 scroll_delta, // y_offset
113 0, // x_offset_ordinal
114 scroll_delta, // y_offset_ordinal
115 2); // finger_count
116 ui::ScrollEvent* event = new ui::ScrollEvent(scoped_xevent_);
117 ui::Event::DispatcherApi dispatcher(event);
118 dispatcher.set_target(target_);
119 return event;
120 #else
121 ui::ScrollEvent* event = new ui::ScrollEvent(
122 ui::ET_SCROLL, gfx::Point(0, 0), ui::EventTimeForNow(), ui::EF_NONE,
123 0, // x_offset
124 scroll_delta, // y_offset
125 0, // x_offset_ordinal
126 scroll_delta, // y_offset_ordinal
127 2); // finger_count
128 ui::Event::DispatcherApi dispatcher(event);
129 dispatcher.set_target(target_);
130 return event;
131 #endif
134 ui::ScrollEvent* GenerateFlingScrollEvent(int fling_delta,
135 bool is_cancel) {
136 #if defined(USE_X11)
137 scoped_xevent_.InitFlingScrollEvent(
138 kTouchPadDeviceId, // deviceid
139 0, // x_velocity
140 fling_delta, // y_velocity
141 0, // x_velocity_ordinal
142 fling_delta, // y_velocity_ordinal
143 is_cancel); // is_cancel
144 ui::ScrollEvent* event = new ui::ScrollEvent(scoped_xevent_);
145 ui::Event::DispatcherApi dispatcher(event);
146 dispatcher.set_target(target_);
147 return event;
148 #else
149 ui::ScrollEvent* event = new ui::ScrollEvent(
150 is_cancel ? ui::ET_SCROLL_FLING_CANCEL : ui::ET_SCROLL_FLING_START,
151 gfx::Point(0, 0), ui::EventTimeForNow(), ui::EF_NONE,
152 0, // x_velocity
153 fling_delta, // y_velocity
154 0, // x_velocity_ordinal
155 fling_delta, // y_velocity_ordinal
156 11); // finger_count
157 ui::Event::DispatcherApi dispatcher(event);
158 dispatcher.set_target(target_);
159 return event;
160 #endif
163 // Creates a synthesized KeyEvent that is not backed by a native event.
164 ui::KeyEvent* GenerateSynthesizedKeyEvent(ui::EventType type,
165 ui::KeyboardCode code) {
166 return new ui::KeyEvent(type, code, ui::EF_NONE);
169 // Creates a synthesized MouseEvent that is not backed by a native event.
170 ui::MouseEvent* GenerateSynthesizedMouseEventAt(ui::EventType event_type,
171 const gfx::Point& location) {
172 ui::MouseEvent* event = new ui::MouseEvent(
173 event_type, location, location, ui::EventTimeForNow(),
174 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
175 ui::Event::DispatcherApi dispatcher(event);
176 dispatcher.set_target(target_);
177 return event;
180 // Creates a synthesized mouse press or release event.
181 ui::MouseEvent* GenerateSynthesizedMouseClickEvent(
182 ui::EventType type,
183 const gfx::Point& location) {
184 return GenerateSynthesizedMouseEventAt(type, location);
187 // Creates a synthesized ET_MOUSE_MOVED event.
188 ui::MouseEvent* GenerateSynthesizedMouseMoveEvent(
189 const gfx::Point& location) {
190 return GenerateSynthesizedMouseEventAt(ui::ET_MOUSE_MOVED, location);
193 // Creates a synthesized MouseWHeel event.
194 ui::MouseWheelEvent* GenerateSynthesizedMouseWheelEvent(int wheel_delta) {
195 scoped_ptr<ui::MouseEvent> mev(
196 GenerateSynthesizedMouseEventAt(ui::ET_MOUSEWHEEL, gfx::Point(0, 0)));
197 ui::MouseWheelEvent* event = new ui::MouseWheelEvent(*mev, 0, wheel_delta);
198 ui::Event::DispatcherApi dispatcher(event);
199 dispatcher.set_target(target_);
200 return event;
203 void SendActivateStickyKeyPattern(StickyKeysHandler* handler,
204 ui::KeyboardCode key_code) {
205 bool released = false;
206 int down_flags = 0;
207 scoped_ptr<ui::KeyEvent> ev;
208 ev.reset(GenerateKey(ui::ET_KEY_PRESSED, key_code));
209 handler->HandleKeyEvent(*ev.get(), key_code, &down_flags, &released);
210 ev.reset(GenerateKey(ui::ET_KEY_RELEASED, key_code));
211 handler->HandleKeyEvent(*ev.get(), key_code, &down_flags, &released);
214 bool HandleKeyEvent(const ui::KeyEvent& key_event,
215 StickyKeysHandler* handler,
216 int* down,
217 bool* up) {
218 return handler->HandleKeyEvent(key_event, key_event.key_code(), down, up);
221 int HandleKeyEventForDownFlags(const ui::KeyEvent& key_event,
222 StickyKeysHandler* handler) {
223 bool released = false;
224 int down = 0;
225 handler->HandleKeyEvent(key_event, key_event.key_code(), &down, &released);
226 return down;
229 aura::Window* target() { return target_; }
231 private:
232 // Owned by root window of shell, but we can still delete |target_| safely.
233 aura::Window* target_;
234 // The root window of |target_|. Not owned.
235 aura::Window* root_window_;
237 #if defined(USE_X11)
238 // Used to construct the various X events.
239 ui::ScopedXI2Event scoped_xevent_;
240 #endif
242 DISALLOW_COPY_AND_ASSIGN(StickyKeysTest);
245 TEST_F(StickyKeysTest, BasicOneshotScenarioTest) {
246 scoped_ptr<ui::KeyEvent> ev;
247 StickyKeysHandler sticky_key(ui::EF_SHIFT_DOWN);
249 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
251 // By typing Shift key, internal state become ENABLED.
252 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
253 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
255 ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_A));
256 bool released = false;
257 int mod_down_flags = 0;
258 HandleKeyEvent(*ev.get(), &sticky_key, &mod_down_flags, &released);
259 // Next keyboard event is shift modified.
260 EXPECT_TRUE(mod_down_flags & ui::EF_SHIFT_DOWN);
261 // Modifier release notification happens.
262 EXPECT_TRUE(released);
264 ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_A));
265 released = false;
266 mod_down_flags = 0;
267 HandleKeyEvent(*ev.get(), &sticky_key, &mod_down_flags, &released);
269 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
270 // Making sure Shift up keyboard event is available.
271 scoped_ptr<ui::Event> up_event;
272 ASSERT_EQ(0, sticky_key.GetModifierUpEvent(&up_event));
273 EXPECT_TRUE(up_event.get());
274 EXPECT_EQ(ui::ET_KEY_RELEASED, up_event->type());
275 EXPECT_EQ(ui::VKEY_SHIFT,
276 static_cast<const ui::KeyEvent*>(up_event.get())->key_code());
278 // Enabled state is one shot, so next key event should not be shift modified.
279 ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_A));
280 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
281 EXPECT_FALSE(mod_down_flags & ui::EF_SHIFT_DOWN);
283 ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_A));
284 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
285 EXPECT_FALSE(mod_down_flags & ui::EF_SHIFT_DOWN);
288 TEST_F(StickyKeysTest, BasicLockedScenarioTest) {
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 // By typing shift key, internal state become ENABLED.
295 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
296 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
298 // By typing shift key again, internal state become LOCKED.
299 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
300 EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
302 // All keyboard events including keyUp become shift modified.
303 ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_A));
304 int mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
305 EXPECT_TRUE(mod_down_flags & ui::EF_SHIFT_DOWN);
307 ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_A));
308 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
309 EXPECT_TRUE(mod_down_flags & ui::EF_SHIFT_DOWN);
311 // Locked state keeps after normal keyboard event.
312 EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
314 ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_B));
315 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
316 EXPECT_TRUE(mod_down_flags & ui::EF_SHIFT_DOWN);
318 ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_B));
319 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
320 EXPECT_TRUE(mod_down_flags & ui::EF_SHIFT_DOWN);
322 EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
324 // By typing shift key again, internal state become back to DISABLED.
325 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
326 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
329 TEST_F(StickyKeysTest, NonTargetModifierTest) {
330 scoped_ptr<ui::KeyEvent> ev;
331 StickyKeysHandler sticky_key(ui::EF_SHIFT_DOWN);
333 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
335 // Non target modifier key does not affect internal state
336 ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_MENU));
337 int mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
338 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
339 EXPECT_EQ(ui::EF_NONE, mod_down_flags);
341 ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_MENU));
342 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
343 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
344 EXPECT_EQ(ui::EF_NONE, mod_down_flags);
346 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
347 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
349 // Non target modifier key does not affect internal state
350 ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_MENU));
351 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
352 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
353 EXPECT_EQ(ui::EF_NONE, mod_down_flags);
355 ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_MENU));
356 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
357 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
358 EXPECT_EQ(ui::EF_NONE, mod_down_flags);
360 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
361 EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
363 // Non target modifier key does not affect internal state
364 ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_MENU));
365 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
366 EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
367 EXPECT_EQ(ui::EF_NONE, mod_down_flags);
369 ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_MENU));
370 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
371 EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
372 EXPECT_EQ(ui::EF_NONE, mod_down_flags);
375 TEST_F(StickyKeysTest, NormalShortcutTest) {
376 // Sticky keys should not be enabled if we perform a normal shortcut.
377 scoped_ptr<ui::KeyEvent> ev;
378 StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
380 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
382 // Perform ctrl+n shortcut.
383 ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL));
384 int mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
385 ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_N));
386 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
387 ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_N));
388 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
389 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
390 ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL));
391 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
393 // Sticky keys should not be enabled afterwards.
394 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
395 EXPECT_EQ(ui::EF_NONE, mod_down_flags);
397 // Perform ctrl+n shortcut, releasing ctrl first.
398 ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL));
399 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
400 ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_N));
401 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
402 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
403 ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL));
404 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
405 ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_N));
406 mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
408 // Sticky keys should not be enabled afterwards.
409 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
410 EXPECT_EQ(ui::EF_NONE, mod_down_flags);
413 TEST_F(StickyKeysTest, NormalModifiedClickTest) {
414 scoped_ptr<ui::KeyEvent> kev;
415 scoped_ptr<ui::MouseEvent> mev;
416 StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
418 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
420 // Perform ctrl+click.
421 kev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL));
422 int mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
423 mev.reset(GenerateMouseEvent(ui::ET_MOUSE_PRESSED));
424 bool released = false;
425 sticky_key.HandleMouseEvent(*mev.get(), &mod_down_flags, &released);
426 mev.reset(GenerateMouseEvent(ui::ET_MOUSE_RELEASED));
427 sticky_key.HandleMouseEvent(*mev.get(), &mod_down_flags, &released);
429 // Sticky keys should not be enabled afterwards.
430 kev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL));
431 mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
432 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
433 EXPECT_EQ(ui::EF_NONE, mod_down_flags);
436 TEST_F(StickyKeysTest, MouseMovedModifierTest) {
437 scoped_ptr<ui::KeyEvent> kev;
438 scoped_ptr<ui::MouseEvent> mev;
439 StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
441 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
443 // Press ctrl and handle mouse move events.
444 kev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL));
445 int mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
446 mev.reset(GenerateSynthesizedMouseMoveEvent(gfx::Point(0, 0)));
447 bool released = false;
448 sticky_key.HandleMouseEvent(*mev.get(), &mod_down_flags, &released);
449 mev.reset(GenerateSynthesizedMouseMoveEvent(gfx::Point(100, 100)));
450 sticky_key.HandleMouseEvent(*mev.get(), &mod_down_flags, &released);
452 // Sticky keys should be enabled afterwards.
453 kev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL));
454 mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
455 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
456 EXPECT_EQ(ui::EF_NONE, mod_down_flags);
459 TEST_F(StickyKeysTest, NormalModifiedScrollTest) {
460 scoped_ptr<ui::KeyEvent> kev;
461 scoped_ptr<ui::ScrollEvent> sev;
462 StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
464 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
466 // Perform ctrl+scroll.
467 kev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL));
468 int mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
469 sev.reset(GenerateFlingScrollEvent(0, true));
470 bool released = false;
471 sticky_key.HandleScrollEvent(*sev.get(), &mod_down_flags, &released);
472 sev.reset(GenerateScrollEvent(10));
473 sticky_key.HandleScrollEvent(*sev.get(), &mod_down_flags, &released);
474 sev.reset(GenerateFlingScrollEvent(10, false));
475 sticky_key.HandleScrollEvent(*sev.get(), &mod_down_flags, &released);
477 // Sticky keys should not be enabled afterwards.
478 kev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL));
479 mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
480 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
481 EXPECT_EQ(ui::EF_NONE, mod_down_flags);
484 TEST_F(StickyKeysTest, MouseEventOneshot) {
485 scoped_ptr<ui::MouseEvent> ev;
486 scoped_ptr<ui::KeyEvent> kev;
487 StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
489 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
490 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
491 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
493 // We should still be in the ENABLED state until we get the mouse
494 // release event.
495 ev.reset(GenerateMouseEvent(ui::ET_MOUSE_PRESSED));
496 bool released = false;
497 int mod_down_flags = 0;
498 sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
499 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
500 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
502 ev.reset(GenerateMouseEvent(ui::ET_MOUSE_RELEASED));
503 released = false;
504 mod_down_flags = 0;
505 sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
506 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
507 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
509 // Making sure modifier key release event is dispatched in the right order.
510 EXPECT_TRUE(released);
511 scoped_ptr<ui::Event> up_event;
512 ASSERT_EQ(0, sticky_key.GetModifierUpEvent(&up_event));
513 EXPECT_TRUE(up_event.get());
514 EXPECT_EQ(ui::ET_KEY_RELEASED, up_event->type());
515 EXPECT_EQ(ui::VKEY_CONTROL,
516 static_cast<const ui::KeyEvent*>(up_event.get())->key_code());
518 // Enabled state is one shot, so next click should not be control modified.
519 ev.reset(GenerateMouseEvent(ui::ET_MOUSE_PRESSED));
520 released = false;
521 mod_down_flags = 0;
522 sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
523 EXPECT_FALSE(mod_down_flags & ui::EF_CONTROL_DOWN);
525 ev.reset(GenerateMouseEvent(ui::ET_MOUSE_RELEASED));
526 released = false;
527 mod_down_flags = 0;
528 sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
529 EXPECT_FALSE(mod_down_flags & ui::EF_CONTROL_DOWN);
532 TEST_F(StickyKeysTest, MouseEventLocked) {
533 scoped_ptr<ui::MouseEvent> ev;
534 scoped_ptr<ui::KeyEvent> kev;
535 StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
537 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
539 // Pressing modifier key twice should make us enter lock state.
540 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
541 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
542 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
543 EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
545 // Mouse events should not disable locked mode.
546 for (int i = 0; i < 3; ++i) {
547 bool released = false;
548 int mod_down_flags = 0;
549 ev.reset(GenerateMouseEvent(ui::ET_MOUSE_PRESSED));
550 sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
551 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
552 ev.reset(GenerateMouseEvent(ui::ET_MOUSE_RELEASED));
553 released = false;
554 mod_down_flags = 0;
555 sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
556 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
557 EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
560 // Test with mouse wheel.
561 for (int i = 0; i < 3; ++i) {
562 bool released = false;
563 int mod_down_flags = 0;
564 ev.reset(GenerateMouseWheelEvent(ui::MouseWheelEvent::kWheelDelta));
565 sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
566 ev.reset(GenerateMouseWheelEvent(-ui::MouseWheelEvent::kWheelDelta));
567 released = false;
568 mod_down_flags = 0;
569 sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
570 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
571 EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
574 // Test mixed case with mouse events and key events.
575 ev.reset(GenerateMouseWheelEvent(ui::MouseWheelEvent::kWheelDelta));
576 bool released = false;
577 int mod_down_flags = 0;
578 sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
579 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
580 kev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_N));
581 mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
582 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
583 mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
584 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
586 EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
589 TEST_F(StickyKeysTest, ScrollEventOneshot) {
590 scoped_ptr<ui::ScrollEvent> ev;
591 scoped_ptr<ui::KeyEvent> kev;
592 StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
594 int scroll_deltas[] = {-10, 10};
595 for (int i = 0; i < 2; ++i) {
596 // Enable sticky keys.
597 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
598 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
599 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
601 // Test a scroll sequence. Sticky keys should only be disabled at the end
602 // of the scroll sequence. Fling cancel event starts the scroll sequence.
603 ev.reset(GenerateFlingScrollEvent(0, true));
604 bool released = false;
605 int mod_down_flags = 0;
606 sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
607 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
608 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
610 // Scrolls should all be modified but not disable sticky keys.
611 for (int j = 0; j < 3; ++j) {
612 ev.reset(GenerateScrollEvent(scroll_deltas[i]));
613 released = false;
614 mod_down_flags = 0;
615 sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
616 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
617 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
620 // Fling start event ends scroll sequence.
621 ev.reset(GenerateFlingScrollEvent(scroll_deltas[i], false));
622 released = false;
623 mod_down_flags = 0;
624 sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
625 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
626 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
628 scoped_ptr<ui::Event> up_event;
629 EXPECT_TRUE(released);
630 ASSERT_EQ(0, sticky_key.GetModifierUpEvent(&up_event));
631 EXPECT_TRUE(up_event.get());
632 EXPECT_EQ(ui::ET_KEY_RELEASED, up_event->type());
633 EXPECT_EQ(ui::VKEY_CONTROL,
634 static_cast<const ui::KeyEvent*>(up_event.get())->key_code());
638 TEST_F(StickyKeysTest, ScrollDirectionChanged) {
639 scoped_ptr<ui::ScrollEvent> ev;
640 scoped_ptr<ui::KeyEvent> kev;
641 StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
643 // Test direction change with both boundary value and negative value.
644 const int direction_change_values[2] = {0, -10};
645 for (int i = 0; i < 2; ++i) {
646 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
647 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
649 // Fling cancel starts scroll sequence.
650 ev.reset(GenerateFlingScrollEvent(0, true));
651 bool released = false;
652 int mod_down_flags = 0;
653 sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
654 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
656 // Test that changing directions in a scroll sequence will
657 // return sticky keys to DISABLED state.
658 for (int j = 0; j < 3; ++j) {
659 ev.reset(GenerateScrollEvent(10));
660 released = false;
661 mod_down_flags = 0;
662 sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
663 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
664 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
667 ev.reset(GenerateScrollEvent(direction_change_values[i]));
668 released = false;
669 mod_down_flags = 0;
670 sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
671 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
675 TEST_F(StickyKeysTest, ScrollEventLocked) {
676 scoped_ptr<ui::ScrollEvent> ev;
677 scoped_ptr<ui::KeyEvent> kev;
678 StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
680 // Lock sticky keys.
681 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
682 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
683 EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
685 // Test scroll events are correctly modified in locked state.
686 for (int i = 0; i < 5; ++i) {
687 // Fling cancel starts scroll sequence.
688 ev.reset(GenerateFlingScrollEvent(0, true));
689 bool released = false;
690 int mod_down_flags = 0;
691 sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
693 ev.reset(GenerateScrollEvent(10));
694 released = false;
695 mod_down_flags = 0;
696 sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
697 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
698 ev.reset(GenerateScrollEvent(-10));
699 sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
700 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
702 // Fling start ends scroll sequence.
703 ev.reset(GenerateFlingScrollEvent(-10, false));
704 sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
707 EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
710 TEST_F(StickyKeysTest, SynthesizedEvents) {
711 // Non-native, internally generated events should be properly handled
712 // by sticky keys.
713 StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
715 // Test non-native key events.
716 scoped_ptr<ui::KeyEvent> kev;
717 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
718 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
720 kev.reset(GenerateSynthesizedKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_K));
721 int mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
722 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
723 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
725 kev.reset(GenerateSynthesizedKeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_K));
726 mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
727 EXPECT_FALSE(mod_down_flags & ui::EF_CONTROL_DOWN);
728 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
730 // Test non-native mouse events.
731 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
732 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
734 scoped_ptr<ui::MouseEvent> mev;
735 mev.reset(GenerateSynthesizedMouseClickEvent(ui::ET_MOUSE_PRESSED,
736 gfx::Point(0, 0)));
737 bool released = false;
738 sticky_key.HandleMouseEvent(*mev.get(), &mod_down_flags, &released);
739 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
740 EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
742 mev.reset(GenerateSynthesizedMouseClickEvent(ui::ET_MOUSE_RELEASED,
743 gfx::Point(0, 0)));
744 released = false;
745 mod_down_flags = 0;
746 sticky_key.HandleMouseEvent(*mev.get(), &mod_down_flags, &released);
747 EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
748 EXPECT_TRUE(released);
749 EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
752 } // namespace ash