- add sources.
[platform/framework/web/crosswalk.git] / src / ash / wm / sticky_keys_unittest.cc
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
11 #include "ash/test/ash_test_base.h"
12 #include "base/memory/scoped_vector.h"
13 #include "ui/events/x/events_x_utils.h"
14
15 namespace ash {
16
17 // A stub implementation of EventTarget.
18 class StubEventTarget : public ui::EventTarget {
19  public:
20   StubEventTarget() {}
21   virtual ~StubEventTarget() {}
22
23   virtual bool CanAcceptEvent(const ui::Event& event) OVERRIDE {
24     return true;
25   }
26
27   virtual EventTarget* GetParentTarget() OVERRIDE {
28     return NULL;
29   }
30
31  private:
32   DISALLOW_COPY_AND_ASSIGN(StubEventTarget);
33 };
34
35 // A testable and StickyKeysHandler.
36 class MockStickyKeysHandlerDelegate :
37     public StickyKeysHandler::StickyKeysHandlerDelegate {
38  public:
39   MockStickyKeysHandlerDelegate() {}
40   virtual ~MockStickyKeysHandlerDelegate() {}
41
42   // StickyKeysHandler override.
43   virtual void DispatchKeyEvent(ui::KeyEvent* event,
44                                 aura::Window* target) OVERRIDE {
45     key_events_.push_back(event->Copy());
46   }
47
48   // Returns the count of dispatched keyboard event.
49   size_t GetKeyEventCount() const {
50     return key_events_.size();
51   }
52
53   // Returns the |index|-th dispatched keyboard event.
54   const ui::KeyEvent* GetKeyEvent(size_t index) const {
55     return key_events_[index];
56   }
57
58  private:
59   ScopedVector<ui::KeyEvent> key_events_;
60
61   DISALLOW_COPY_AND_ASSIGN(MockStickyKeysHandlerDelegate);
62 };
63
64 class StickyKeysTest : public test::AshTestBase {
65  protected:
66   virtual void SetUp() OVERRIDE {
67     target_.reset(new StubEventTarget());
68     test::AshTestBase::SetUp();
69   }
70
71   virtual void TearDown() OVERRIDE {
72     test::AshTestBase::TearDown();
73     target_.reset();
74   }
75
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,
81         code,
82         0,
83         xev);
84     xevs_.push_back(xev);
85     ui::KeyEvent* event =  new ui::KeyEvent(xev, false);
86     ui::Event::DispatcherApi dispatcher(event);
87     dispatcher.set_target(target_.get());
88     return event;
89   }
90
91  private:
92   scoped_ptr<StubEventTarget> target_;
93   ScopedVector<XEvent> xevs_;
94 };
95
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);
101
102   EXPECT_EQ(StickyKeysHandler::DISABLED, sticky_key.current_state());
103   ev.reset(GenerateKey(true, ui::VKEY_SHIFT));
104   sticky_key.HandleKeyEvent(ev.get());
105
106   ev.reset(GenerateKey(false, ui::VKEY_SHIFT));
107   sticky_key.HandleKeyEvent(ev.get());
108
109   // By typing Shift key, internal state become ENABLED.
110   EXPECT_EQ(StickyKeysHandler::ENABLED, sticky_key.current_state());
111
112   ev.reset(GenerateKey(true, ui::VKEY_A));
113   sticky_key.HandleKeyEvent(ev.get());
114
115   // Next keyboard event is shift modified.
116   EXPECT_TRUE(ev->flags() & ui::EF_SHIFT_DOWN);
117
118   ev.reset(GenerateKey(false, ui::VKEY_A));
119   sticky_key.HandleKeyEvent(ev.get());
120
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());
128
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);
133
134   ev.reset(GenerateKey(false, ui::VKEY_A));
135   sticky_key.HandleKeyEvent(ev.get());
136   EXPECT_FALSE(ev->flags() & ui::EF_SHIFT_DOWN);
137 }
138
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);
144
145   EXPECT_EQ(StickyKeysHandler::DISABLED, sticky_key.current_state());
146   ev.reset(GenerateKey(true, ui::VKEY_SHIFT));
147   sticky_key.HandleKeyEvent(ev.get());
148
149   ev.reset(GenerateKey(false, ui::VKEY_SHIFT));
150   sticky_key.HandleKeyEvent(ev.get());
151
152   // By typing shift key, internal state become ENABLED.
153   EXPECT_EQ(StickyKeysHandler::ENABLED, sticky_key.current_state());
154
155   ev.reset(GenerateKey(true, ui::VKEY_SHIFT));
156   sticky_key.HandleKeyEvent(ev.get());
157
158   ev.reset(GenerateKey(false, ui::VKEY_SHIFT));
159   sticky_key.HandleKeyEvent(ev.get());
160
161   // By typing shift key again, internal state become LOCKED.
162   EXPECT_EQ(StickyKeysHandler::LOCKED, sticky_key.current_state());
163
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);
168
169   ev.reset(GenerateKey(false, ui::VKEY_A));
170   sticky_key.HandleKeyEvent(ev.get());
171   EXPECT_TRUE(ev->flags() & ui::EF_SHIFT_DOWN);
172
173   // Locked state keeps after normal keyboard event.
174   EXPECT_EQ(StickyKeysHandler::LOCKED, sticky_key.current_state());
175
176   ev.reset(GenerateKey(true, ui::VKEY_B));
177   sticky_key.HandleKeyEvent(ev.get());
178   EXPECT_TRUE(ev->flags() & ui::EF_SHIFT_DOWN);
179
180   ev.reset(GenerateKey(false, ui::VKEY_B));
181   sticky_key.HandleKeyEvent(ev.get());
182   EXPECT_TRUE(ev->flags() & ui::EF_SHIFT_DOWN);
183
184   EXPECT_EQ(StickyKeysHandler::LOCKED, sticky_key.current_state());
185
186   ev.reset(GenerateKey(true, ui::VKEY_SHIFT));
187   sticky_key.HandleKeyEvent(ev.get());
188
189   ev.reset(GenerateKey(false, ui::VKEY_SHIFT));
190   sticky_key.HandleKeyEvent(ev.get());
191
192   // By typing shift key again, internal state become back to DISABLED.
193   EXPECT_EQ(StickyKeysHandler::DISABLED, sticky_key.current_state());
194 }
195
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);
201
202   EXPECT_EQ(StickyKeysHandler::DISABLED, sticky_key.current_state());
203
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());
208
209   ev.reset(GenerateKey(false, ui::VKEY_MENU));
210   sticky_key.HandleKeyEvent(ev.get());
211   EXPECT_EQ(StickyKeysHandler::DISABLED, sticky_key.current_state());
212
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());
218
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());
223
224   ev.reset(GenerateKey(false, ui::VKEY_MENU));
225   sticky_key.HandleKeyEvent(ev.get());
226   EXPECT_EQ(StickyKeysHandler::ENABLED, sticky_key.current_state());
227
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());
233
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());
238
239   ev.reset(GenerateKey(false, ui::VKEY_MENU));
240   sticky_key.HandleKeyEvent(ev.get());
241   EXPECT_EQ(StickyKeysHandler::LOCKED, sticky_key.current_state());
242 }
243
244 TEST_F(StickyKeysTest, NormalShortcutTest) {
245   // Sticky keys should not be enabled if we perform a normal shortcut.
246   scoped_ptr<ui::KeyEvent> ev;
247   MockStickyKeysHandlerDelegate* mock_delegate =
248       new MockStickyKeysHandlerDelegate();
249   StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
250
251   EXPECT_EQ(StickyKeysHandler::DISABLED, sticky_key.current_state());
252
253   // Perform ctrl+n shortcut.
254   ev.reset(GenerateKey(true, ui::VKEY_CONTROL));
255   sticky_key.HandleKeyEvent(ev.get());
256   ev.reset(GenerateKey(true, ui::VKEY_N));
257   sticky_key.HandleKeyEvent(ev.get());
258   ev.reset(GenerateKey(false, ui::VKEY_N));
259   sticky_key.HandleKeyEvent(ev.get());
260   EXPECT_EQ(StickyKeysHandler::DISABLED, sticky_key.current_state());
261
262   // Sticky keys should not be enabled afterwards.
263   ev.reset(GenerateKey(false, ui::VKEY_CONTROL));
264   sticky_key.HandleKeyEvent(ev.get());
265   EXPECT_EQ(StickyKeysHandler::DISABLED, sticky_key.current_state());
266 }
267
268 }  // namespace ash