Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(361)

Side by Side Diff: ash/wm/sticky_keys_unittest.cc

Issue 118543002: Move sticky keys files to their own directory and rename to StickyKeysController. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: update ash.gyp Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « ash/wm/sticky_keys.cc ('k') | chrome/browser/chromeos/accessibility/accessibility_manager.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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/wm/sticky_keys.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/root_window.h"
18 #include "ui/aura/window.h"
19 #include "ui/aura/window_tree_host_delegate.h"
20 #include "ui/events/event_handler.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 scroll device.
29 const unsigned int kScrollDeviceId = 1;
30
31 } // namespace
32
33 // Keeps a buffer of handled events.
34 class EventBuffer : public ui::EventHandler {
35 public:
36 EventBuffer() {}
37 virtual ~EventBuffer() {}
38
39 void PopEvents(ScopedVector<ui::Event>* events) {
40 events->clear();
41 events->swap(events_);
42 }
43
44 private:
45 // ui::EventHandler overrides:
46 virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE {
47 events_.push_back(new ui::KeyEvent(*event));
48 }
49
50 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
51 if (event->IsMouseWheelEvent()) {
52 events_.push_back(
53 new ui::MouseWheelEvent(*static_cast<ui::MouseWheelEvent*>(event)));
54 } else {
55 events_.push_back(new ui::MouseEvent(event->native_event()));
56 }
57 }
58
59 ScopedVector<ui::Event> events_;
60
61 DISALLOW_COPY_AND_ASSIGN(EventBuffer);
62 };
63
64 // A testable and StickyKeysHandler.
65 class MockStickyKeysHandlerDelegate :
66 public StickyKeysHandler::StickyKeysHandlerDelegate {
67 public:
68 class Delegate {
69 public:
70 virtual aura::Window* GetExpectedTarget() = 0;
71 virtual void OnShortcutPressed() = 0;
72
73 protected:
74 virtual ~Delegate() {}
75 };
76
77 MockStickyKeysHandlerDelegate(Delegate* delegate) : delegate_(delegate) {}
78
79 virtual ~MockStickyKeysHandlerDelegate() {}
80
81 // StickyKeysHandler override.
82 virtual void DispatchKeyEvent(ui::KeyEvent* event,
83 aura::Window* target) OVERRIDE {
84 ASSERT_EQ(delegate_->GetExpectedTarget(), target);
85
86 // Detect a special shortcut when it is dispatched. This shortcut will
87 // not be hit in the LOCKED state as this case does not involve the
88 // delegate.
89 if (event->type() == ui::ET_KEY_PRESSED &&
90 event->key_code() == ui::VKEY_J &&
91 event->flags() | ui::EF_CONTROL_DOWN) {
92 delegate_->OnShortcutPressed();
93 }
94
95 events_.push_back(new ui::KeyEvent(*event));
96 }
97
98 virtual void DispatchMouseEvent(ui::MouseEvent* event,
99 aura::Window* target) OVERRIDE {
100 ASSERT_EQ(delegate_->GetExpectedTarget(), target);
101 events_.push_back(
102 new ui::MouseEvent(*event, target, target->GetRootWindow()));
103 }
104
105 virtual void DispatchScrollEvent(ui::ScrollEvent* event,
106 aura::Window* target) OVERRIDE {
107 events_.push_back(new ui::ScrollEvent(event->native_event()));
108 }
109
110 // Returns the count of dispatched events.
111 size_t GetEventCount() const {
112 return events_.size();
113 }
114
115 // Returns the |index|-th dispatched event.
116 const ui::Event* GetEvent(size_t index) const {
117 return events_[index];
118 }
119
120 // Clears all previously dispatched events.
121 void ClearEvents() {
122 events_.clear();
123 }
124
125 private:
126 ScopedVector<ui::Event> events_;
127 Delegate* delegate_;
128
129 DISALLOW_COPY_AND_ASSIGN(MockStickyKeysHandlerDelegate);
130 };
131
132 class StickyKeysTest : public test::AshTestBase,
133 public MockStickyKeysHandlerDelegate::Delegate {
134 protected:
135 StickyKeysTest()
136 : target_(NULL),
137 root_window_(NULL) {}
138
139 virtual void SetUp() OVERRIDE {
140 test::AshTestBase::SetUp();
141
142 // |target_| owned by root window of shell. It is still safe to delete
143 // it ourselves.
144 target_ = CreateTestWindowInShellWithId(0);
145 root_window_ = target_->GetRootWindow();
146 }
147
148 virtual void TearDown() OVERRIDE {
149 test::AshTestBase::TearDown();
150 }
151
152 // Overridden from MockStickyKeysHandlerDelegate::Delegate:
153 virtual aura::Window* GetExpectedTarget() OVERRIDE {
154 return target_ ? target_ : root_window_;
155 }
156
157 virtual void OnShortcutPressed() OVERRIDE {
158 if (target_) {
159 delete target_;
160 target_ = NULL;
161 }
162 }
163
164 ui::KeyEvent* GenerateKey(bool is_key_press, ui::KeyboardCode code) {
165 scoped_xevent_.InitKeyEvent(
166 is_key_press ? ui::ET_KEY_PRESSED : ui::ET_KEY_RELEASED,
167 code,
168 0);
169 ui::KeyEvent* event = new ui::KeyEvent(scoped_xevent_, false);
170 ui::Event::DispatcherApi dispatcher(event);
171 dispatcher.set_target(target_);
172 return event;
173 }
174
175 ui::MouseEvent* GenerateMouseEvent(bool is_button_press) {
176 scoped_xevent_.InitButtonEvent(
177 is_button_press ? ui::ET_MOUSE_PRESSED : ui::ET_MOUSE_RELEASED, 0);
178 ui::MouseEvent* event = new ui::MouseEvent(scoped_xevent_);
179 ui::Event::DispatcherApi dispatcher(event);
180 dispatcher.set_target(target_);
181 return event;
182 }
183
184 ui::MouseWheelEvent* GenerateMouseWheelEvent(int wheel_delta) {
185 EXPECT_NE(0, wheel_delta);
186 scoped_xevent_.InitMouseWheelEvent(wheel_delta, 0);
187 ui::MouseWheelEvent* event = new ui::MouseWheelEvent(scoped_xevent_);
188 ui::Event::DispatcherApi dispatcher(event);
189 dispatcher.set_target(target_);
190 return event;
191 }
192
193 ui::ScrollEvent* GenerateScrollEvent(int scroll_delta) {
194 scoped_xevent_.InitScrollEvent(kScrollDeviceId, // deviceid
195 0, // x_offset
196 scroll_delta, // y_offset
197 0, // x_offset_ordinal
198 scroll_delta, // y_offset_ordinal
199 2); // finger_count
200 ui::ScrollEvent* event = new ui::ScrollEvent(scoped_xevent_);
201 ui::Event::DispatcherApi dispatcher(event);
202 dispatcher.set_target(target_);
203 return event;
204 }
205
206 ui::ScrollEvent* GenerateFlingScrollEvent(int fling_delta,
207 bool is_cancel) {
208 scoped_xevent_.InitFlingScrollEvent(
209 kScrollDeviceId, // deviceid
210 0, // x_velocity
211 fling_delta, // y_velocity
212 0, // x_velocity_ordinal
213 fling_delta, // y_velocity_ordinal
214 is_cancel); // is_cancel
215 ui::ScrollEvent* event = new ui::ScrollEvent(scoped_xevent_);
216 ui::Event::DispatcherApi dispatcher(event);
217 dispatcher.set_target(target_);
218 return event;
219 }
220
221 // Creates a synthesized KeyEvent that is not backed by a native event.
222 ui::KeyEvent* GenerateSynthesizedKeyEvent(
223 bool is_key_press, ui::KeyboardCode code) {
224 ui::KeyEvent* event = new ui::KeyEvent(
225 is_key_press ? ui::ET_KEY_PRESSED : ui::ET_MOUSE_RELEASED,
226 code, 0, true);
227 ui::Event::DispatcherApi dispatcher(event);
228 dispatcher.set_target(target_);
229 return event;
230 }
231
232 // Creates a synthesized MouseEvent that is not backed by a native event.
233 ui::MouseEvent* GenerateSynthesizedMouseEvent(bool is_button_press) {
234 ui::MouseEvent* event = new ui::MouseEvent(
235 is_button_press ? ui::ET_MOUSE_PRESSED : ui::ET_MOUSE_RELEASED,
236 gfx::Point(0, 0),
237 gfx::Point(0, 0),
238 ui::EF_LEFT_MOUSE_BUTTON,
239 ui::EF_LEFT_MOUSE_BUTTON);
240 ui::Event::DispatcherApi dispatcher(event);
241 dispatcher.set_target(target_);
242 return event;
243 }
244
245 void SendActivateStickyKeyPattern(StickyKeysHandler* handler,
246 ui::KeyboardCode key_code) {
247 scoped_ptr<ui::KeyEvent> ev;
248 ev.reset(GenerateKey(true, key_code));
249 handler->HandleKeyEvent(ev.get());
250 ev.reset(GenerateKey(false, key_code));
251 handler->HandleKeyEvent(ev.get());
252 }
253
254 void SendActivateStickyKeyPattern(aura::RootWindowHostDelegate* delegate,
255 ui::KeyboardCode key_code) {
256 scoped_ptr<ui::KeyEvent> ev;
257 ev.reset(GenerateKey(true, key_code));
258 delegate->OnHostKeyEvent(ev.get());
259 ev.reset(GenerateKey(false, key_code));
260 delegate->OnHostKeyEvent(ev.get());
261 }
262
263 aura::Window* target() { return target_; }
264
265 private:
266 // Owned by root window of shell, but we can still delete |target_| safely.
267 aura::Window* target_;
268 // The root window of |target_|. Not owned.
269 aura::Window* root_window_;
270
271 // Used to construct the various X events.
272 ui::ScopedXI2Event scoped_xevent_;
273
274 DISALLOW_COPY_AND_ASSIGN(StickyKeysTest);
275 };
276
277 TEST_F(StickyKeysTest, BasicOneshotScenarioTest) {
278 scoped_ptr<ui::KeyEvent> ev;
279 MockStickyKeysHandlerDelegate* mock_delegate =
280 new MockStickyKeysHandlerDelegate(this);
281 StickyKeysHandler sticky_key(ui::EF_SHIFT_DOWN, mock_delegate);
282
283 EXPECT_EQ(StickyKeysHandler::DISABLED, sticky_key.current_state());
284
285 // By typing Shift key, internal state become ENABLED.
286 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
287 EXPECT_EQ(StickyKeysHandler::ENABLED, sticky_key.current_state());
288
289 ev.reset(GenerateKey(true, ui::VKEY_A));
290 sticky_key.HandleKeyEvent(ev.get());
291
292 // Next keyboard event is shift modified.
293 EXPECT_TRUE(ev->flags() & ui::EF_SHIFT_DOWN);
294
295 ev.reset(GenerateKey(false, ui::VKEY_A));
296 sticky_key.HandleKeyEvent(ev.get());
297
298 EXPECT_EQ(StickyKeysHandler::DISABLED, sticky_key.current_state());
299 // Making sure Shift up keyboard event is dispatched.
300 ASSERT_EQ(2U, mock_delegate->GetEventCount());
301 EXPECT_EQ(ui::ET_KEY_PRESSED, mock_delegate->GetEvent(0)->type());
302 EXPECT_EQ(ui::VKEY_A,
303 static_cast<const ui::KeyEvent*>(mock_delegate->GetEvent(0))
304 ->key_code());
305 EXPECT_EQ(ui::ET_KEY_RELEASED, mock_delegate->GetEvent(1)->type());
306 EXPECT_EQ(ui::VKEY_SHIFT,
307 static_cast<const ui::KeyEvent*>(mock_delegate->GetEvent(1))
308 ->key_code());
309
310 // Enabled state is one shot, so next key event should not be shift modified.
311 ev.reset(GenerateKey(true, ui::VKEY_A));
312 sticky_key.HandleKeyEvent(ev.get());
313 EXPECT_FALSE(ev->flags() & ui::EF_SHIFT_DOWN);
314
315 ev.reset(GenerateKey(false, ui::VKEY_A));
316 sticky_key.HandleKeyEvent(ev.get());
317 EXPECT_FALSE(ev->flags() & ui::EF_SHIFT_DOWN);
318 }
319
320 TEST_F(StickyKeysTest, BasicLockedScenarioTest) {
321 scoped_ptr<ui::KeyEvent> ev;
322 MockStickyKeysHandlerDelegate* mock_delegate =
323 new MockStickyKeysHandlerDelegate(this);
324 StickyKeysHandler sticky_key(ui::EF_SHIFT_DOWN, mock_delegate);
325
326 EXPECT_EQ(StickyKeysHandler::DISABLED, sticky_key.current_state());
327
328 // By typing shift key, internal state become ENABLED.
329 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
330 EXPECT_EQ(StickyKeysHandler::ENABLED, sticky_key.current_state());
331
332 // By typing shift key again, internal state become LOCKED.
333 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
334 EXPECT_EQ(StickyKeysHandler::LOCKED, sticky_key.current_state());
335
336 // All keyboard events including keyUp become shift modified.
337 ev.reset(GenerateKey(true, ui::VKEY_A));
338 sticky_key.HandleKeyEvent(ev.get());
339 EXPECT_TRUE(ev->flags() & ui::EF_SHIFT_DOWN);
340
341 ev.reset(GenerateKey(false, ui::VKEY_A));
342 sticky_key.HandleKeyEvent(ev.get());
343 EXPECT_TRUE(ev->flags() & ui::EF_SHIFT_DOWN);
344
345 // Locked state keeps after normal keyboard event.
346 EXPECT_EQ(StickyKeysHandler::LOCKED, sticky_key.current_state());
347
348 ev.reset(GenerateKey(true, ui::VKEY_B));
349 sticky_key.HandleKeyEvent(ev.get());
350 EXPECT_TRUE(ev->flags() & ui::EF_SHIFT_DOWN);
351
352 ev.reset(GenerateKey(false, ui::VKEY_B));
353 sticky_key.HandleKeyEvent(ev.get());
354 EXPECT_TRUE(ev->flags() & ui::EF_SHIFT_DOWN);
355
356 EXPECT_EQ(StickyKeysHandler::LOCKED, sticky_key.current_state());
357
358 // By typing shift key again, internal state become back to DISABLED.
359 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
360 EXPECT_EQ(StickyKeysHandler::DISABLED, sticky_key.current_state());
361 }
362
363 TEST_F(StickyKeysTest, NonTargetModifierTest) {
364 scoped_ptr<ui::KeyEvent> ev;
365 MockStickyKeysHandlerDelegate* mock_delegate =
366 new MockStickyKeysHandlerDelegate(this);
367 StickyKeysHandler sticky_key(ui::EF_SHIFT_DOWN, mock_delegate);
368
369 EXPECT_EQ(StickyKeysHandler::DISABLED, sticky_key.current_state());
370
371 // Non target modifier key does not affect internal state
372 ev.reset(GenerateKey(true, ui::VKEY_MENU));
373 sticky_key.HandleKeyEvent(ev.get());
374 EXPECT_EQ(StickyKeysHandler::DISABLED, sticky_key.current_state());
375
376 ev.reset(GenerateKey(false, ui::VKEY_MENU));
377 sticky_key.HandleKeyEvent(ev.get());
378 EXPECT_EQ(StickyKeysHandler::DISABLED, sticky_key.current_state());
379
380 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
381 EXPECT_EQ(StickyKeysHandler::ENABLED, sticky_key.current_state());
382
383 // Non target modifier key does not affect internal state
384 ev.reset(GenerateKey(true, ui::VKEY_MENU));
385 sticky_key.HandleKeyEvent(ev.get());
386 EXPECT_EQ(StickyKeysHandler::ENABLED, sticky_key.current_state());
387
388 ev.reset(GenerateKey(false, ui::VKEY_MENU));
389 sticky_key.HandleKeyEvent(ev.get());
390 EXPECT_EQ(StickyKeysHandler::ENABLED, sticky_key.current_state());
391
392 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
393 EXPECT_EQ(StickyKeysHandler::LOCKED, sticky_key.current_state());
394
395 // Non target modifier key does not affect internal state
396 ev.reset(GenerateKey(true, ui::VKEY_MENU));
397 sticky_key.HandleKeyEvent(ev.get());
398 EXPECT_EQ(StickyKeysHandler::LOCKED, sticky_key.current_state());
399
400 ev.reset(GenerateKey(false, ui::VKEY_MENU));
401 sticky_key.HandleKeyEvent(ev.get());
402 EXPECT_EQ(StickyKeysHandler::LOCKED, sticky_key.current_state());
403 }
404
405 TEST_F(StickyKeysTest, NormalShortcutTest) {
406 // Sticky keys should not be enabled if we perform a normal shortcut.
407 scoped_ptr<ui::KeyEvent> ev;
408 MockStickyKeysHandlerDelegate* mock_delegate =
409 new MockStickyKeysHandlerDelegate(this);
410 StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
411
412 EXPECT_EQ(StickyKeysHandler::DISABLED, sticky_key.current_state());
413
414 // Perform ctrl+n shortcut.
415 ev.reset(GenerateKey(true, ui::VKEY_CONTROL));
416 sticky_key.HandleKeyEvent(ev.get());
417 ev.reset(GenerateKey(true, ui::VKEY_N));
418 sticky_key.HandleKeyEvent(ev.get());
419 ev.reset(GenerateKey(false, ui::VKEY_N));
420 sticky_key.HandleKeyEvent(ev.get());
421 EXPECT_EQ(StickyKeysHandler::DISABLED, sticky_key.current_state());
422
423 // Sticky keys should not be enabled afterwards.
424 ev.reset(GenerateKey(false, ui::VKEY_CONTROL));
425 sticky_key.HandleKeyEvent(ev.get());
426 EXPECT_EQ(StickyKeysHandler::DISABLED, sticky_key.current_state());
427 }
428
429 TEST_F(StickyKeysTest, NormalModifiedClickTest) {
430 scoped_ptr<ui::KeyEvent> kev;
431 scoped_ptr<ui::MouseEvent> mev;
432 MockStickyKeysHandlerDelegate* mock_delegate =
433 new MockStickyKeysHandlerDelegate(this);
434 StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
435
436 EXPECT_EQ(StickyKeysHandler::DISABLED, sticky_key.current_state());
437
438 // Perform ctrl+click.
439 kev.reset(GenerateKey(true, ui::VKEY_CONTROL));
440 sticky_key.HandleKeyEvent(kev.get());
441 mev.reset(GenerateMouseEvent(true));
442 sticky_key.HandleMouseEvent(mev.get());
443 mev.reset(GenerateMouseEvent(false));
444 sticky_key.HandleMouseEvent(mev.get());
445
446 // Sticky keys should not be enabled afterwards.
447 kev.reset(GenerateKey(false, ui::VKEY_CONTROL));
448 sticky_key.HandleKeyEvent(kev.get());
449 EXPECT_EQ(StickyKeysHandler::DISABLED, sticky_key.current_state());
450 }
451
452 TEST_F(StickyKeysTest, NormalModifiedScrollTest) {
453 ui::SetUpScrollDeviceForTest(kScrollDeviceId);
454
455 scoped_ptr<ui::KeyEvent> kev;
456 scoped_ptr<ui::ScrollEvent> sev;
457 MockStickyKeysHandlerDelegate* mock_delegate =
458 new MockStickyKeysHandlerDelegate(this);
459 StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
460
461 EXPECT_EQ(StickyKeysHandler::DISABLED, sticky_key.current_state());
462
463 // Perform ctrl+scroll.
464 kev.reset(GenerateKey(true, ui::VKEY_CONTROL));
465 sev.reset(GenerateFlingScrollEvent(0, true));
466 sticky_key.HandleScrollEvent(sev.get());
467 sev.reset(GenerateScrollEvent(10));
468 sticky_key.HandleScrollEvent(sev.get());
469 sev.reset(GenerateFlingScrollEvent(10, false));
470 sticky_key.HandleScrollEvent(sev.get());
471
472 // Sticky keys should not be enabled afterwards.
473 kev.reset(GenerateKey(false, ui::VKEY_CONTROL));
474 sticky_key.HandleKeyEvent(kev.get());
475 EXPECT_EQ(StickyKeysHandler::DISABLED, sticky_key.current_state());
476 }
477
478 TEST_F(StickyKeysTest, MouseEventOneshot) {
479 scoped_ptr<ui::MouseEvent> ev;
480 scoped_ptr<ui::KeyEvent> kev;
481 MockStickyKeysHandlerDelegate* mock_delegate =
482 new MockStickyKeysHandlerDelegate(this);
483 StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
484
485 EXPECT_EQ(StickyKeysHandler::DISABLED, sticky_key.current_state());
486 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
487 EXPECT_EQ(StickyKeysHandler::ENABLED, sticky_key.current_state());
488
489 // We should still be in the ENABLED state until we get the mouse
490 // release event.
491 ev.reset(GenerateMouseEvent(true));
492 sticky_key.HandleMouseEvent(ev.get());
493 EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
494 EXPECT_EQ(StickyKeysHandler::ENABLED, sticky_key.current_state());
495
496 ev.reset(GenerateMouseEvent(false));
497 sticky_key.HandleMouseEvent(ev.get());
498 EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
499 EXPECT_EQ(StickyKeysHandler::DISABLED, sticky_key.current_state());
500
501 // Making sure modifier key release event is dispatched in the right order.
502 ASSERT_EQ(2u, mock_delegate->GetEventCount());
503 EXPECT_EQ(ui::ET_MOUSE_RELEASED, mock_delegate->GetEvent(0)->type());
504 EXPECT_EQ(ui::ET_KEY_RELEASED, mock_delegate->GetEvent(1)->type());
505 EXPECT_EQ(ui::VKEY_CONTROL,
506 static_cast<const ui::KeyEvent*>(mock_delegate->GetEvent(1))
507 ->key_code());
508
509 // Enabled state is one shot, so next click should not be control modified.
510 ev.reset(GenerateMouseEvent(true));
511 sticky_key.HandleMouseEvent(ev.get());
512 EXPECT_FALSE(ev->flags() & ui::EF_CONTROL_DOWN);
513
514 ev.reset(GenerateMouseEvent(false));
515 sticky_key.HandleMouseEvent(ev.get());
516 EXPECT_FALSE(ev->flags() & ui::EF_CONTROL_DOWN);
517 }
518
519 TEST_F(StickyKeysTest, MouseEventLocked) {
520 scoped_ptr<ui::MouseEvent> ev;
521 scoped_ptr<ui::KeyEvent> kev;
522 MockStickyKeysHandlerDelegate* mock_delegate =
523 new MockStickyKeysHandlerDelegate(this);
524 StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
525
526 EXPECT_EQ(StickyKeysHandler::DISABLED, sticky_key.current_state());
527
528 // Pressing modifier key twice should make us enter lock state.
529 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
530 EXPECT_EQ(StickyKeysHandler::ENABLED, sticky_key.current_state());
531 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
532 EXPECT_EQ(StickyKeysHandler::LOCKED, sticky_key.current_state());
533
534 // Mouse events should not disable locked mode.
535 for (int i = 0; i < 3; ++i) {
536 ev.reset(GenerateMouseEvent(true));
537 sticky_key.HandleMouseEvent(ev.get());
538 EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
539 ev.reset(GenerateMouseEvent(false));
540 sticky_key.HandleMouseEvent(ev.get());
541 EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
542 EXPECT_EQ(StickyKeysHandler::LOCKED, sticky_key.current_state());
543 }
544
545 // Test with mouse wheel.
546 for (int i = 0; i < 3; ++i) {
547 ev.reset(GenerateMouseWheelEvent(ui::MouseWheelEvent::kWheelDelta));
548 sticky_key.HandleMouseEvent(ev.get());
549 ev.reset(GenerateMouseWheelEvent(-ui::MouseWheelEvent::kWheelDelta));
550 sticky_key.HandleMouseEvent(ev.get());
551 EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
552 EXPECT_EQ(StickyKeysHandler::LOCKED, sticky_key.current_state());
553 }
554
555 // Test mixed case with mouse events and key events.
556 ev.reset(GenerateMouseWheelEvent(ui::MouseWheelEvent::kWheelDelta));
557 sticky_key.HandleMouseEvent(ev.get());
558 EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
559 kev.reset(GenerateKey(true, ui::VKEY_N));
560 sticky_key.HandleKeyEvent(kev.get());
561 EXPECT_TRUE(kev->flags() & ui::EF_CONTROL_DOWN);
562 kev.reset(GenerateKey(false, ui::VKEY_N));
563 sticky_key.HandleKeyEvent(kev.get());
564 EXPECT_TRUE(kev->flags() & ui::EF_CONTROL_DOWN);
565
566 EXPECT_EQ(StickyKeysHandler::LOCKED, sticky_key.current_state());
567 }
568
569 TEST_F(StickyKeysTest, ScrollEventOneshot) {
570 ui::SetUpScrollDeviceForTest(kScrollDeviceId);
571 // Disable Australlian scrolling.
572 ui::DeviceDataManager::GetInstance()->set_natural_scroll_enabled(true);
573
574 scoped_ptr<ui::ScrollEvent> ev;
575 scoped_ptr<ui::KeyEvent> kev;
576 MockStickyKeysHandlerDelegate* mock_delegate =
577 new MockStickyKeysHandlerDelegate(this);
578 StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
579
580 int scroll_deltas[] = {-10, 10};
581 for (int i = 0; i < 2; ++i) {
582 mock_delegate->ClearEvents();
583
584 // Enable sticky keys.
585 EXPECT_EQ(StickyKeysHandler::DISABLED, sticky_key.current_state());
586 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
587 EXPECT_EQ(StickyKeysHandler::ENABLED, sticky_key.current_state());
588
589 // Test a scroll sequence. Sticky keys should only be disabled at the end
590 // of the scroll sequence. Fling cancel event starts the scroll sequence.
591 ev.reset(GenerateFlingScrollEvent(0, true));
592 sticky_key.HandleScrollEvent(ev.get());
593 EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
594 EXPECT_EQ(StickyKeysHandler::ENABLED, sticky_key.current_state());
595
596 // Scrolls should all be modified but not disable sticky keys.
597 for (int j = 0; j < 3; ++j) {
598 ev.reset(GenerateScrollEvent(scroll_deltas[i]));
599 sticky_key.HandleScrollEvent(ev.get());
600 EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
601 EXPECT_EQ(StickyKeysHandler::ENABLED, sticky_key.current_state());
602 }
603
604 // Fling start event ends scroll sequence.
605 ev.reset(GenerateFlingScrollEvent(scroll_deltas[i], false));
606 sticky_key.HandleScrollEvent(ev.get());
607 EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
608 EXPECT_EQ(StickyKeysHandler::DISABLED, sticky_key.current_state());
609
610 ASSERT_EQ(2U, mock_delegate->GetEventCount());
611 EXPECT_EQ(ui::ET_SCROLL_FLING_START, mock_delegate->GetEvent(0)->type());
612 EXPECT_FLOAT_EQ(scroll_deltas[i],
613 static_cast<const ui::ScrollEvent*>(
614 mock_delegate->GetEvent(0))->y_offset());
615 EXPECT_EQ(ui::ET_KEY_RELEASED, mock_delegate->GetEvent(1)->type());
616 EXPECT_EQ(ui::VKEY_CONTROL,
617 static_cast<const ui::KeyEvent*>(mock_delegate->GetEvent(1))
618 ->key_code());
619 }
620 }
621
622 TEST_F(StickyKeysTest, ScrollDirectionChanged) {
623 ui::SetUpScrollDeviceForTest(kScrollDeviceId);
624 // Disable Australlian scrolling.
625 ui::DeviceDataManager::GetInstance()->set_natural_scroll_enabled(true);
626
627 scoped_ptr<ui::ScrollEvent> ev;
628 scoped_ptr<ui::KeyEvent> kev;
629 MockStickyKeysHandlerDelegate* mock_delegate =
630 new MockStickyKeysHandlerDelegate(this);
631 StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
632
633 // Test direction change with both boundary value and negative value.
634 const int direction_change_values[2] = {0, -10};
635 for (int i = 0; i < 2; ++i) {
636 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
637 EXPECT_EQ(StickyKeysHandler::ENABLED, sticky_key.current_state());
638
639 // Fling cancel starts scroll sequence.
640 ev.reset(GenerateFlingScrollEvent(0, true));
641 sticky_key.HandleScrollEvent(ev.get());
642 EXPECT_EQ(StickyKeysHandler::ENABLED, sticky_key.current_state());
643
644 // Test that changing directions in a scroll sequence will
645 // return sticky keys to DISABLED state.
646 for (int j = 0; j < 3; ++j) {
647 ev.reset(GenerateScrollEvent(10));
648 sticky_key.HandleScrollEvent(ev.get());
649 EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
650 EXPECT_EQ(StickyKeysHandler::ENABLED, sticky_key.current_state());
651 }
652
653 ev.reset(GenerateScrollEvent(direction_change_values[i]));
654 sticky_key.HandleScrollEvent(ev.get());
655 EXPECT_FALSE(ev->flags() & ui::EF_CONTROL_DOWN);
656 EXPECT_EQ(StickyKeysHandler::DISABLED, sticky_key.current_state());
657 }
658 }
659
660 TEST_F(StickyKeysTest, ScrollEventLocked) {
661 ui::SetUpScrollDeviceForTest(kScrollDeviceId);
662 // Disable Australlian scrolling.
663 ui::DeviceDataManager::GetInstance()->set_natural_scroll_enabled(true);
664
665 scoped_ptr<ui::ScrollEvent> ev;
666 scoped_ptr<ui::KeyEvent> kev;
667 MockStickyKeysHandlerDelegate* mock_delegate =
668 new MockStickyKeysHandlerDelegate(this);
669 StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
670
671 // Lock sticky keys.
672 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
673 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
674 EXPECT_EQ(StickyKeysHandler::LOCKED, sticky_key.current_state());
675
676 // Test scroll events are correctly modified in locked state.
677 for (int i = 0; i < 5; ++i) {
678 // Fling cancel starts scroll sequence.
679 ev.reset(GenerateFlingScrollEvent(0, true));
680 sticky_key.HandleScrollEvent(ev.get());
681
682 ev.reset(GenerateScrollEvent(10));
683 sticky_key.HandleScrollEvent(ev.get());
684 EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
685 ev.reset(GenerateScrollEvent(-10));
686 sticky_key.HandleScrollEvent(ev.get());
687 EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
688
689 // Fling start ends scroll sequence.
690 ev.reset(GenerateFlingScrollEvent(-10, false));
691 sticky_key.HandleScrollEvent(ev.get());
692 }
693
694 EXPECT_EQ(StickyKeysHandler::LOCKED, sticky_key.current_state());
695 }
696
697 TEST_F(StickyKeysTest, EventTargetDestroyed) {
698 scoped_ptr<ui::KeyEvent> ev;
699 MockStickyKeysHandlerDelegate* mock_delegate =
700 new MockStickyKeysHandlerDelegate(this);
701 StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
702
703 target()->Focus();
704
705 // Go into ENABLED state.
706 EXPECT_EQ(StickyKeysHandler::DISABLED, sticky_key.current_state());
707 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
708 EXPECT_EQ(StickyKeysHandler::ENABLED, sticky_key.current_state());
709
710 // CTRL+J is a special shortcut that will destroy the event target.
711 ev.reset(GenerateKey(true, ui::VKEY_J));
712 sticky_key.HandleKeyEvent(ev.get());
713 EXPECT_EQ(StickyKeysHandler::DISABLED, sticky_key.current_state());
714 EXPECT_FALSE(target());
715 }
716
717 TEST_F(StickyKeysTest, SynthesizedEvents) {
718 // Non-native, internally generated events should be properly handled
719 // by sticky keys.
720 MockStickyKeysHandlerDelegate* mock_delegate =
721 new MockStickyKeysHandlerDelegate(this);
722 StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
723
724 // Test non-native key events.
725 scoped_ptr<ui::KeyEvent> kev;
726 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
727 EXPECT_EQ(StickyKeysHandler::ENABLED, sticky_key.current_state());
728
729 kev.reset(GenerateSynthesizedKeyEvent(true, ui::VKEY_K));
730 sticky_key.HandleKeyEvent(kev.get());
731 EXPECT_TRUE(kev->flags() & ui::EF_CONTROL_DOWN);
732 EXPECT_EQ(StickyKeysHandler::DISABLED, sticky_key.current_state());
733
734 kev.reset(GenerateSynthesizedKeyEvent(false, ui::VKEY_K));
735 sticky_key.HandleKeyEvent(kev.get());
736 EXPECT_FALSE(kev->flags() & ui::EF_CONTROL_DOWN);
737 EXPECT_EQ(StickyKeysHandler::DISABLED, sticky_key.current_state());
738
739 // Test non-native mouse events.
740 SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
741 EXPECT_EQ(StickyKeysHandler::ENABLED, sticky_key.current_state());
742
743 scoped_ptr<ui::MouseEvent> mev;
744 mev.reset(GenerateSynthesizedMouseEvent(true));
745 sticky_key.HandleMouseEvent(mev.get());
746 EXPECT_TRUE(mev->flags() & ui::EF_CONTROL_DOWN);
747 EXPECT_EQ(StickyKeysHandler::ENABLED, sticky_key.current_state());
748
749 mev.reset(GenerateSynthesizedMouseEvent(false));
750 sticky_key.HandleMouseEvent(mev.get());
751 EXPECT_TRUE(mev->flags() & ui::EF_CONTROL_DOWN);
752 EXPECT_EQ(StickyKeysHandler::DISABLED, sticky_key.current_state());
753 }
754
755 TEST_F(StickyKeysTest, KeyEventDispatchImpl) {
756 // Test the actual key event dispatch implementation.
757 EventBuffer buffer;
758 ScopedVector<ui::Event> events;
759 aura::RootWindowHostDelegate* delegate = Shell::GetPrimaryRootWindow()
760 ->GetDispatcher()->AsRootWindowHostDelegate();
761 Shell::GetInstance()->AddPreTargetHandler(&buffer);
762 Shell::GetInstance()->sticky_keys()->Enable(true);
763
764 SendActivateStickyKeyPattern(delegate, ui::VKEY_CONTROL);
765 scoped_ptr<ui::KeyEvent> ev;
766 buffer.PopEvents(&events);
767
768 // Test key press event is correctly modified and modifier release
769 // event is sent.
770 ev.reset(GenerateKey(true, ui::VKEY_C));
771 delegate->OnHostKeyEvent(ev.get());
772 buffer.PopEvents(&events);
773 EXPECT_EQ(2u, events.size());
774 EXPECT_EQ(ui::ET_KEY_PRESSED, events[0]->type());
775 EXPECT_EQ(ui::VKEY_C, static_cast<ui::KeyEvent*>(events[0])->key_code());
776 EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
777 EXPECT_EQ(ui::ET_KEY_RELEASED, events[1]->type());
778 EXPECT_EQ(ui::VKEY_CONTROL,
779 static_cast<ui::KeyEvent*>(events[1])->key_code());
780
781 // Test key release event is not modified.
782 ev.reset(GenerateKey(false, ui::VKEY_C));
783 delegate->OnHostKeyEvent(ev.get());
784 buffer.PopEvents(&events);
785 EXPECT_EQ(1u, events.size());
786 EXPECT_EQ(ui::ET_KEY_RELEASED, events[0]->type());
787 EXPECT_EQ(ui::VKEY_C,
788 static_cast<ui::KeyEvent*>(events[0])->key_code());
789 EXPECT_FALSE(events[0]->flags() & ui::EF_CONTROL_DOWN);
790
791 Shell::GetInstance()->RemovePreTargetHandler(&buffer);
792 }
793
794 TEST_F(StickyKeysTest, MouseEventDispatchImpl) {
795 // Test the actual sticky mouse event dispatch implementation.
796 EventBuffer buffer;
797 ScopedVector<ui::Event> events;
798 aura::RootWindowHostDelegate* delegate = Shell::GetPrimaryRootWindow()
799 ->GetDispatcher()->AsRootWindowHostDelegate();
800 Shell::GetInstance()->AddPreTargetHandler(&buffer);
801 Shell::GetInstance()->sticky_keys()->Enable(true);
802
803 scoped_ptr<ui::MouseEvent> ev;
804 SendActivateStickyKeyPattern(delegate, ui::VKEY_CONTROL);
805 buffer.PopEvents(&events);
806
807 // Test mouse press event is correctly modified.
808 ev.reset(GenerateMouseEvent(true));
809 delegate->OnHostMouseEvent(ev.get());
810 buffer.PopEvents(&events);
811 EXPECT_EQ(1u, events.size());
812 EXPECT_EQ(ui::ET_MOUSE_PRESSED, events[0]->type());
813 EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
814
815 // Test mouse release event is correctly modified and modifier release
816 // event is sent.
817 ev.reset(GenerateMouseEvent(false));
818 delegate->OnHostMouseEvent(ev.get());
819 buffer.PopEvents(&events);
820 EXPECT_EQ(2u, events.size());
821 EXPECT_EQ(ui::ET_MOUSE_RELEASED, events[0]->type());
822 EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
823 EXPECT_EQ(ui::ET_KEY_RELEASED, events[1]->type());
824 EXPECT_EQ(ui::VKEY_CONTROL,
825 static_cast<ui::KeyEvent*>(events[1])->key_code());
826
827 Shell::GetInstance()->RemovePreTargetHandler(&buffer);
828 }
829
830 TEST_F(StickyKeysTest, MouseWheelEventDispatchImpl) {
831 // Test the actual mouse wheel event dispatch implementation.
832 EventBuffer buffer;
833 ScopedVector<ui::Event> events;
834 aura::RootWindowHostDelegate* delegate = Shell::GetPrimaryRootWindow()
835 ->GetDispatcher()->AsRootWindowHostDelegate();
836 Shell::GetInstance()->AddPreTargetHandler(&buffer);
837 Shell::GetInstance()->sticky_keys()->Enable(true);
838
839 scoped_ptr<ui::MouseWheelEvent> ev;
840 SendActivateStickyKeyPattern(delegate, ui::VKEY_CONTROL);
841 buffer.PopEvents(&events);
842
843 // Test positive mouse wheel event is correctly modified and modifier release
844 // event is sent.
845 ev.reset(GenerateMouseWheelEvent(ui::MouseWheelEvent::kWheelDelta));
846 delegate->OnHostMouseEvent(ev.get());
847 buffer.PopEvents(&events);
848 EXPECT_EQ(2u, events.size());
849 EXPECT_TRUE(events[0]->IsMouseWheelEvent());
850 EXPECT_EQ(ui::MouseWheelEvent::kWheelDelta,
851 static_cast<ui::MouseWheelEvent*>(events[0])->y_offset());
852 EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
853 EXPECT_EQ(ui::ET_KEY_RELEASED, events[1]->type());
854 EXPECT_EQ(ui::VKEY_CONTROL,
855 static_cast<ui::KeyEvent*>(events[1])->key_code());
856
857 // Test negative mouse wheel event is correctly modified and modifier release
858 // event is sent.
859 SendActivateStickyKeyPattern(delegate, ui::VKEY_CONTROL);
860 buffer.PopEvents(&events);
861
862 ev.reset(GenerateMouseWheelEvent(-ui::MouseWheelEvent::kWheelDelta));
863 delegate->OnHostMouseEvent(ev.get());
864 buffer.PopEvents(&events);
865 EXPECT_EQ(2u, events.size());
866 EXPECT_TRUE(events[0]->IsMouseWheelEvent());
867 EXPECT_EQ(-ui::MouseWheelEvent::kWheelDelta,
868 static_cast<ui::MouseWheelEvent*>(events[0])->y_offset());
869 EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
870 EXPECT_EQ(ui::ET_KEY_RELEASED, events[1]->type());
871 EXPECT_EQ(ui::VKEY_CONTROL,
872 static_cast<ui::KeyEvent*>(events[1])->key_code());
873
874 Shell::GetInstance()->RemovePreTargetHandler(&buffer);
875 }
876
877 } // namespace ash
OLDNEW
« no previous file with comments | « ash/wm/sticky_keys.cc ('k') | chrome/browser/chromeos/accessibility/accessibility_manager.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698