event_rewriter_unittest.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. // Copyright 2014 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 "ui/events/event_rewriter.h"
  5. #include <list>
  6. #include <map>
  7. #include <set>
  8. #include <utility>
  9. #include "base/check_op.h"
  10. #include "base/memory/raw_ptr.h"
  11. #include "base/notreached.h"
  12. #include "testing/gtest/include/gtest/gtest.h"
  13. #include "ui/events/keycodes/dom/dom_code.h"
  14. #include "ui/events/keycodes/keyboard_codes.h"
  15. #include "ui/events/test/test_event_source.h"
  16. namespace ui {
  17. namespace {
  18. // TestEventRewriteSink is set up with a sequence of event types,
  19. // and fails if the events received via OnEventFromSource() do not match
  20. // this sequence. These expected event types are consumed on receipt.
  21. class TestEventRewriteSink : public EventSink {
  22. public:
  23. TestEventRewriteSink() {}
  24. TestEventRewriteSink(const TestEventRewriteSink&) = delete;
  25. TestEventRewriteSink& operator=(const TestEventRewriteSink&) = delete;
  26. ~TestEventRewriteSink() override { CheckAllReceived(); }
  27. void AddExpectedEvent(EventType type) { expected_events_.push_back(type); }
  28. // Test that all expected events have been received.
  29. void CheckAllReceived() { EXPECT_TRUE(expected_events_.empty()); }
  30. // EventSink override:
  31. EventDispatchDetails OnEventFromSource(Event* event) override {
  32. EXPECT_FALSE(expected_events_.empty());
  33. EXPECT_EQ(expected_events_.front(), event->type());
  34. expected_events_.pop_front();
  35. return EventDispatchDetails();
  36. }
  37. private:
  38. std::list<EventType> expected_events_;
  39. };
  40. std::unique_ptr<Event> CreateEventForType(EventType type) {
  41. switch (type) {
  42. case ET_CANCEL_MODE:
  43. return std::make_unique<CancelModeEvent>();
  44. case ET_MOUSE_DRAGGED:
  45. case ET_MOUSE_PRESSED:
  46. case ET_MOUSE_RELEASED:
  47. return std::make_unique<MouseEvent>(type, gfx::Point(), gfx::Point(),
  48. base::TimeTicks::Now(), 0, 0);
  49. case ET_KEY_PRESSED:
  50. case ET_KEY_RELEASED:
  51. return std::make_unique<KeyEvent>(type, ui::VKEY_TAB, DomCode::NONE, 0);
  52. case ET_SCROLL_FLING_CANCEL:
  53. case ET_SCROLL_FLING_START:
  54. return std::make_unique<ScrollEvent>(
  55. type, gfx::Point(), base::TimeTicks::Now(), 0, 0, 0, 0, 0, 0);
  56. default:
  57. NOTREACHED() << type;
  58. return nullptr;
  59. }
  60. }
  61. class TestEventRewriteSource : public test::TestEventSource {
  62. public:
  63. explicit TestEventRewriteSource(EventSink* sink) : TestEventSource(sink) {}
  64. EventDispatchDetails Send(EventType type) {
  65. auto event = CreateEventForType(type);
  66. return TestEventSource::Send(event.get());
  67. }
  68. };
  69. // This EventRewriter always returns the same status, and if rewriting, the
  70. // same event type; it is used to test simple rewriting, and rewriter addition,
  71. // removal, and sequencing. Consequently EVENT_REWRITE_DISPATCH_ANOTHER is not
  72. // supported here (calls to NextDispatchEvent() would continue indefinitely).
  73. class TestConstantEventRewriterOld : public EventRewriter {
  74. public:
  75. TestConstantEventRewriterOld(EventRewriteStatus status, EventType type)
  76. : status_(status), type_(type) {
  77. CHECK_NE(EVENT_REWRITE_DISPATCH_ANOTHER, status);
  78. }
  79. EventRewriteStatus RewriteEvent(
  80. const Event& event,
  81. std::unique_ptr<Event>* rewritten_event) override {
  82. if (status_ == EVENT_REWRITE_REWRITTEN)
  83. *rewritten_event = CreateEventForType(type_);
  84. return status_;
  85. }
  86. EventRewriteStatus NextDispatchEvent(
  87. const Event& last_event,
  88. std::unique_ptr<Event>* new_event) override {
  89. NOTREACHED();
  90. return status_;
  91. }
  92. private:
  93. EventRewriteStatus status_;
  94. EventType type_;
  95. };
  96. // This EventRewriter runs a simple state machine; it is used to test
  97. // EVENT_REWRITE_DISPATCH_ANOTHER.
  98. class TestStateMachineEventRewriterOld : public EventRewriter {
  99. public:
  100. TestStateMachineEventRewriterOld()
  101. : last_rewritten_event_(nullptr), state_(0) {}
  102. void AddRule(int from_state,
  103. EventType from_type,
  104. int to_state,
  105. EventType to_type,
  106. EventRewriteStatus to_status) {
  107. RewriteResult r = {to_state, to_type, to_status};
  108. rules_.emplace(RewriteCase(from_state, from_type), r);
  109. }
  110. EventRewriteStatus RewriteEvent(
  111. const Event& event,
  112. std::unique_ptr<Event>* rewritten_event) override {
  113. auto find = rules_.find(RewriteCase(state_, event.type()));
  114. if (find == rules_.end())
  115. return EVENT_REWRITE_CONTINUE;
  116. if ((find->second.status == EVENT_REWRITE_REWRITTEN) ||
  117. (find->second.status == EVENT_REWRITE_DISPATCH_ANOTHER)) {
  118. *rewritten_event = CreateEventForType(find->second.type);
  119. last_rewritten_event_ = rewritten_event->get();
  120. } else {
  121. last_rewritten_event_ = nullptr;
  122. }
  123. state_ = find->second.state;
  124. return find->second.status;
  125. }
  126. EventRewriteStatus NextDispatchEvent(
  127. const Event& last_event,
  128. std::unique_ptr<Event>* new_event) override {
  129. EXPECT_TRUE(last_rewritten_event_);
  130. EXPECT_EQ(last_rewritten_event_, &last_event);
  131. EXPECT_FALSE(new_event->get() && new_event->get() == &last_event);
  132. return RewriteEvent(last_event, new_event);
  133. }
  134. private:
  135. typedef std::pair<int, EventType> RewriteCase;
  136. struct RewriteResult {
  137. int state;
  138. EventType type;
  139. EventRewriteStatus status;
  140. };
  141. typedef std::map<RewriteCase, RewriteResult> RewriteRules;
  142. RewriteRules rules_;
  143. raw_ptr<Event> last_rewritten_event_;
  144. int state_;
  145. };
  146. // This EventRewriter always accepts the original event. It is used to test
  147. // simple rewriting, and rewriter addition, removal, and sequencing.
  148. class TestAlwaysAcceptEventRewriter : public EventRewriter {
  149. public:
  150. TestAlwaysAcceptEventRewriter() {}
  151. EventDispatchDetails RewriteEvent(const Event& event,
  152. const Continuation continuation) override {
  153. return SendEvent(continuation, &event);
  154. }
  155. };
  156. // This EventRewriter always rewrites with the same event type; it is used
  157. // to test simple rewriting, and rewriter addition, removal, and sequencing.
  158. class TestConstantEventRewriter : public EventRewriter {
  159. public:
  160. explicit TestConstantEventRewriter(EventType type) : type_(type) {}
  161. EventDispatchDetails RewriteEvent(const Event& event,
  162. const Continuation continuation) override {
  163. std::unique_ptr<Event> replacement_event = CreateEventForType(type_);
  164. return SendEventFinally(continuation, replacement_event.get());
  165. }
  166. private:
  167. EventType type_;
  168. };
  169. // This EventRewriter runs a simple state machine; it is used to test
  170. // EVENT_REWRITE_DISPATCH_ANOTHER.
  171. class TestStateMachineEventRewriter : public EventRewriter {
  172. public:
  173. enum RewriteAction { ACCEPT, DISCARD, REPLACE };
  174. enum StateAction { RETURN, PROCEED };
  175. TestStateMachineEventRewriter() : state_(0) {}
  176. void AddRule(int from_state,
  177. EventType from_type,
  178. int to_state,
  179. EventType to_type,
  180. RewriteAction rewrite_action,
  181. StateAction state_action) {
  182. RewriteResult r = {to_state, to_type, rewrite_action, state_action};
  183. rules_.insert({RewriteCase(from_state, from_type), r});
  184. }
  185. EventDispatchDetails RewriteEvent(const Event& event,
  186. const Continuation continuation) override {
  187. for (;;) {
  188. RewriteRules::iterator find =
  189. rules_.find(RewriteCase(state_, event.type()));
  190. if (find == rules_.end())
  191. return SendEvent(continuation, &event);
  192. state_ = find->second.state;
  193. EventDispatchDetails details;
  194. switch (find->second.rewrite_action) {
  195. case ACCEPT:
  196. details = SendEvent(continuation, &event);
  197. break;
  198. case DISCARD:
  199. break;
  200. case REPLACE:
  201. details = SendEventFinally(
  202. continuation, CreateEventForType(find->second.type).get());
  203. break;
  204. }
  205. if (details.dispatcher_destroyed || find->second.state_action == RETURN)
  206. return details;
  207. }
  208. NOTREACHED();
  209. }
  210. private:
  211. typedef std::pair<int, EventType> RewriteCase;
  212. struct RewriteResult {
  213. int state;
  214. EventType type;
  215. RewriteAction rewrite_action;
  216. StateAction state_action;
  217. };
  218. typedef std::map<RewriteCase, RewriteResult> RewriteRules;
  219. RewriteRules rules_;
  220. int state_;
  221. };
  222. } // namespace
  223. TEST(EventRewriterTest, EventRewritingOld) {
  224. // TestEventRewriter r0 always rewrites events to ET_CANCEL_MODE;
  225. // it is placed at the beginning of the chain and later removed,
  226. // to verify that rewriter removal works.
  227. TestConstantEventRewriterOld r0(EVENT_REWRITE_REWRITTEN, ET_CANCEL_MODE);
  228. // TestEventRewriter r1 always returns EVENT_REWRITE_CONTINUE;
  229. // it is at the beginning of the chain (once r0 is removed)
  230. // to verify that a later rewriter sees the events.
  231. TestConstantEventRewriterOld r1(EVENT_REWRITE_CONTINUE, ET_UNKNOWN);
  232. // TestEventRewriter r2 has a state machine, primarily to test
  233. // |EVENT_REWRITE_DISPATCH_ANOTHER|.
  234. TestStateMachineEventRewriterOld r2;
  235. // TestEventRewriter r3 always rewrites events to ET_CANCEL_MODE;
  236. // it is placed at the end of the chain to verify that previously
  237. // rewritten events are not passed further down the chain.
  238. TestConstantEventRewriterOld r3(EVENT_REWRITE_REWRITTEN, ET_CANCEL_MODE);
  239. TestEventRewriteSink p;
  240. TestEventRewriteSource s(&p);
  241. s.AddEventRewriter(&r0);
  242. s.AddEventRewriter(&r1);
  243. s.AddEventRewriter(&r2);
  244. // These events should be rewritten by r0 to ET_CANCEL_MODE.
  245. p.AddExpectedEvent(ET_CANCEL_MODE);
  246. s.Send(ET_MOUSE_DRAGGED);
  247. p.AddExpectedEvent(ET_CANCEL_MODE);
  248. s.Send(ET_MOUSE_PRESSED);
  249. p.CheckAllReceived();
  250. // Remove r0, and verify that it's gone and that events make it through.
  251. // - r0 is removed, so the resulting event should NOT be ET_CANCEL_MODE.
  252. // - r2 should rewrite ET_SCROLL_FLING_START to ET_SCROLL_FLING_CANCEL,
  253. // and skip subsequent rewriters, so the resulting event should be
  254. // ET_SCROLL_FLING_CANCEL.
  255. // - r3 should be skipped after r2 returns, so the resulting event
  256. // should NOT be ET_CANCEL_MODE.
  257. s.AddEventRewriter(&r3);
  258. s.RemoveEventRewriter(&r0);
  259. // clang-format off
  260. r2.AddRule(0, ET_SCROLL_FLING_START,
  261. 0, ET_SCROLL_FLING_CANCEL, EVENT_REWRITE_REWRITTEN);
  262. // clang-format on
  263. p.AddExpectedEvent(ET_SCROLL_FLING_CANCEL);
  264. s.Send(ET_SCROLL_FLING_START);
  265. p.CheckAllReceived();
  266. s.RemoveEventRewriter(&r3);
  267. // Verify EVENT_REWRITE_DISPATCH_ANOTHER using a state machine
  268. // (that happens to be analogous to sticky keys).
  269. // clang-format off
  270. r2.AddRule(0, ET_KEY_PRESSED,
  271. 1, ET_KEY_PRESSED, EVENT_REWRITE_CONTINUE);
  272. r2.AddRule(1, ET_MOUSE_PRESSED,
  273. 0, ET_MOUSE_PRESSED, EVENT_REWRITE_CONTINUE);
  274. r2.AddRule(1, ET_KEY_RELEASED,
  275. 2, ET_KEY_RELEASED, EVENT_REWRITE_DISCARD);
  276. r2.AddRule(2, ET_MOUSE_RELEASED,
  277. 3, ET_MOUSE_RELEASED, EVENT_REWRITE_DISPATCH_ANOTHER);
  278. r2.AddRule(3, ET_MOUSE_RELEASED,
  279. 0, ET_KEY_RELEASED, EVENT_REWRITE_REWRITTEN);
  280. // clang-format on
  281. p.AddExpectedEvent(ET_KEY_PRESSED);
  282. s.Send(ET_KEY_PRESSED);
  283. s.Send(ET_KEY_RELEASED);
  284. p.AddExpectedEvent(ET_MOUSE_PRESSED);
  285. s.Send(ET_MOUSE_PRESSED);
  286. // Removing rewriter r1 shouldn't affect r2.
  287. s.RemoveEventRewriter(&r1);
  288. // Continue with the state-based rewriting.
  289. p.AddExpectedEvent(ET_MOUSE_RELEASED);
  290. p.AddExpectedEvent(ET_KEY_RELEASED);
  291. s.Send(ET_MOUSE_RELEASED);
  292. p.CheckAllReceived();
  293. }
  294. TEST(EventRewriterTest, EventRewriting) {
  295. // TestEventRewriter r0 always rewrites events to ET_CANCEL_MODE;
  296. // it is placed at the beginning of the chain and later removed,
  297. // to verify that rewriter removal works.
  298. TestConstantEventRewriter r0(ET_CANCEL_MODE);
  299. // TestEventRewriter r1 always returns EVENT_REWRITE_CONTINUE;
  300. // it is at the beginning of the chain (once r0 is removed)
  301. // to verify that a later rewriter sees the events.
  302. TestAlwaysAcceptEventRewriter r1;
  303. // TestEventRewriter r2 has a state machine, primarily to test
  304. // |EVENT_REWRITE_DISPATCH_ANOTHER|.
  305. TestStateMachineEventRewriter r2;
  306. // TestEventRewriter r3 always rewrites events to ET_CANCEL_MODE;
  307. // it is placed at the end of the chain to verify that previously
  308. // rewritten events are not passed further down the chain.
  309. TestConstantEventRewriter r3(ET_CANCEL_MODE);
  310. TestEventRewriteSink p;
  311. TestEventRewriteSource s(&p);
  312. s.AddEventRewriter(&r0);
  313. s.AddEventRewriter(&r1);
  314. s.AddEventRewriter(&r2);
  315. // These events should be rewritten by r0 to ET_CANCEL_MODE.
  316. p.AddExpectedEvent(ET_CANCEL_MODE);
  317. s.Send(ET_MOUSE_DRAGGED);
  318. p.AddExpectedEvent(ET_CANCEL_MODE);
  319. s.Send(ET_MOUSE_PRESSED);
  320. p.CheckAllReceived();
  321. // Remove r0, and verify that it's gone and that events make it through.
  322. // - r0 is removed, so the resulting event should NOT be ET_CANCEL_MODE.
  323. // - r2 should rewrite ET_SCROLL_FLING_START to ET_SCROLL_FLING_CANCEL,
  324. // and skip subsequent rewriters, so the resulting event should be
  325. // ET_SCROLL_FLING_CANCEL.
  326. // - r3 should be skipped after r2 returns, so the resulting event
  327. // should NOT be ET_CANCEL_MODE.
  328. s.AddEventRewriter(&r3);
  329. s.RemoveEventRewriter(&r0);
  330. r2.AddRule(0, ET_SCROLL_FLING_START, 0, ET_SCROLL_FLING_CANCEL,
  331. TestStateMachineEventRewriter::REPLACE,
  332. TestStateMachineEventRewriter::RETURN);
  333. p.AddExpectedEvent(ET_SCROLL_FLING_CANCEL);
  334. s.Send(ET_SCROLL_FLING_START);
  335. p.CheckAllReceived();
  336. s.RemoveEventRewriter(&r3);
  337. // Verify replacing an event with multiple events using a state machine
  338. // (that happens to be analogous to sticky keys).
  339. r2.AddRule(0, ET_KEY_PRESSED, 1, ET_UNKNOWN,
  340. TestStateMachineEventRewriter::ACCEPT,
  341. TestStateMachineEventRewriter::RETURN);
  342. r2.AddRule(1, ET_MOUSE_PRESSED, 0, ET_UNKNOWN,
  343. TestStateMachineEventRewriter::ACCEPT,
  344. TestStateMachineEventRewriter::RETURN);
  345. r2.AddRule(1, ET_KEY_RELEASED, 2, ET_UNKNOWN,
  346. TestStateMachineEventRewriter::DISCARD,
  347. TestStateMachineEventRewriter::RETURN);
  348. r2.AddRule(2, ET_MOUSE_RELEASED, 3, ET_MOUSE_RELEASED,
  349. TestStateMachineEventRewriter::REPLACE,
  350. TestStateMachineEventRewriter::PROCEED);
  351. r2.AddRule(3, ET_MOUSE_RELEASED, 0, ET_KEY_RELEASED,
  352. TestStateMachineEventRewriter::REPLACE,
  353. TestStateMachineEventRewriter::RETURN);
  354. p.AddExpectedEvent(ET_KEY_PRESSED);
  355. s.Send(ET_KEY_PRESSED); // state 0 ET_KEY_PRESSED -> 1 ACCEPT ET_KEY_PRESSED
  356. s.Send(ET_KEY_RELEASED); // state 1 ET_KEY_RELEASED -> 2 DISCARD
  357. p.AddExpectedEvent(ET_MOUSE_PRESSED);
  358. s.Send(ET_MOUSE_PRESSED); // no matching rule; pass event through.
  359. // Removing rewriter r1 shouldn't affect r2.
  360. s.RemoveEventRewriter(&r1);
  361. // Continue with the state-based rewriting.
  362. p.AddExpectedEvent(ET_MOUSE_RELEASED);
  363. p.AddExpectedEvent(ET_KEY_RELEASED);
  364. s.Send(
  365. ET_MOUSE_RELEASED); // 2 ET_MOUSE_RELEASED -> 3 PROCEED ET_MOUSE_RELEASED
  366. // 3 ET_MOUSE_RELEASED -> 0 REPLACE ET_KEY_RELEASED
  367. p.CheckAllReceived();
  368. }
  369. } // namespace ui