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/wm/sticky_keys.h"
11 #include "ash/test/ash_test_base.h"
12 #include "base/memory/scoped_vector.h"
13 #include "ui/base/x/x11_util.h"
17 // A stub implementation of EventTarget.
18 class StubEventTarget
: public ui::EventTarget
{
21 virtual ~StubEventTarget() {}
23 virtual bool CanAcceptEvent(const ui::Event
& event
) OVERRIDE
{
27 virtual EventTarget
* GetParentTarget() OVERRIDE
{
32 DISALLOW_COPY_AND_ASSIGN(StubEventTarget
);
35 // A testable and StickyKeysHandler.
36 class MockStickyKeysHandlerDelegate
:
37 public StickyKeysHandler::StickyKeysHandlerDelegate
{
39 MockStickyKeysHandlerDelegate() {}
40 virtual ~MockStickyKeysHandlerDelegate() {}
42 // StickyKeysHandler override.
43 virtual void DispatchKeyEvent(ui::KeyEvent
* event
,
44 aura::Window
* target
) OVERRIDE
{
45 key_events_
.push_back(event
->Copy());
48 // Returns the count of dispatched keyboard event.
49 size_t GetKeyEventCount() const {
50 return key_events_
.size();
53 // Returns the |index|-th dispatched keyboard event.
54 const ui::KeyEvent
* GetKeyEvent(size_t index
) const {
55 return key_events_
[index
];
59 ScopedVector
<ui::KeyEvent
> key_events_
;
61 DISALLOW_COPY_AND_ASSIGN(MockStickyKeysHandlerDelegate
);
64 class StickyKeysTest
: public test::AshTestBase
{
66 virtual void SetUp() OVERRIDE
{
67 target_
.reset(new StubEventTarget());
68 test::AshTestBase::SetUp();
71 virtual void TearDown() OVERRIDE
{
72 test::AshTestBase::TearDown();
76 // Generates keyboard event.
77 ui::KeyEvent
* GenerateKey(bool is_key_press
, ui::KeyboardCode code
) {
78 XEvent
* xev
= new XEvent();
79 ui::InitXKeyEventForTesting(
80 is_key_press
? ui::ET_KEY_PRESSED
: ui::ET_KEY_RELEASED
,
85 ui::KeyEvent
* event
= new ui::KeyEvent(xev
, false);
86 ui::Event::DispatcherApi
dispatcher(event
);
87 dispatcher
.set_target(target_
.get());
92 scoped_ptr
<StubEventTarget
> target_
;
93 ScopedVector
<XEvent
> xevs_
;
96 TEST_F(StickyKeysTest
, BasicOneshotScenarioTest
) {
97 scoped_ptr
<ui::KeyEvent
> ev
;
98 MockStickyKeysHandlerDelegate
* mock_delegate
=
99 new MockStickyKeysHandlerDelegate();
100 StickyKeysHandler
sticky_key(ui::EF_SHIFT_DOWN
, mock_delegate
);
102 EXPECT_EQ(StickyKeysHandler::DISABLED
, sticky_key
.current_state());
103 ev
.reset(GenerateKey(true, ui::VKEY_SHIFT
));
104 sticky_key
.HandleKeyEvent(ev
.get());
106 ev
.reset(GenerateKey(false, ui::VKEY_SHIFT
));
107 sticky_key
.HandleKeyEvent(ev
.get());
109 // By typing Shift key, internal state become ENABLED.
110 EXPECT_EQ(StickyKeysHandler::ENABLED
, sticky_key
.current_state());
112 ev
.reset(GenerateKey(true, ui::VKEY_A
));
113 sticky_key
.HandleKeyEvent(ev
.get());
115 // Next keyboard event is shift modified.
116 EXPECT_TRUE(ev
->flags() & ui::EF_SHIFT_DOWN
);
118 ev
.reset(GenerateKey(false, ui::VKEY_A
));
119 sticky_key
.HandleKeyEvent(ev
.get());
121 EXPECT_EQ(StickyKeysHandler::DISABLED
, sticky_key
.current_state());
122 // Making sure Shift up keyboard event is dispatched.
123 ASSERT_EQ(2U, mock_delegate
->GetKeyEventCount());
124 EXPECT_EQ(ui::VKEY_A
, mock_delegate
->GetKeyEvent(0)->key_code());
125 EXPECT_EQ(ui::ET_KEY_PRESSED
, mock_delegate
->GetKeyEvent(0)->type());
126 EXPECT_EQ(ui::VKEY_SHIFT
, mock_delegate
->GetKeyEvent(1)->key_code());
127 EXPECT_EQ(ui::ET_KEY_RELEASED
, mock_delegate
->GetKeyEvent(1)->type());
129 // Enabled state is one shot, so next key event should not be shift modified.
130 ev
.reset(GenerateKey(true, ui::VKEY_A
));
131 sticky_key
.HandleKeyEvent(ev
.get());
132 EXPECT_FALSE(ev
->flags() & ui::EF_SHIFT_DOWN
);
134 ev
.reset(GenerateKey(false, ui::VKEY_A
));
135 sticky_key
.HandleKeyEvent(ev
.get());
136 EXPECT_FALSE(ev
->flags() & ui::EF_SHIFT_DOWN
);
139 TEST_F(StickyKeysTest
, BasicLockedScenarioTest
) {
140 scoped_ptr
<ui::KeyEvent
> ev
;
141 MockStickyKeysHandlerDelegate
* mock_delegate
=
142 new MockStickyKeysHandlerDelegate();
143 StickyKeysHandler
sticky_key(ui::EF_SHIFT_DOWN
, mock_delegate
);
145 EXPECT_EQ(StickyKeysHandler::DISABLED
, sticky_key
.current_state());
146 ev
.reset(GenerateKey(true, ui::VKEY_SHIFT
));
147 sticky_key
.HandleKeyEvent(ev
.get());
149 ev
.reset(GenerateKey(false, ui::VKEY_SHIFT
));
150 sticky_key
.HandleKeyEvent(ev
.get());
152 // By typing shift key, internal state become ENABLED.
153 EXPECT_EQ(StickyKeysHandler::ENABLED
, sticky_key
.current_state());
155 ev
.reset(GenerateKey(true, ui::VKEY_SHIFT
));
156 sticky_key
.HandleKeyEvent(ev
.get());
158 ev
.reset(GenerateKey(false, ui::VKEY_SHIFT
));
159 sticky_key
.HandleKeyEvent(ev
.get());
161 // By typing shift key again, internal state become LOCKED.
162 EXPECT_EQ(StickyKeysHandler::LOCKED
, sticky_key
.current_state());
164 // All keyboard events including keyUp become shift modified.
165 ev
.reset(GenerateKey(true, ui::VKEY_A
));
166 sticky_key
.HandleKeyEvent(ev
.get());
167 EXPECT_TRUE(ev
->flags() & ui::EF_SHIFT_DOWN
);
169 ev
.reset(GenerateKey(false, ui::VKEY_A
));
170 sticky_key
.HandleKeyEvent(ev
.get());
171 EXPECT_TRUE(ev
->flags() & ui::EF_SHIFT_DOWN
);
173 // Locked state keeps after normal keyboard event.
174 EXPECT_EQ(StickyKeysHandler::LOCKED
, sticky_key
.current_state());
176 ev
.reset(GenerateKey(true, ui::VKEY_B
));
177 sticky_key
.HandleKeyEvent(ev
.get());
178 EXPECT_TRUE(ev
->flags() & ui::EF_SHIFT_DOWN
);
180 ev
.reset(GenerateKey(false, ui::VKEY_B
));
181 sticky_key
.HandleKeyEvent(ev
.get());
182 EXPECT_TRUE(ev
->flags() & ui::EF_SHIFT_DOWN
);
184 EXPECT_EQ(StickyKeysHandler::LOCKED
, sticky_key
.current_state());
186 ev
.reset(GenerateKey(true, ui::VKEY_SHIFT
));
187 sticky_key
.HandleKeyEvent(ev
.get());
189 ev
.reset(GenerateKey(false, ui::VKEY_SHIFT
));
190 sticky_key
.HandleKeyEvent(ev
.get());
192 // By typing shift key again, internal state become back to DISABLED.
193 EXPECT_EQ(StickyKeysHandler::DISABLED
, sticky_key
.current_state());
196 TEST_F(StickyKeysTest
, NonTargetModifierTest
) {
197 scoped_ptr
<ui::KeyEvent
> ev
;
198 MockStickyKeysHandlerDelegate
* mock_delegate
=
199 new MockStickyKeysHandlerDelegate();
200 StickyKeysHandler
sticky_key(ui::EF_SHIFT_DOWN
, mock_delegate
);
202 EXPECT_EQ(StickyKeysHandler::DISABLED
, sticky_key
.current_state());
204 // Non target modifier key does not affect internal state
205 ev
.reset(GenerateKey(true, ui::VKEY_MENU
));
206 sticky_key
.HandleKeyEvent(ev
.get());
207 EXPECT_EQ(StickyKeysHandler::DISABLED
, sticky_key
.current_state());
209 ev
.reset(GenerateKey(false, ui::VKEY_MENU
));
210 sticky_key
.HandleKeyEvent(ev
.get());
211 EXPECT_EQ(StickyKeysHandler::DISABLED
, sticky_key
.current_state());
213 ev
.reset(GenerateKey(true, ui::VKEY_SHIFT
));
214 sticky_key
.HandleKeyEvent(ev
.get());
215 ev
.reset(GenerateKey(false, ui::VKEY_SHIFT
));
216 sticky_key
.HandleKeyEvent(ev
.get());
217 EXPECT_EQ(StickyKeysHandler::ENABLED
, sticky_key
.current_state());
219 // Non target modifier key does not affect internal state
220 ev
.reset(GenerateKey(true, ui::VKEY_MENU
));
221 sticky_key
.HandleKeyEvent(ev
.get());
222 EXPECT_EQ(StickyKeysHandler::ENABLED
, sticky_key
.current_state());
224 ev
.reset(GenerateKey(false, ui::VKEY_MENU
));
225 sticky_key
.HandleKeyEvent(ev
.get());
226 EXPECT_EQ(StickyKeysHandler::ENABLED
, sticky_key
.current_state());
228 ev
.reset(GenerateKey(true, ui::VKEY_SHIFT
));
229 sticky_key
.HandleKeyEvent(ev
.get());
230 ev
.reset(GenerateKey(false, ui::VKEY_SHIFT
));
231 sticky_key
.HandleKeyEvent(ev
.get());
232 EXPECT_EQ(StickyKeysHandler::LOCKED
, sticky_key
.current_state());
234 // Non target modifier key does not affect internal state
235 ev
.reset(GenerateKey(true, ui::VKEY_MENU
));
236 sticky_key
.HandleKeyEvent(ev
.get());
237 EXPECT_EQ(StickyKeysHandler::LOCKED
, sticky_key
.current_state());
239 ev
.reset(GenerateKey(false, ui::VKEY_MENU
));
240 sticky_key
.HandleKeyEvent(ev
.get());
241 EXPECT_EQ(StickyKeysHandler::LOCKED
, sticky_key
.current_state());