OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2016 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 <stdint.h> | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/macros.h" | |
9 #include "base/message_loop/message_loop.h" | |
10 #include "base/run_loop.h" | |
11 #include "base/strings/utf_string_conversions.h" | |
12 #include "chrome/browser/ui/views/ime_driver/input_method_bridge_chromeos.h" | |
13 #include "content/public/test/test_browser_thread_bundle.h" | |
14 #include "mojo/public/cpp/bindings/binding.h" | |
15 #include "testing/gtest/include/gtest/gtest.h" | |
16 #include "ui/base/ime/ime_bridge.h" | |
17 #include "ui/events/event.h" | |
18 #include "ui/events/event_constants.h" | |
19 #include "ui/events/event_utils.h" | |
20 #include "ui/events/keycodes/dom/dom_code.h" | |
21 #include "ui/events/keycodes/dom/dom_key.h" | |
22 #include "ui/events/keycodes/keyboard_code_conversion.h" | |
23 #include "ui/events/keycodes/keyboard_codes.h" | |
24 | |
25 enum CompositionEventType { SET, CONFIRM, CLEAR, INSERT_TEXT, INSERT_CHAR }; | |
sky
2016/12/12 02:16:21
enum class.
Hadi
2016/12/12 16:04:58
Done.
| |
26 | |
27 struct CompositionEvent { | |
28 CompositionEventType type; | |
29 base::string16 text_data; | |
30 base::char16 char_data; | |
31 }; | |
32 | |
33 class TestTextInputClient : public ui::mojom::TextInputClient { | |
34 public: | |
35 explicit TestTextInputClient(ui::mojom::TextInputClientRequest request) | |
36 : binding_(this, std::move(request)) {} | |
37 | |
38 CompositionEvent WaitUntilCompositionEvent() { | |
39 if (!receieved_event_.has_value()) { | |
40 run_loop_.reset(new base::RunLoop); | |
sky
2016/12/12 02:16:21
Again, MakeUnique where possible.
Hadi
2016/12/12 16:04:58
Done.
Couple of "new"'s are still in ime_driver_m
| |
41 run_loop_->Run(); | |
42 run_loop_.reset(); | |
43 } | |
44 CompositionEvent result = receieved_event_.value(); | |
45 receieved_event_.reset(); | |
46 return result; | |
47 } | |
48 | |
49 private: | |
50 void SetCompositionText(const ui::CompositionText& composition) override { | |
51 CompositionEvent ev = {CompositionEventType::SET, composition.text, 0}; | |
52 receieved_event_ = ev; | |
53 if (run_loop_) | |
54 run_loop_->Quit(); | |
55 } | |
56 void ConfirmCompositionText() override { | |
57 CompositionEvent ev = {CompositionEventType::CONFIRM, base::string16(), 0}; | |
58 receieved_event_ = ev; | |
59 if (run_loop_) | |
60 run_loop_->Quit(); | |
61 } | |
62 void ClearCompositionText() override { | |
63 CompositionEvent ev = {CompositionEventType::CLEAR, base::string16(), 0}; | |
64 receieved_event_ = ev; | |
65 if (run_loop_) | |
66 run_loop_->Quit(); | |
67 } | |
68 void InsertText(const std::string& text) override { | |
69 CompositionEvent ev = {CompositionEventType::INSERT_TEXT, | |
70 base::UTF8ToUTF16(text), 0}; | |
71 receieved_event_ = ev; | |
72 if (run_loop_) | |
73 run_loop_->Quit(); | |
74 } | |
75 void InsertChar(std::unique_ptr<ui::Event> event) override { | |
76 ASSERT_TRUE(event->IsKeyEvent()); | |
77 CompositionEvent ev = {CompositionEventType::INSERT_CHAR, base::string16(), | |
78 event->AsKeyEvent()->GetCharacter()}; | |
79 receieved_event_ = ev; | |
80 if (run_loop_) | |
81 run_loop_->Quit(); | |
82 } | |
83 | |
84 mojo::Binding<ui::mojom::TextInputClient> binding_; | |
85 std::unique_ptr<base::RunLoop> run_loop_; | |
86 base::Optional<CompositionEvent> receieved_event_; | |
87 | |
88 DISALLOW_COPY_AND_ASSIGN(TestTextInputClient); | |
89 }; | |
90 | |
91 class InputMethodBridgeChromeOSTest : public testing::Test { | |
92 public: | |
93 InputMethodBridgeChromeOSTest() | |
94 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {} | |
95 ~InputMethodBridgeChromeOSTest() override {} | |
96 | |
97 void SetUp() override { | |
98 ui::IMEBridge::Initialize(); | |
99 | |
100 ui::mojom::TextInputClientPtr client_ptr; | |
101 client_.reset(new TestTextInputClient(GetProxy(&client_ptr))); | |
102 input_method_.reset(new InputMethodBridge(std::move(client_ptr))); | |
103 } | |
104 | |
105 bool ProcessKeyEvent(std::unique_ptr<ui::Event> event) { | |
106 handled_.reset(); | |
107 | |
108 input_method_->ProcessKeyEvent( | |
109 std::move(event), | |
110 base::Bind(&InputMethodBridgeChromeOSTest::ProcessKeyEventCallback, | |
111 base::Unretained(this))); | |
112 | |
113 if (!handled_.has_value()) { | |
114 run_loop_.reset(new base::RunLoop); | |
115 run_loop_->Run(); | |
116 run_loop_.reset(); | |
117 } | |
118 | |
119 return handled_.value(); | |
120 } | |
121 | |
122 std::unique_ptr<ui::Event> UnicodeKeyPress(ui::KeyboardCode vkey, | |
123 ui::DomCode code, | |
124 int flags, | |
125 base::char16 character) const { | |
126 return base::MakeUnique<ui::KeyEvent>(ui::ET_KEY_PRESSED, vkey, code, flags, | |
127 ui::DomKey::FromCharacter(character), | |
128 ui::EventTimeForNow()); | |
129 } | |
130 | |
131 protected: | |
132 void ProcessKeyEventCallback(bool handled) { | |
133 handled_ = handled; | |
134 if (run_loop_) | |
135 run_loop_->Quit(); | |
136 } | |
137 | |
138 content::TestBrowserThreadBundle thread_bundle_; | |
139 std::unique_ptr<TestTextInputClient> client_; | |
140 std::unique_ptr<InputMethodBridge> input_method_; | |
141 std::unique_ptr<base::RunLoop> run_loop_; | |
142 base::Optional<bool> handled_; | |
143 | |
144 DISALLOW_COPY_AND_ASSIGN(InputMethodBridgeChromeOSTest); | |
145 }; | |
146 | |
147 // Tests if hexadecimal composition provided by ui::CharacterComposer works | |
148 // correctly. ui::CharacterComposer is tried if no input method extensions | |
149 // have been registered yet. | |
150 TEST_F(InputMethodBridgeChromeOSTest, HexadecimalComposition) { | |
151 struct { | |
152 ui::KeyboardCode vkey; | |
153 ui::DomCode code; | |
154 int flags; | |
155 base::char16 character; | |
156 std::string composition_text; | |
157 } kTestSequence[] = { | |
158 {ui::VKEY_U, ui::DomCode::US_U, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN, | |
159 'U', "u"}, | |
160 {ui::VKEY_3, ui::DomCode::DIGIT3, 0, '3', "u3"}, | |
161 {ui::VKEY_0, ui::DomCode::DIGIT0, 0, '0', "u30"}, | |
162 {ui::VKEY_4, ui::DomCode::DIGIT4, 0, '4', "u304"}, | |
163 {ui::VKEY_2, ui::DomCode::DIGIT2, 0, '2', "u3042"}, | |
164 }; | |
165 | |
166 // Send the Ctrl-Shift-U,3,4,0,2 sequence. | |
167 for (size_t i = 0; i < arraysize(kTestSequence); i++) { | |
168 EXPECT_TRUE(ProcessKeyEvent( | |
169 UnicodeKeyPress(kTestSequence[i].vkey, kTestSequence[i].code, | |
170 kTestSequence[i].flags, kTestSequence[i].character))); | |
171 CompositionEvent ev = client_->WaitUntilCompositionEvent(); | |
172 EXPECT_EQ(CompositionEventType::SET, ev.type); | |
173 EXPECT_EQ(base::UTF8ToUTF16(kTestSequence[i].composition_text), | |
174 ev.text_data); | |
175 } | |
176 | |
177 // Press the return key and verify that the composition text was converted | |
178 // to the desired text. | |
179 EXPECT_TRUE(ProcessKeyEvent( | |
180 UnicodeKeyPress(ui::VKEY_RETURN, ui::DomCode::ENTER, 0, '\r'))); | |
181 CompositionEvent ev = client_->WaitUntilCompositionEvent(); | |
182 EXPECT_EQ(CompositionEventType::INSERT_TEXT, ev.type); | |
183 EXPECT_EQ(base::string16(1, 0x3042), ev.text_data); | |
184 } | |
185 | |
186 // Test that Ctrl-C, Ctrl-X, and Ctrl-V are not handled. | |
187 TEST_F(InputMethodBridgeChromeOSTest, ClipboardAccelerators) { | |
188 EXPECT_FALSE(ProcessKeyEvent(UnicodeKeyPress(ui::VKEY_C, ui::DomCode::US_C, | |
189 ui::EF_CONTROL_DOWN, 'C'))); | |
190 EXPECT_FALSE(ProcessKeyEvent(UnicodeKeyPress(ui::VKEY_X, ui::DomCode::US_X, | |
191 ui::EF_CONTROL_DOWN, 'X'))); | |
192 EXPECT_FALSE(ProcessKeyEvent(UnicodeKeyPress(ui::VKEY_V, ui::DomCode::US_V, | |
193 ui::EF_CONTROL_DOWN, 'V'))); | |
194 } | |
OLD | NEW |