sticky_keys_unittest.cc 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679
  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. #include "ash/accessibility/sticky_keys/sticky_keys_controller.h"
  5. #include "ash/shell.h"
  6. #include "ash/test/ash_test_base.h"
  7. #include "base/bind.h"
  8. #include "base/callback.h"
  9. #include "ui/aura/window.h"
  10. #include "ui/aura/window_tree_host.h"
  11. #include "ui/events/event_source.h"
  12. #include "ui/events/event_utils.h"
  13. namespace ash {
  14. class StickyKeysTest : public AshTestBase {
  15. public:
  16. StickyKeysTest(const StickyKeysTest&) = delete;
  17. StickyKeysTest& operator=(const StickyKeysTest&) = delete;
  18. protected:
  19. StickyKeysTest() : target_(NULL), root_window_(NULL) {}
  20. void SetUp() override {
  21. AshTestBase::SetUp();
  22. // |target_| owned by root window of shell. It is still safe to delete
  23. // it ourselves.
  24. target_ = CreateTestWindowInShellWithId(0);
  25. root_window_ = target_->GetRootWindow();
  26. }
  27. virtual void OnShortcutPressed() {
  28. if (target_) {
  29. delete target_;
  30. target_ = NULL;
  31. }
  32. }
  33. ui::KeyEvent* GenerateKey(ui::EventType type, ui::KeyboardCode code) {
  34. return GenerateSynthesizedKeyEvent(type, code);
  35. }
  36. // Creates a mouse event backed by a native XInput2 generic button event.
  37. // This is the standard native event on Chromebooks.
  38. ui::MouseEvent* GenerateMouseEvent(ui::EventType type) {
  39. return GenerateMouseEventAt(type, gfx::Point());
  40. }
  41. // Creates a mouse event backed by a native XInput2 generic button event.
  42. // The |location| should be in physical pixels.
  43. ui::MouseEvent* GenerateMouseEventAt(ui::EventType type,
  44. const gfx::Point& location) {
  45. return GenerateSynthesizedMouseEventAt(type, location);
  46. }
  47. ui::MouseWheelEvent* GenerateMouseWheelEvent(int wheel_delta) {
  48. return GenerateSynthesizedMouseWheelEvent(wheel_delta);
  49. }
  50. ui::ScrollEvent* GenerateScrollEvent(int scroll_delta) {
  51. ui::ScrollEvent* event = new ui::ScrollEvent(
  52. ui::ET_SCROLL, gfx::Point(0, 0), ui::EventTimeForNow(), ui::EF_NONE,
  53. 0, // x_offset
  54. scroll_delta, // y_offset
  55. 0, // x_offset_ordinal
  56. scroll_delta, // y_offset_ordinal
  57. 2); // finger_count
  58. ui::Event::DispatcherApi dispatcher(event);
  59. dispatcher.set_target(target_);
  60. return event;
  61. }
  62. ui::ScrollEvent* GenerateFlingScrollEvent(int fling_delta, bool is_cancel) {
  63. ui::ScrollEvent* event = new ui::ScrollEvent(
  64. is_cancel ? ui::ET_SCROLL_FLING_CANCEL : ui::ET_SCROLL_FLING_START,
  65. gfx::Point(0, 0), ui::EventTimeForNow(), ui::EF_NONE,
  66. 0, // x_velocity
  67. fling_delta, // y_velocity
  68. 0, // x_velocity_ordinal
  69. fling_delta, // y_velocity_ordinal
  70. 11); // finger_count
  71. ui::Event::DispatcherApi dispatcher(event);
  72. dispatcher.set_target(target_);
  73. return event;
  74. }
  75. // Creates a synthesized KeyEvent that is not backed by a native event.
  76. ui::KeyEvent* GenerateSynthesizedKeyEvent(ui::EventType type,
  77. ui::KeyboardCode code) {
  78. return new ui::KeyEvent(type, code, ui::EF_NONE);
  79. }
  80. // Creates a synthesized MouseEvent that is not backed by a native event.
  81. ui::MouseEvent* GenerateSynthesizedMouseEventAt(ui::EventType event_type,
  82. const gfx::Point& location) {
  83. ui::MouseEvent* event;
  84. if (event_type == ui::ET_MOUSEWHEEL) {
  85. event = new ui::MouseWheelEvent(
  86. gfx::Vector2d(), location, location, ui::EventTimeForNow(),
  87. ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
  88. } else {
  89. event = new ui::MouseEvent(
  90. event_type, location, location, ui::EventTimeForNow(),
  91. ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
  92. }
  93. ui::Event::DispatcherApi dispatcher(event);
  94. dispatcher.set_target(target_);
  95. return event;
  96. }
  97. // Creates a synthesized mouse press or release event.
  98. ui::MouseEvent* GenerateSynthesizedMouseClickEvent(
  99. ui::EventType type,
  100. const gfx::Point& location) {
  101. return GenerateSynthesizedMouseEventAt(type, location);
  102. }
  103. // Creates a synthesized ET_MOUSE_MOVED event.
  104. ui::MouseEvent* GenerateSynthesizedMouseMoveEvent(
  105. const gfx::Point& location) {
  106. return GenerateSynthesizedMouseEventAt(ui::ET_MOUSE_MOVED, location);
  107. }
  108. // Creates a synthesized MouseWHeel event.
  109. ui::MouseWheelEvent* GenerateSynthesizedMouseWheelEvent(int wheel_delta) {
  110. std::unique_ptr<ui::MouseEvent> mev(
  111. GenerateSynthesizedMouseEventAt(ui::ET_MOUSEWHEEL, gfx::Point(0, 0)));
  112. ui::MouseWheelEvent* event = new ui::MouseWheelEvent(*mev, 0, wheel_delta);
  113. ui::Event::DispatcherApi dispatcher(event);
  114. dispatcher.set_target(target_);
  115. return event;
  116. }
  117. void SendActivateStickyKeyPattern(StickyKeysHandler* handler,
  118. ui::KeyboardCode key_code) {
  119. bool released = false;
  120. int down_flags = 0;
  121. std::unique_ptr<ui::KeyEvent> ev;
  122. ev.reset(GenerateKey(ui::ET_KEY_PRESSED, key_code));
  123. handler->HandleKeyEvent(*ev.get(), &down_flags, &released);
  124. ev.reset(GenerateKey(ui::ET_KEY_RELEASED, key_code));
  125. handler->HandleKeyEvent(*ev.get(), &down_flags, &released);
  126. }
  127. bool HandleKeyEvent(const ui::KeyEvent& key_event,
  128. StickyKeysHandler* handler,
  129. int* down,
  130. bool* up) {
  131. return handler->HandleKeyEvent(key_event, down, up);
  132. }
  133. int HandleKeyEventForDownFlags(const ui::KeyEvent& key_event,
  134. StickyKeysHandler* handler) {
  135. bool released = false;
  136. int down = 0;
  137. handler->HandleKeyEvent(key_event, &down, &released);
  138. return down;
  139. }
  140. aura::Window* target() { return target_; }
  141. private:
  142. // Owned by root window of shell, but we can still delete |target_| safely.
  143. aura::Window* target_;
  144. // The root window of |target_|. Not owned.
  145. aura::Window* root_window_;
  146. };
  147. TEST_F(StickyKeysTest, BasicOneshotScenarioTest) {
  148. std::unique_ptr<ui::KeyEvent> ev;
  149. StickyKeysHandler sticky_key(ui::EF_SHIFT_DOWN);
  150. EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
  151. // By typing Shift key, internal state become ENABLED.
  152. SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
  153. EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
  154. ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_A));
  155. bool released = false;
  156. int mod_down_flags = 0;
  157. HandleKeyEvent(*ev.get(), &sticky_key, &mod_down_flags, &released);
  158. // Next keyboard event is shift modified.
  159. EXPECT_TRUE(mod_down_flags & ui::EF_SHIFT_DOWN);
  160. // Modifier release notification happens.
  161. EXPECT_TRUE(released);
  162. ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_A));
  163. released = false;
  164. mod_down_flags = 0;
  165. HandleKeyEvent(*ev.get(), &sticky_key, &mod_down_flags, &released);
  166. EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
  167. // Making sure Shift up keyboard event is available.
  168. std::unique_ptr<ui::Event> up_event;
  169. ASSERT_EQ(0, sticky_key.GetModifierUpEvent(&up_event));
  170. EXPECT_TRUE(up_event.get());
  171. EXPECT_EQ(ui::ET_KEY_RELEASED, up_event->type());
  172. EXPECT_EQ(ui::VKEY_SHIFT,
  173. static_cast<const ui::KeyEvent*>(up_event.get())->key_code());
  174. // Enabled state is one shot, so next key event should not be shift modified.
  175. ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_A));
  176. mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
  177. EXPECT_FALSE(mod_down_flags & ui::EF_SHIFT_DOWN);
  178. ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_A));
  179. mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
  180. EXPECT_FALSE(mod_down_flags & ui::EF_SHIFT_DOWN);
  181. }
  182. TEST_F(StickyKeysTest, BasicLockedScenarioTest) {
  183. std::unique_ptr<ui::KeyEvent> ev;
  184. StickyKeysHandler sticky_key(ui::EF_SHIFT_DOWN);
  185. EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
  186. // By typing shift key, internal state become ENABLED.
  187. SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
  188. EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
  189. // By typing shift key again, internal state become LOCKED.
  190. SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
  191. EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
  192. // All keyboard events including keyUp become shift modified.
  193. ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_A));
  194. int mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
  195. EXPECT_TRUE(mod_down_flags & ui::EF_SHIFT_DOWN);
  196. ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_A));
  197. mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
  198. EXPECT_TRUE(mod_down_flags & ui::EF_SHIFT_DOWN);
  199. // Locked state keeps after normal keyboard event.
  200. EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
  201. ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_B));
  202. mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
  203. EXPECT_TRUE(mod_down_flags & ui::EF_SHIFT_DOWN);
  204. ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_B));
  205. mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
  206. EXPECT_TRUE(mod_down_flags & ui::EF_SHIFT_DOWN);
  207. EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
  208. // By typing shift key again, internal state become back to DISABLED.
  209. SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
  210. EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
  211. }
  212. TEST_F(StickyKeysTest, NonTargetModifierTest) {
  213. std::unique_ptr<ui::KeyEvent> ev;
  214. StickyKeysHandler sticky_key(ui::EF_SHIFT_DOWN);
  215. EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
  216. // Non target modifier key does not affect internal state
  217. ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_MENU));
  218. int mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
  219. EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
  220. EXPECT_EQ(ui::EF_NONE, mod_down_flags);
  221. ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_MENU));
  222. mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
  223. EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
  224. EXPECT_EQ(ui::EF_NONE, mod_down_flags);
  225. SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
  226. EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
  227. // Non target modifier key does not affect internal state
  228. ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_MENU));
  229. mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
  230. EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
  231. EXPECT_EQ(ui::EF_NONE, mod_down_flags);
  232. ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_MENU));
  233. mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
  234. EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
  235. EXPECT_EQ(ui::EF_NONE, mod_down_flags);
  236. SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
  237. EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
  238. // Non target modifier key does not affect internal state
  239. ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_MENU));
  240. mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
  241. EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
  242. EXPECT_EQ(ui::EF_NONE, mod_down_flags);
  243. ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_MENU));
  244. mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
  245. EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
  246. EXPECT_EQ(ui::EF_NONE, mod_down_flags);
  247. }
  248. TEST_F(StickyKeysTest, NormalShortcutTest) {
  249. // Sticky keys should not be enabled if we perform a normal shortcut.
  250. std::unique_ptr<ui::KeyEvent> ev;
  251. StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
  252. EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
  253. // Perform ctrl+n shortcut.
  254. ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL));
  255. int mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
  256. ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_N));
  257. mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
  258. ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_N));
  259. mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
  260. EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
  261. ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL));
  262. mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
  263. // Sticky keys should not be enabled afterwards.
  264. EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
  265. EXPECT_EQ(ui::EF_NONE, mod_down_flags);
  266. // Perform ctrl+n shortcut, releasing ctrl first.
  267. ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL));
  268. mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
  269. ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_N));
  270. mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
  271. EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
  272. ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL));
  273. mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
  274. ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_N));
  275. mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
  276. // Sticky keys should not be enabled afterwards.
  277. EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
  278. EXPECT_EQ(ui::EF_NONE, mod_down_flags);
  279. }
  280. TEST_F(StickyKeysTest, NormalModifiedClickTest) {
  281. std::unique_ptr<ui::KeyEvent> kev;
  282. std::unique_ptr<ui::MouseEvent> mev;
  283. StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
  284. EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
  285. // Perform ctrl+click.
  286. kev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL));
  287. int mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
  288. mev.reset(GenerateMouseEvent(ui::ET_MOUSE_PRESSED));
  289. bool released = false;
  290. sticky_key.HandleMouseEvent(*mev.get(), &mod_down_flags, &released);
  291. mev.reset(GenerateMouseEvent(ui::ET_MOUSE_RELEASED));
  292. sticky_key.HandleMouseEvent(*mev.get(), &mod_down_flags, &released);
  293. // Sticky keys should not be enabled afterwards.
  294. kev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL));
  295. mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
  296. EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
  297. EXPECT_EQ(ui::EF_NONE, mod_down_flags);
  298. }
  299. TEST_F(StickyKeysTest, MouseMovedModifierTest) {
  300. std::unique_ptr<ui::KeyEvent> kev;
  301. std::unique_ptr<ui::MouseEvent> mev;
  302. StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
  303. EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
  304. // Press ctrl and handle mouse move events.
  305. kev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL));
  306. int mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
  307. mev.reset(GenerateSynthesizedMouseMoveEvent(gfx::Point(0, 0)));
  308. bool released = false;
  309. sticky_key.HandleMouseEvent(*mev.get(), &mod_down_flags, &released);
  310. mev.reset(GenerateSynthesizedMouseMoveEvent(gfx::Point(100, 100)));
  311. sticky_key.HandleMouseEvent(*mev.get(), &mod_down_flags, &released);
  312. // Sticky keys should be enabled afterwards.
  313. kev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL));
  314. mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
  315. EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
  316. EXPECT_EQ(ui::EF_NONE, mod_down_flags);
  317. }
  318. TEST_F(StickyKeysTest, NormalModifiedScrollTest) {
  319. std::unique_ptr<ui::KeyEvent> kev;
  320. std::unique_ptr<ui::ScrollEvent> sev;
  321. StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
  322. EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
  323. // Perform ctrl+scroll.
  324. kev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL));
  325. int mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
  326. sev.reset(GenerateFlingScrollEvent(0, true));
  327. bool released = false;
  328. sticky_key.HandleScrollEvent(*sev.get(), &mod_down_flags, &released);
  329. sev.reset(GenerateScrollEvent(10));
  330. sticky_key.HandleScrollEvent(*sev.get(), &mod_down_flags, &released);
  331. sev.reset(GenerateFlingScrollEvent(10, false));
  332. sticky_key.HandleScrollEvent(*sev.get(), &mod_down_flags, &released);
  333. // Sticky keys should not be enabled afterwards.
  334. kev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL));
  335. mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
  336. EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
  337. EXPECT_EQ(ui::EF_NONE, mod_down_flags);
  338. }
  339. TEST_F(StickyKeysTest, MouseEventOneshot) {
  340. std::unique_ptr<ui::MouseEvent> ev;
  341. std::unique_ptr<ui::KeyEvent> kev;
  342. StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
  343. EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
  344. SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
  345. EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
  346. // We should still be in the ENABLED state until we get the mouse
  347. // release event.
  348. ev.reset(GenerateMouseEvent(ui::ET_MOUSE_PRESSED));
  349. bool released = false;
  350. int mod_down_flags = 0;
  351. sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
  352. EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
  353. EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
  354. ev.reset(GenerateMouseEvent(ui::ET_MOUSE_RELEASED));
  355. released = false;
  356. mod_down_flags = 0;
  357. sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
  358. EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
  359. EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
  360. // Making sure modifier key release event is dispatched in the right order.
  361. EXPECT_TRUE(released);
  362. std::unique_ptr<ui::Event> up_event;
  363. ASSERT_EQ(0, sticky_key.GetModifierUpEvent(&up_event));
  364. EXPECT_TRUE(up_event.get());
  365. EXPECT_EQ(ui::ET_KEY_RELEASED, up_event->type());
  366. EXPECT_EQ(ui::VKEY_CONTROL,
  367. static_cast<const ui::KeyEvent*>(up_event.get())->key_code());
  368. // Enabled state is one shot, so next click should not be control modified.
  369. ev.reset(GenerateMouseEvent(ui::ET_MOUSE_PRESSED));
  370. released = false;
  371. mod_down_flags = 0;
  372. sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
  373. EXPECT_FALSE(mod_down_flags & ui::EF_CONTROL_DOWN);
  374. ev.reset(GenerateMouseEvent(ui::ET_MOUSE_RELEASED));
  375. released = false;
  376. mod_down_flags = 0;
  377. sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
  378. EXPECT_FALSE(mod_down_flags & ui::EF_CONTROL_DOWN);
  379. }
  380. TEST_F(StickyKeysTest, MouseEventLocked) {
  381. std::unique_ptr<ui::MouseEvent> ev;
  382. std::unique_ptr<ui::KeyEvent> kev;
  383. StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
  384. EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
  385. // Pressing modifier key twice should make us enter lock state.
  386. SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
  387. EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
  388. SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
  389. EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
  390. // Mouse events should not disable locked mode.
  391. for (int i = 0; i < 3; ++i) {
  392. bool released = false;
  393. int mod_down_flags = 0;
  394. ev.reset(GenerateMouseEvent(ui::ET_MOUSE_PRESSED));
  395. sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
  396. EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
  397. ev.reset(GenerateMouseEvent(ui::ET_MOUSE_RELEASED));
  398. released = false;
  399. mod_down_flags = 0;
  400. sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
  401. EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
  402. EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
  403. }
  404. // Test with mouse wheel.
  405. for (int i = 0; i < 3; ++i) {
  406. bool released = false;
  407. int mod_down_flags = 0;
  408. ev.reset(GenerateMouseWheelEvent(ui::MouseWheelEvent::kWheelDelta));
  409. sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
  410. ev.reset(GenerateMouseWheelEvent(-ui::MouseWheelEvent::kWheelDelta));
  411. released = false;
  412. mod_down_flags = 0;
  413. sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
  414. EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
  415. EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
  416. }
  417. // Test mixed case with mouse events and key events.
  418. ev.reset(GenerateMouseWheelEvent(ui::MouseWheelEvent::kWheelDelta));
  419. bool released = false;
  420. int mod_down_flags = 0;
  421. sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
  422. EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
  423. kev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_N));
  424. mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
  425. EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
  426. mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
  427. EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
  428. EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
  429. }
  430. TEST_F(StickyKeysTest, ScrollEventOneshot) {
  431. std::unique_ptr<ui::ScrollEvent> ev;
  432. std::unique_ptr<ui::KeyEvent> kev;
  433. StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
  434. int scroll_deltas[] = {-10, 10};
  435. for (int i = 0; i < 2; ++i) {
  436. // Enable sticky keys.
  437. EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
  438. SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
  439. EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
  440. // Test a scroll sequence. Sticky keys should only be disabled at the end
  441. // of the scroll sequence. Fling cancel event starts the scroll sequence.
  442. ev.reset(GenerateFlingScrollEvent(0, true));
  443. bool released = false;
  444. int mod_down_flags = 0;
  445. sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
  446. EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
  447. EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
  448. // Scrolls should all be modified but not disable sticky keys.
  449. for (int j = 0; j < 3; ++j) {
  450. ev.reset(GenerateScrollEvent(scroll_deltas[i]));
  451. released = false;
  452. mod_down_flags = 0;
  453. sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
  454. EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
  455. EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
  456. }
  457. // Fling start event ends scroll sequence.
  458. ev.reset(GenerateFlingScrollEvent(scroll_deltas[i], false));
  459. released = false;
  460. mod_down_flags = 0;
  461. sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
  462. EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
  463. EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
  464. std::unique_ptr<ui::Event> up_event;
  465. EXPECT_TRUE(released);
  466. ASSERT_EQ(0, sticky_key.GetModifierUpEvent(&up_event));
  467. EXPECT_TRUE(up_event.get());
  468. EXPECT_EQ(ui::ET_KEY_RELEASED, up_event->type());
  469. EXPECT_EQ(ui::VKEY_CONTROL,
  470. static_cast<const ui::KeyEvent*>(up_event.get())->key_code());
  471. }
  472. }
  473. TEST_F(StickyKeysTest, ScrollDirectionChanged) {
  474. std::unique_ptr<ui::ScrollEvent> ev;
  475. std::unique_ptr<ui::KeyEvent> kev;
  476. StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
  477. // Test direction change with both boundary value and negative value.
  478. const int direction_change_values[2] = {0, -10};
  479. for (int i = 0; i < 2; ++i) {
  480. SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
  481. EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
  482. // Fling cancel starts scroll sequence.
  483. ev.reset(GenerateFlingScrollEvent(0, true));
  484. bool released = false;
  485. int mod_down_flags = 0;
  486. sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
  487. EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
  488. // Test that changing directions in a scroll sequence will
  489. // return sticky keys to DISABLED state.
  490. for (int j = 0; j < 3; ++j) {
  491. ev.reset(GenerateScrollEvent(10));
  492. released = false;
  493. mod_down_flags = 0;
  494. sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
  495. EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
  496. EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
  497. }
  498. ev.reset(GenerateScrollEvent(direction_change_values[i]));
  499. released = false;
  500. mod_down_flags = 0;
  501. sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
  502. EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
  503. }
  504. }
  505. TEST_F(StickyKeysTest, ScrollEventLocked) {
  506. std::unique_ptr<ui::ScrollEvent> ev;
  507. std::unique_ptr<ui::KeyEvent> kev;
  508. StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
  509. // Lock sticky keys.
  510. SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
  511. SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
  512. EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
  513. // Test scroll events are correctly modified in locked state.
  514. for (int i = 0; i < 5; ++i) {
  515. // Fling cancel starts scroll sequence.
  516. ev.reset(GenerateFlingScrollEvent(0, true));
  517. bool released = false;
  518. int mod_down_flags = 0;
  519. sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
  520. ev.reset(GenerateScrollEvent(10));
  521. released = false;
  522. mod_down_flags = 0;
  523. sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
  524. EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
  525. ev.reset(GenerateScrollEvent(-10));
  526. sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
  527. EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
  528. // Fling start ends scroll sequence.
  529. ev.reset(GenerateFlingScrollEvent(-10, false));
  530. sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
  531. }
  532. EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
  533. }
  534. TEST_F(StickyKeysTest, SynthesizedEvents) {
  535. // Non-native, internally generated events should be properly handled
  536. // by sticky keys.
  537. StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
  538. // Test non-native key events.
  539. std::unique_ptr<ui::KeyEvent> kev;
  540. SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
  541. EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
  542. kev.reset(GenerateSynthesizedKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_K));
  543. int mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
  544. EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
  545. EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
  546. kev.reset(GenerateSynthesizedKeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_K));
  547. mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
  548. EXPECT_FALSE(mod_down_flags & ui::EF_CONTROL_DOWN);
  549. EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
  550. // Test non-native mouse events.
  551. SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
  552. EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
  553. std::unique_ptr<ui::MouseEvent> mev;
  554. mev.reset(GenerateSynthesizedMouseClickEvent(ui::ET_MOUSE_PRESSED,
  555. gfx::Point(0, 0)));
  556. bool released = false;
  557. sticky_key.HandleMouseEvent(*mev.get(), &mod_down_flags, &released);
  558. EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
  559. EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
  560. mev.reset(GenerateSynthesizedMouseClickEvent(ui::ET_MOUSE_RELEASED,
  561. gfx::Point(0, 0)));
  562. released = false;
  563. mod_down_flags = 0;
  564. sticky_key.HandleMouseEvent(*mev.get(), &mod_down_flags, &released);
  565. EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
  566. EXPECT_TRUE(released);
  567. EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
  568. }
  569. } // namespace ash