Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(23)

Side by Side Diff: ui/aura/desktop_host_ime_unittest.cc

Issue 8576005: IME (input method editor) support for Aura, part 3 of 3: Use ui::InputMethod in ash. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: git mv desktop_host_unittest.cc desktop_host_ime_unittest.cc Created 9 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 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 "ui/aura/desktop_host.h"
6
7 #if defined(USE_X11)
8 #include <X11/keysym.h>
9 #include <X11/Xlib.h>
10 #undef Bool
11 #undef None
12 #undef Status
13 #endif
14
15 #include <cstring>
16
17 #include "base/message_loop.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "ui/aura/desktop.h"
20 #include "ui/aura/event.h"
21 #include "ui/aura/test/aura_test_base.h"
22 #include "ui/aura/test/test_window_delegate.h"
23 #include "ui/aura/test/test_windows.h"
24 #include "ui/base/ime/input_method_delegate.h"
25 #include "ui/base/ime/mock_input_method.h"
26 #include "ui/base/ime/text_input_client.h"
27 #if defined(USE_X11)
28 #include "ui/base/x/x11_util.h"
29 #endif
30 #include "ui/gfx/rect.h"
31
32 #if !defined(USE_X11)
33 #define PostKeyEvent DISABLED_PostKeyEvent
34 #define PostKeyEventNoDummyDelegate DISABLED_PostKeyEventNoDummyDelegate
35 #define PostKeyEventWithInputMethodNoDummyDelegate \
36 DISABLED_PostKeyEventWithInputMethodNoDummyDelegate
37 #endif
38
39 namespace aura {
40 namespace test {
41
42 namespace {
43
44 // A dummy WindowDelegate implementation which quits a current message loop
45 // when it receives a key event.
46 class DummyWindowDelegate : public TestWindowDelegate {
47 public:
48 virtual ~DummyWindowDelegate() {
49 }
50 virtual bool OnKeyEvent(KeyEvent* event) OVERRIDE {
51 MessageLoopForUI::current()->Quit();
52 return true;
53 }
54 };
55
56 // A dummy InputMethodDelegate implementation which quits a current message loop
57 // when it receives a native or fabricated key event.
58 class DummyInputMethodDelegate : public ui::internal::InputMethodDelegate {
59 public:
60 DummyInputMethodDelegate() {
61 ResetFlags();
62 }
63 virtual ~DummyInputMethodDelegate() {}
64
65 virtual void DispatchKeyEventPostIME(
66 const base::NativeEvent& native_key_event) OVERRIDE {
67 has_key_event_ = true;
68 MessageLoopForUI::current()->Quit();
69 }
70 virtual void DispatchFabricatedKeyEventPostIME(
71 ui::EventType type, ui::KeyboardCode key_code, int flags) OVERRIDE {
72 has_fabricated_key_event_ = true;
73 MessageLoopForUI::current()->Quit();
74 }
75
76 void ResetFlags() {
77 has_key_event_ = has_fabricated_key_event_ = false;
78 }
79
80 bool has_key_event_;
81 bool has_fabricated_key_event_;
82 };
83
84 // A dummy TextInputClient implementation which remembers if InsertChar function
85 // is called.
86 class DummyTextInputClient : public ui::TextInputClient {
87 public:
88 DummyTextInputClient() {
89 ResetFlag();
90 }
91 virtual ~DummyTextInputClient() {
92 }
93
94 virtual void SetCompositionText(
95 const ui::CompositionText& composition) OVERRIDE {}
96 virtual void ConfirmCompositionText() OVERRIDE {}
97 virtual void ClearCompositionText() OVERRIDE {}
98 virtual void InsertText(const string16& text) OVERRIDE {}
99 virtual void InsertChar(char16 ch, int flags) OVERRIDE {
100 has_char_event_ = true;
101 }
102 virtual ui::TextInputType GetTextInputType() const OVERRIDE {
103 return ui::TEXT_INPUT_TYPE_NONE;
104 }
105 virtual gfx::Rect GetCaretBounds() OVERRIDE {
106 return gfx::Rect();
107 }
108 virtual bool HasCompositionText() OVERRIDE {
109 return false;
110 }
111 virtual bool GetTextRange(ui::Range* range) OVERRIDE {
112 return false;
113 }
114 virtual bool GetCompositionTextRange(ui::Range* range) OVERRIDE {
115 return false;
116 }
117 virtual bool GetSelectionRange(ui::Range* range) OVERRIDE {
118 return false;
119 }
120 virtual bool SetSelectionRange(const ui::Range& range) OVERRIDE {
121 return false;
122 }
123 virtual bool DeleteRange(const ui::Range& range) OVERRIDE {
124 return false;
125 }
126 virtual bool GetTextFromRange(
127 const ui::Range& range, string16* text) OVERRIDE {
128 return false;
129 }
130 virtual void OnInputMethodChanged() OVERRIDE {
131 }
132 virtual bool ChangeTextDirectionAndLayoutAlignment(
133 base::i18n::TextDirection direction) OVERRIDE {
134 return false;
135 }
136
137 void ResetFlag() {
138 has_char_event_ = false;
139 }
140
141 bool has_char_event_;
142 };
143
144 // Returns a native key press or key release event.
145 // TODO(yusukes): Add function parameters like |key_name| and |modifiers| so
146 // that it could generate an event other than XK_space.
147 base::NativeEvent SynthesizeKeyEvent(bool is_press) {
148 base::NativeEvent event = base::NativeEvent();
149
150 #if defined(USE_X11)
151 event = new XEvent;
152 std::memset(event, 0, sizeof(XEvent));
153
154 Display* display = ui::GetXDisplay();
155 ::Window focused;
156 int dummy;
157 XGetInputFocus(display, &focused, &dummy);
158
159 XKeyEvent* key_event = &event->xkey;
160 key_event->display = display;
161 key_event->keycode = XKeysymToKeycode(display, XK_space);
162 key_event->root = ui::GetX11RootWindow();
163 key_event->same_screen = True;
164 key_event->send_event = False;
165 key_event->state = 0;
166 key_event->subwindow = 0L; // None;
167 key_event->time = CurrentTime;
168 key_event->type = is_press ? KeyPress : KeyRelease;
169 key_event->window = focused;
170 key_event->x = key_event->x_root = key_event->y = key_event->y_root = 1;
171 #else
172 // TODO(yusukes): Support Windows.
173 NOTIMPLEMENTED();
174 #endif
175
176 return event;
177 }
178
179 // Deletes a native event generated by SynthesizeKeyEvent() above.
180 void Delete(base::NativeEvent event) {
181 #if defined(USE_X11)
182 delete event;
183 #else
184 // TODO(yusukes): Support Windows.
185 NOTIMPLEMENTED();
186 #endif
187 }
188
189 // Enters a nested message loop.
190 void RunMessageLoop() {
191 MessageLoop* loop = MessageLoop::current();
192 const bool did_allow_task_nesting = loop->NestableTasksAllowed();
193 loop->SetNestableTasksAllowed(true);
194 aura::Desktop::GetInstance()->Run();
195 loop->SetNestableTasksAllowed(did_allow_task_nesting);
196 }
197
198 } // namespace
199
200 class DesktopHostIMETest : public AuraTestBase {
201 protected:
202 DesktopHostIMETest() : desktop_(Desktop::GetInstance()),
203 host_(desktop_->host_.get()),
204 input_method_(new ui::MockInputMethod(host_)),
205 window_(CreateTestWindowWithDelegate(
206 &window_delegate_, -1,
207 gfx::Rect(2, 3, 4, 5), NULL)) {
208 }
209
210 virtual void SetUp() OVERRIDE {
211 input_method_->Init(NULL);
212 input_method_->SetFocusedTextInputClient(&text_input_client_);
213 host_->SetInputMethod(input_method_); // pass ownership
214 AuraTestBase::SetUp();
215 }
216
217 Desktop* desktop_;
218 DesktopHost* host_;
219 ui::MockInputMethod* input_method_;
220
221 DummyInputMethodDelegate input_method_delegate_;
222 DummyTextInputClient text_input_client_;
223
224 DummyWindowDelegate window_delegate_;
225 scoped_ptr<aura::Window> window_;
226 };
227
228 // Test if DesktopHost correctly passes a key press/release event to an IME.
229 TEST_F(DesktopHostIMETest, PostKeyEvent) {
230 input_method_->set_delegate(&input_method_delegate_);
231
232 // Press space. The press event should directly go to |input_method_delegate_|
233 // and then, a 'Char' event should also be generated and passed to
234 // |text_input_client_|.
235 base::NativeEvent event = SynthesizeKeyEvent(true /* press */);
236 host_->PostNativeEvent(event);
237 // Enter a new message loop and wait for an InputMethodDelegate function to
238 // be called.
239 RunMessageLoop();
240 EXPECT_TRUE(input_method_delegate_.has_key_event_);
241 EXPECT_FALSE(input_method_delegate_.has_fabricated_key_event_);
242 EXPECT_TRUE(text_input_client_.has_char_event_);
243 input_method_delegate_.ResetFlags();
244 text_input_client_.ResetFlag();
245 Delete(event);
246
247 // Release space. A Char event should NOT be generated.
248 event = SynthesizeKeyEvent(false);
249 host_->PostNativeEvent(event);
250 RunMessageLoop();
251 EXPECT_TRUE(input_method_delegate_.has_key_event_);
252 EXPECT_FALSE(input_method_delegate_.has_fabricated_key_event_);
253 EXPECT_FALSE(text_input_client_.has_char_event_);
254 input_method_delegate_.ResetFlags();
255 text_input_client_.ResetFlag();
256 Delete(event);
257 }
258
259 // Do the same as above, but use the |host_| itself as ui::InputMethodDelegate
260 // to see if DesktopHost::DispatchKeyEventPostIME() function correctly passes
261 // a key event to the |desktop_|.
262 TEST_F(DesktopHostIMETest, PostKeyEventNoDummyDelegate) {
263 input_method_->set_delegate(host_);
264 // Call SetActiveWindow here so DummyWindowDelegate could receive a key event.
265 desktop_->SetActiveWindow(window_.get(), NULL);
266
267 // Press space. DummyWindowDelegate will quit the loop. A Char event should
268 // be generated.
269 base::NativeEvent event = SynthesizeKeyEvent(true /* press */);
270 host_->PostNativeEvent(event);
271 RunMessageLoop();
272 EXPECT_TRUE(text_input_client_.has_char_event_);
273 text_input_client_.ResetFlag();
274 Delete(event);
275
276 // Release space.
277 event = SynthesizeKeyEvent(false);
278 host_->PostNativeEvent(event);
279 RunMessageLoop();
280 EXPECT_FALSE(text_input_client_.has_char_event_);
281 text_input_client_.ResetFlag();
282 Delete(event);
283 }
284
285 // Do the same as above, but this time, |input_method_| consumes the key press
286 // event. Checks if DesktopHost::DispatchFabricatedKeyEventPostIME() function
287 // called by |input_method_| correctly passes a VK_PROCESS key event to the
288 // |desktop_|.
289 TEST_F(DesktopHostIMETest, PostKeyEventWithInputMethodNoDummyDelegate) {
290 input_method_->set_delegate(host_);
291 input_method_->ConsumeNextKey();
292 desktop_->SetActiveWindow(window_.get(), NULL);
293
294 // Press space. The press event will be consumed by the mock IME and will not
295 // be passed to the delegate. Instead, a fabricated key event (VK_PROCESSKEY)
296 // will be passed to it. Char event should not be generated this time.
297 base::NativeEvent event = SynthesizeKeyEvent(true);
298 host_->PostNativeEvent(event);
299 RunMessageLoop();
300 EXPECT_FALSE(text_input_client_.has_char_event_);
301 text_input_client_.ResetFlag();
302 Delete(event);
303
304 // Release space. A Char event should not be generated.
305 event = SynthesizeKeyEvent(false);
306 host_->PostNativeEvent(event);
307 RunMessageLoop();
308 EXPECT_FALSE(text_input_client_.has_char_event_);
309 text_input_client_.ResetFlag();
310 Delete(event);
311 }
312
313 } // namespace test
314 } // namespace aura
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698