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 "ui/base/ime/remote_input_method_win.h"
6
7 #include <InputScope.h>
8
9 #include <vector>
10
11 #include "base/memory/scoped_ptr.h"
12 #include "base/scoped_observer.h"
13 #include "base/strings/string16.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "ui/base/ime/composition_text.h"
16 #include "ui/base/ime/dummy_text_input_client.h"
17 #include "ui/base/ime/input_method.h"
18 #include "ui/base/ime/input_method_delegate.h"
19 #include "ui/base/ime/input_method_observer.h"
20 #include "ui/base/ime/remote_input_method_delegate_win.h"
21 #include "ui/events/event.h"
22
23 namespace ui {
24 namespace {
25
26 class MockTextInputClient : public DummyTextInputClient {
27 public:
MockTextInputClient()28 MockTextInputClient()
29 : text_input_type_(TEXT_INPUT_TYPE_NONE),
30 text_input_mode_(TEXT_INPUT_MODE_DEFAULT),
31 call_count_set_composition_text_(0),
32 call_count_insert_char_(0),
33 call_count_insert_text_(0) {
34 }
35
call_count_set_composition_text() const36 size_t call_count_set_composition_text() const {
37 return call_count_set_composition_text_;
38 }
inserted_text() const39 const base::string16& inserted_text() const {
40 return inserted_text_;
41 }
call_count_insert_char() const42 size_t call_count_insert_char() const {
43 return call_count_insert_char_;
44 }
call_count_insert_text() const45 size_t call_count_insert_text() const {
46 return call_count_insert_text_;
47 }
Reset()48 void Reset() {
49 text_input_type_ = TEXT_INPUT_TYPE_NONE;
50 text_input_mode_ = TEXT_INPUT_MODE_DEFAULT;
51 call_count_set_composition_text_ = 0;
52 inserted_text_.clear();
53 call_count_insert_char_ = 0;
54 call_count_insert_text_ = 0;
55 caret_bounds_ = gfx::Rect();
56 composition_character_bounds_.clear();
57 }
set_text_input_type(ui::TextInputType type)58 void set_text_input_type(ui::TextInputType type) {
59 text_input_type_ = type;
60 }
set_text_input_mode(ui::TextInputMode mode)61 void set_text_input_mode(ui::TextInputMode mode) {
62 text_input_mode_ = mode;
63 }
set_caret_bounds(const gfx::Rect & caret_bounds)64 void set_caret_bounds(const gfx::Rect& caret_bounds) {
65 caret_bounds_ = caret_bounds;
66 }
set_composition_character_bounds(const std::vector<gfx::Rect> & composition_character_bounds)67 void set_composition_character_bounds(
68 const std::vector<gfx::Rect>& composition_character_bounds) {
69 composition_character_bounds_ = composition_character_bounds;
70 }
71
72 private:
73 // Overriden from DummyTextInputClient.
SetCompositionText(const ui::CompositionText & composition)74 virtual void SetCompositionText(
75 const ui::CompositionText& composition) OVERRIDE {
76 ++call_count_set_composition_text_;
77 }
InsertChar(char16 ch,int flags)78 virtual void InsertChar(char16 ch, int flags) OVERRIDE{
79 inserted_text_.append(1, ch);
80 ++call_count_insert_char_;
81 }
InsertText(const string16 & text)82 virtual void InsertText(const string16& text) OVERRIDE{
83 inserted_text_.append(text);
84 ++call_count_insert_text_;
85 }
GetTextInputType() const86 virtual ui::TextInputType GetTextInputType() const OVERRIDE {
87 return text_input_type_;
88 }
GetTextInputMode() const89 virtual ui::TextInputMode GetTextInputMode() const OVERRIDE {
90 return text_input_mode_;
91 }
GetCaretBounds() const92 virtual gfx::Rect GetCaretBounds() const {
93 return caret_bounds_;
94 }
GetCompositionCharacterBounds(uint32 index,gfx::Rect * rect) const95 virtual bool GetCompositionCharacterBounds(uint32 index,
96 gfx::Rect* rect) const OVERRIDE {
97 if (!rect || composition_character_bounds_.size() <= index)
98 return false;
99 *rect = composition_character_bounds_[index];
100 return true;
101 }
HasCompositionText() const102 virtual bool HasCompositionText() const OVERRIDE {
103 return !composition_character_bounds_.empty();
104 }
105
106 ui::TextInputType text_input_type_;
107 ui::TextInputMode text_input_mode_;
108 gfx::Rect caret_bounds_;
109 std::vector<gfx::Rect> composition_character_bounds_;
110 base::string16 inserted_text_;
111 size_t call_count_set_composition_text_;
112 size_t call_count_insert_char_;
113 size_t call_count_insert_text_;
114 DISALLOW_COPY_AND_ASSIGN(MockTextInputClient);
115 };
116
117 class MockInputMethodDelegate : public internal::InputMethodDelegate {
118 public:
MockInputMethodDelegate()119 MockInputMethodDelegate() {}
120
fabricated_key_events() const121 const std::vector<ui::KeyboardCode>& fabricated_key_events() const {
122 return fabricated_key_events_;
123 }
Reset()124 void Reset() {
125 fabricated_key_events_.clear();
126 }
127
128 private:
DispatchKeyEventPostIME(const base::NativeEvent & native_key_event)129 virtual bool DispatchKeyEventPostIME(
130 const base::NativeEvent& native_key_event) OVERRIDE {
131 EXPECT_TRUE(false) << "Not reach here";
132 return true;
133 }
DispatchFabricatedKeyEventPostIME(ui::EventType type,ui::KeyboardCode key_code,int flags)134 virtual bool DispatchFabricatedKeyEventPostIME(ui::EventType type,
135 ui::KeyboardCode key_code,
136 int flags) OVERRIDE {
137 fabricated_key_events_.push_back(key_code);
138 return true;
139 }
140
141 std::vector<ui::KeyboardCode> fabricated_key_events_;
142 DISALLOW_COPY_AND_ASSIGN(MockInputMethodDelegate);
143 };
144
145 class MockRemoteInputMethodDelegateWin
146 : public internal::RemoteInputMethodDelegateWin {
147 public:
MockRemoteInputMethodDelegateWin()148 MockRemoteInputMethodDelegateWin()
149 : cancel_composition_called_(false),
150 text_input_client_updated_called_(false) {
151 }
152
cancel_composition_called() const153 bool cancel_composition_called() const {
154 return cancel_composition_called_;
155 }
text_input_client_updated_called() const156 bool text_input_client_updated_called() const {
157 return text_input_client_updated_called_;
158 }
input_scopes() const159 const std::vector<int32>& input_scopes() const {
160 return input_scopes_;
161 }
composition_character_bounds() const162 const std::vector<gfx::Rect>& composition_character_bounds() const {
163 return composition_character_bounds_;
164 }
Reset()165 void Reset() {
166 cancel_composition_called_ = false;
167 text_input_client_updated_called_ = false;
168 input_scopes_.clear();
169 composition_character_bounds_.clear();
170 }
171
172 private:
CancelComposition()173 virtual void CancelComposition() OVERRIDE {
174 cancel_composition_called_ = true;
175 }
176
OnTextInputClientUpdated(const std::vector<int32> & input_scopes,const std::vector<gfx::Rect> & composition_character_bounds)177 virtual void OnTextInputClientUpdated(
178 const std::vector<int32>& input_scopes,
179 const std::vector<gfx::Rect>& composition_character_bounds) OVERRIDE {
180 text_input_client_updated_called_ = true;
181 input_scopes_ = input_scopes;
182 composition_character_bounds_ = composition_character_bounds;
183 }
184
185 bool cancel_composition_called_;
186 bool text_input_client_updated_called_;
187 std::vector<int32> input_scopes_;
188 std::vector<gfx::Rect> composition_character_bounds_;
189 DISALLOW_COPY_AND_ASSIGN(MockRemoteInputMethodDelegateWin);
190 };
191
192 class MockInputMethodObserver : public InputMethodObserver {
193 public:
MockInputMethodObserver()194 MockInputMethodObserver()
195 : on_text_input_state_changed_(0),
196 on_input_method_destroyed_changed_(0) {
197 }
~MockInputMethodObserver()198 virtual ~MockInputMethodObserver() {
199 }
Reset()200 void Reset() {
201 on_text_input_state_changed_ = 0;
202 on_input_method_destroyed_changed_ = 0;
203 }
on_text_input_state_changed() const204 size_t on_text_input_state_changed() const {
205 return on_text_input_state_changed_;
206 }
on_input_method_destroyed_changed() const207 size_t on_input_method_destroyed_changed() const {
208 return on_input_method_destroyed_changed_;
209 }
210
211 private:
212 // Overriden from InputMethodObserver.
OnTextInputTypeChanged(const TextInputClient * client)213 virtual void OnTextInputTypeChanged(const TextInputClient* client) OVERRIDE {
214 }
OnFocus()215 virtual void OnFocus() OVERRIDE {
216 }
OnBlur()217 virtual void OnBlur() OVERRIDE {
218 }
OnCaretBoundsChanged(const TextInputClient * client)219 virtual void OnCaretBoundsChanged(const TextInputClient* client) OVERRIDE {
220 }
OnTextInputStateChanged(const TextInputClient * client)221 virtual void OnTextInputStateChanged(const TextInputClient* client) OVERRIDE {
222 ++on_text_input_state_changed_;
223 }
OnInputMethodDestroyed(const InputMethod * client)224 virtual void OnInputMethodDestroyed(const InputMethod* client) OVERRIDE {
225 ++on_input_method_destroyed_changed_;
226 }
227
228 size_t on_text_input_state_changed_;
229 size_t on_input_method_destroyed_changed_;
230 DISALLOW_COPY_AND_ASSIGN(MockInputMethodObserver);
231 };
232
233 typedef ScopedObserver<InputMethod, InputMethodObserver>
234 InputMethodScopedObserver;
235
TEST(RemoteInputMethodWinTest,RemoteInputMethodPrivateWin)236 TEST(RemoteInputMethodWinTest, RemoteInputMethodPrivateWin) {
237 InputMethod* other_ptr = static_cast<InputMethod*>(NULL) + 1;
238
239 // Use typed NULL to make EXPECT_NE happy until nullptr becomes available.
240 RemoteInputMethodPrivateWin* kNull =
241 static_cast<RemoteInputMethodPrivateWin*>(NULL);
242 EXPECT_EQ(kNull, RemoteInputMethodPrivateWin::Get(other_ptr));
243
244 MockInputMethodDelegate delegate_;
245 scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
246 EXPECT_NE(kNull, RemoteInputMethodPrivateWin::Get(input_method.get()));
247
248 InputMethod* dangling_ptr = input_method.get();
249 input_method.reset(NULL);
250 EXPECT_EQ(kNull, RemoteInputMethodPrivateWin::Get(dangling_ptr));
251 }
252
TEST(RemoteInputMethodWinTest,OnInputSourceChanged)253 TEST(RemoteInputMethodWinTest, OnInputSourceChanged) {
254 MockInputMethodDelegate delegate_;
255 scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
256 RemoteInputMethodPrivateWin* private_ptr =
257 RemoteInputMethodPrivateWin::Get(input_method.get());
258 ASSERT_TRUE(private_ptr != NULL);
259
260 private_ptr->OnInputSourceChanged(
261 MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN), true);
262 EXPECT_EQ("ja-JP", input_method->GetInputLocale());
263 EXPECT_EQ(base::i18n::LEFT_TO_RIGHT,
264 input_method->GetInputTextDirection());
265
266 private_ptr->OnInputSourceChanged(
267 MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_QATAR), true);
268 EXPECT_EQ("ar-QA", input_method->GetInputLocale());
269 EXPECT_EQ(base::i18n::RIGHT_TO_LEFT,
270 input_method->GetInputTextDirection());
271 }
272
TEST(RemoteInputMethodWinTest,OnCandidatePopupChanged)273 TEST(RemoteInputMethodWinTest, OnCandidatePopupChanged) {
274 MockInputMethodDelegate delegate_;
275 scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
276 RemoteInputMethodPrivateWin* private_ptr =
277 RemoteInputMethodPrivateWin::Get(input_method.get());
278 ASSERT_TRUE(private_ptr != NULL);
279
280 // Initial value
281 EXPECT_FALSE(input_method->IsCandidatePopupOpen());
282
283 private_ptr->OnCandidatePopupChanged(true);
284 EXPECT_TRUE(input_method->IsCandidatePopupOpen());
285
286 private_ptr->OnCandidatePopupChanged(false);
287 EXPECT_FALSE(input_method->IsCandidatePopupOpen());
288 }
289
TEST(RemoteInputMethodWinTest,CancelComposition)290 TEST(RemoteInputMethodWinTest, CancelComposition) {
291 MockInputMethodDelegate delegate_;
292 MockTextInputClient mock_text_input_client;
293 scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
294
295 // This must not cause a crash.
296 input_method->CancelComposition(&mock_text_input_client);
297
298 RemoteInputMethodPrivateWin* private_ptr =
299 RemoteInputMethodPrivateWin::Get(input_method.get());
300 ASSERT_TRUE(private_ptr != NULL);
301 MockRemoteInputMethodDelegateWin mock_remote_delegate;
302 private_ptr->SetRemoteDelegate(&mock_remote_delegate);
303
304 input_method->CancelComposition(&mock_text_input_client);
305 EXPECT_FALSE(mock_remote_delegate.cancel_composition_called());
306
307 input_method->SetFocusedTextInputClient(&mock_text_input_client);
308 input_method->CancelComposition(&mock_text_input_client);
309 EXPECT_TRUE(mock_remote_delegate.cancel_composition_called());
310 }
311
TEST(RemoteInputMethodWinTest,SetFocusedTextInputClient)312 TEST(RemoteInputMethodWinTest, SetFocusedTextInputClient) {
313 MockInputMethodDelegate delegate_;
314 MockTextInputClient mock_text_input_client;
315 scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
316
317 mock_text_input_client.set_caret_bounds(gfx::Rect(10, 0, 10, 20));
318 mock_text_input_client.set_text_input_type(ui::TEXT_INPUT_TYPE_URL);
319 input_method->SetFocusedTextInputClient(&mock_text_input_client);
320
321 RemoteInputMethodPrivateWin* private_ptr =
322 RemoteInputMethodPrivateWin::Get(input_method.get());
323 ASSERT_TRUE(private_ptr != NULL);
324 MockRemoteInputMethodDelegateWin mock_remote_delegate;
325 private_ptr->SetRemoteDelegate(&mock_remote_delegate);
326
327 // Initial state must be synced.
328 EXPECT_TRUE(mock_remote_delegate.text_input_client_updated_called());
329 ASSERT_EQ(1, mock_remote_delegate.composition_character_bounds().size());
330 EXPECT_EQ(gfx::Rect(10, 0, 10, 20),
331 mock_remote_delegate.composition_character_bounds()[0]);
332 ASSERT_EQ(1, mock_remote_delegate.input_scopes().size());
333 EXPECT_EQ(IS_URL, mock_remote_delegate.input_scopes()[0]);
334
335 // State must be cleared by SetFocusedTextInputClient(NULL).
336 mock_remote_delegate.Reset();
337 input_method->SetFocusedTextInputClient(NULL);
338 EXPECT_TRUE(mock_remote_delegate.text_input_client_updated_called());
339 EXPECT_TRUE(mock_remote_delegate.composition_character_bounds().empty());
340 EXPECT_TRUE(mock_remote_delegate.input_scopes().empty());
341 }
342
TEST(RemoteInputMethodWinTest,DetachTextInputClient)343 TEST(RemoteInputMethodWinTest, DetachTextInputClient) {
344 MockInputMethodDelegate delegate_;
345 MockTextInputClient mock_text_input_client;
346 scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
347
348 mock_text_input_client.set_caret_bounds(gfx::Rect(10, 0, 10, 20));
349 mock_text_input_client.set_text_input_type(ui::TEXT_INPUT_TYPE_URL);
350 input_method->SetFocusedTextInputClient(&mock_text_input_client);
351
352 RemoteInputMethodPrivateWin* private_ptr =
353 RemoteInputMethodPrivateWin::Get(input_method.get());
354 ASSERT_TRUE(private_ptr != NULL);
355 MockRemoteInputMethodDelegateWin mock_remote_delegate;
356 private_ptr->SetRemoteDelegate(&mock_remote_delegate);
357
358 // Initial state must be synced.
359 EXPECT_TRUE(mock_remote_delegate.text_input_client_updated_called());
360 ASSERT_EQ(1, mock_remote_delegate.composition_character_bounds().size());
361 EXPECT_EQ(gfx::Rect(10, 0, 10, 20),
362 mock_remote_delegate.composition_character_bounds()[0]);
363 ASSERT_EQ(1, mock_remote_delegate.input_scopes().size());
364 EXPECT_EQ(IS_URL, mock_remote_delegate.input_scopes()[0]);
365
366 // State must be cleared by DetachTextInputClient
367 mock_remote_delegate.Reset();
368 input_method->DetachTextInputClient(&mock_text_input_client);
369 EXPECT_TRUE(mock_remote_delegate.text_input_client_updated_called());
370 EXPECT_TRUE(mock_remote_delegate.composition_character_bounds().empty());
371 EXPECT_TRUE(mock_remote_delegate.input_scopes().empty());
372 }
373
TEST(RemoteInputMethodWinTest,OnCaretBoundsChanged)374 TEST(RemoteInputMethodWinTest, OnCaretBoundsChanged) {
375 MockInputMethodDelegate delegate_;
376 MockTextInputClient mock_text_input_client;
377 scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
378
379 // This must not cause a crash.
380 input_method->OnCaretBoundsChanged(&mock_text_input_client);
381
382 mock_text_input_client.set_caret_bounds(gfx::Rect(10, 0, 10, 20));
383 input_method->SetFocusedTextInputClient(&mock_text_input_client);
384
385 RemoteInputMethodPrivateWin* private_ptr =
386 RemoteInputMethodPrivateWin::Get(input_method.get());
387 ASSERT_TRUE(private_ptr != NULL);
388 MockRemoteInputMethodDelegateWin mock_remote_delegate;
389 private_ptr->SetRemoteDelegate(&mock_remote_delegate);
390
391 // Initial state must be synced.
392 EXPECT_TRUE(mock_remote_delegate.text_input_client_updated_called());
393 ASSERT_EQ(1, mock_remote_delegate.composition_character_bounds().size());
394 EXPECT_EQ(gfx::Rect(10, 0, 10, 20),
395 mock_remote_delegate.composition_character_bounds()[0]);
396
397 // Redundant OnCaretBoundsChanged must be ignored.
398 mock_remote_delegate.Reset();
399 input_method->OnCaretBoundsChanged(&mock_text_input_client);
400 EXPECT_FALSE(mock_remote_delegate.text_input_client_updated_called());
401
402 // Check OnCaretBoundsChanged is handled. (w/o composition)
403 mock_remote_delegate.Reset();
404 mock_text_input_client.Reset();
405 mock_text_input_client.set_caret_bounds(gfx::Rect(10, 20, 30, 40));
406 input_method->OnCaretBoundsChanged(&mock_text_input_client);
407 EXPECT_TRUE(mock_remote_delegate.text_input_client_updated_called());
408 ASSERT_EQ(1, mock_remote_delegate.composition_character_bounds().size());
409 EXPECT_EQ(gfx::Rect(10, 20, 30, 40),
410 mock_remote_delegate.composition_character_bounds()[0]);
411
412 // Check OnCaretBoundsChanged is handled. (w/ composition)
413 {
414 mock_remote_delegate.Reset();
415 mock_text_input_client.Reset();
416
417 std::vector<gfx::Rect> bounds;
418 bounds.push_back(gfx::Rect(10, 20, 30, 40));
419 bounds.push_back(gfx::Rect(40, 30, 20, 10));
420 mock_text_input_client.set_composition_character_bounds(bounds);
421 input_method->OnCaretBoundsChanged(&mock_text_input_client);
422 EXPECT_TRUE(mock_remote_delegate.text_input_client_updated_called());
423 EXPECT_EQ(bounds, mock_remote_delegate.composition_character_bounds());
424 }
425 }
426
TEST(RemoteInputMethodWinTest,OnTextInputTypeChanged)427 TEST(RemoteInputMethodWinTest, OnTextInputTypeChanged) {
428 MockInputMethodDelegate delegate_;
429 MockTextInputClient mock_text_input_client;
430 scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
431
432 // This must not cause a crash.
433 input_method->OnCaretBoundsChanged(&mock_text_input_client);
434
435 mock_text_input_client.set_text_input_type(ui::TEXT_INPUT_TYPE_URL);
436 input_method->SetFocusedTextInputClient(&mock_text_input_client);
437
438 RemoteInputMethodPrivateWin* private_ptr =
439 RemoteInputMethodPrivateWin::Get(input_method.get());
440 ASSERT_TRUE(private_ptr != NULL);
441 MockRemoteInputMethodDelegateWin mock_remote_delegate;
442 private_ptr->SetRemoteDelegate(&mock_remote_delegate);
443
444 // Initial state must be synced.
445 EXPECT_TRUE(mock_remote_delegate.text_input_client_updated_called());
446 ASSERT_EQ(1, mock_remote_delegate.input_scopes().size());
447 EXPECT_EQ(IS_URL, mock_remote_delegate.input_scopes()[0]);
448
449 // Check TEXT_INPUT_TYPE_NONE is handled.
450 mock_remote_delegate.Reset();
451 mock_text_input_client.Reset();
452 mock_text_input_client.set_text_input_type(ui::TEXT_INPUT_TYPE_NONE);
453 mock_text_input_client.set_text_input_mode(ui::TEXT_INPUT_MODE_KATAKANA);
454 input_method->OnTextInputTypeChanged(&mock_text_input_client);
455 EXPECT_TRUE(mock_remote_delegate.text_input_client_updated_called());
456 EXPECT_TRUE(mock_remote_delegate.input_scopes().empty());
457
458 // Redundant OnTextInputTypeChanged must be ignored.
459 mock_remote_delegate.Reset();
460 input_method->OnTextInputTypeChanged(&mock_text_input_client);
461 EXPECT_FALSE(mock_remote_delegate.text_input_client_updated_called());
462
463 mock_remote_delegate.Reset();
464 mock_text_input_client.Reset();
465 mock_text_input_client.set_caret_bounds(gfx::Rect(10, 20, 30, 40));
466 input_method->OnCaretBoundsChanged(&mock_text_input_client);
467 }
468
TEST(RemoteInputMethodWinTest,DispatchKeyEvent_NativeKeyEvent)469 TEST(RemoteInputMethodWinTest, DispatchKeyEvent_NativeKeyEvent) {
470 // Basically RemoteInputMethodWin does not handle native keydown event.
471
472 MockInputMethodDelegate delegate_;
473 MockTextInputClient mock_text_input_client;
474 scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
475
476 const MSG wm_keydown = { NULL, WM_KEYDOWN, ui::VKEY_A };
477 ui::KeyEvent native_keydown(wm_keydown, false);
478
479 // This must not cause a crash.
480 EXPECT_FALSE(input_method->DispatchKeyEvent(native_keydown));
481 EXPECT_TRUE(mock_text_input_client.inserted_text().empty());
482 EXPECT_TRUE(delegate_.fabricated_key_events().empty());
483 delegate_.Reset();
484 mock_text_input_client.Reset();
485
486 RemoteInputMethodPrivateWin* private_ptr =
487 RemoteInputMethodPrivateWin::Get(input_method.get());
488 ASSERT_TRUE(private_ptr != NULL);
489 MockRemoteInputMethodDelegateWin mock_remote_delegate;
490 private_ptr->SetRemoteDelegate(&mock_remote_delegate);
491
492 // TextInputClient is not focused yet here.
493
494 EXPECT_FALSE(input_method->DispatchKeyEvent(native_keydown));
495 EXPECT_TRUE(mock_text_input_client.inserted_text().empty());
496 EXPECT_TRUE(delegate_.fabricated_key_events().empty());
497 delegate_.Reset();
498 mock_text_input_client.Reset();
499
500 input_method->SetFocusedTextInputClient(&mock_text_input_client);
501
502 // TextInputClient is now focused here.
503
504 EXPECT_FALSE(input_method->DispatchKeyEvent(native_keydown));
505 EXPECT_TRUE(mock_text_input_client.inserted_text().empty());
506 EXPECT_TRUE(delegate_.fabricated_key_events().empty());
507 delegate_.Reset();
508 mock_text_input_client.Reset();
509 }
510
TEST(RemoteInputMethodWinTest,DispatchKeyEvent_NativeCharEvent)511 TEST(RemoteInputMethodWinTest, DispatchKeyEvent_NativeCharEvent) {
512 // RemoteInputMethodWin handles native char event if possible.
513
514 MockInputMethodDelegate delegate_;
515 MockTextInputClient mock_text_input_client;
516 scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
517
518 const MSG wm_char = { NULL, WM_CHAR, 'A', 0 };
519 ui::KeyEvent native_char(wm_char, true);
520
521 // This must not cause a crash.
522 EXPECT_FALSE(input_method->DispatchKeyEvent(native_char));
523 EXPECT_TRUE(mock_text_input_client.inserted_text().empty());
524 EXPECT_TRUE(delegate_.fabricated_key_events().empty());
525 delegate_.Reset();
526 mock_text_input_client.Reset();
527
528 RemoteInputMethodPrivateWin* private_ptr =
529 RemoteInputMethodPrivateWin::Get(input_method.get());
530 ASSERT_TRUE(private_ptr != NULL);
531 MockRemoteInputMethodDelegateWin mock_remote_delegate;
532 private_ptr->SetRemoteDelegate(&mock_remote_delegate);
533
534 // TextInputClient is not focused yet here.
535
536 EXPECT_FALSE(input_method->DispatchKeyEvent(native_char));
537 EXPECT_TRUE(mock_text_input_client.inserted_text().empty());
538 EXPECT_TRUE(delegate_.fabricated_key_events().empty());
539 delegate_.Reset();
540 mock_text_input_client.Reset();
541
542 input_method->SetFocusedTextInputClient(&mock_text_input_client);
543
544 // TextInputClient is now focused here.
545
546 EXPECT_TRUE(input_method->DispatchKeyEvent(native_char));
547 EXPECT_EQ(L"A", mock_text_input_client.inserted_text());
548 EXPECT_TRUE(delegate_.fabricated_key_events().empty());
549 delegate_.Reset();
550 mock_text_input_client.Reset();
551 }
552
TEST(RemoteInputMethodWinTest,DispatchKeyEvent_FabricatedKeyDown)553 TEST(RemoteInputMethodWinTest, DispatchKeyEvent_FabricatedKeyDown) {
554 // Fabricated non-char event will be delegated to
555 // InputMethodDelegate::DispatchFabricatedKeyEventPostIME as long as the
556 // delegate is installed.
557
558 MockInputMethodDelegate delegate_;
559 MockTextInputClient mock_text_input_client;
560 scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
561
562 ui::KeyEvent fabricated_keydown(ui::ET_KEY_PRESSED, ui::VKEY_A, 0, false);
563 fabricated_keydown.set_character(L'A');
564
565 // This must not cause a crash.
566 EXPECT_TRUE(input_method->DispatchKeyEvent(fabricated_keydown));
567 EXPECT_TRUE(mock_text_input_client.inserted_text().empty());
568 ASSERT_EQ(1, delegate_.fabricated_key_events().size());
569 EXPECT_EQ(L'A', delegate_.fabricated_key_events()[0]);
570 delegate_.Reset();
571 mock_text_input_client.Reset();
572
573 RemoteInputMethodPrivateWin* private_ptr =
574 RemoteInputMethodPrivateWin::Get(input_method.get());
575 ASSERT_TRUE(private_ptr != NULL);
576 MockRemoteInputMethodDelegateWin mock_remote_delegate;
577 private_ptr->SetRemoteDelegate(&mock_remote_delegate);
578
579 // TextInputClient is not focused yet here.
580
581 EXPECT_TRUE(input_method->DispatchKeyEvent(fabricated_keydown));
582 EXPECT_TRUE(mock_text_input_client.inserted_text().empty());
583 ASSERT_EQ(1, delegate_.fabricated_key_events().size());
584 EXPECT_EQ(L'A', delegate_.fabricated_key_events()[0]);
585 delegate_.Reset();
586 mock_text_input_client.Reset();
587
588 input_method->SetFocusedTextInputClient(&mock_text_input_client);
589 // TextInputClient is now focused here.
590
591 EXPECT_TRUE(input_method->DispatchKeyEvent(fabricated_keydown));
592 EXPECT_TRUE(mock_text_input_client.inserted_text().empty());
593 ASSERT_EQ(1, delegate_.fabricated_key_events().size());
594 EXPECT_EQ(L'A', delegate_.fabricated_key_events()[0]);
595 delegate_.Reset();
596 mock_text_input_client.Reset();
597
598 input_method->SetDelegate(NULL);
599 // RemoteInputMethodDelegateWin is no longer set here.
600
601 EXPECT_FALSE(input_method->DispatchKeyEvent(fabricated_keydown));
602 EXPECT_TRUE(mock_text_input_client.inserted_text().empty());
603 }
604
TEST(RemoteInputMethodWinTest,DispatchKeyEvent_FabricatedChar)605 TEST(RemoteInputMethodWinTest, DispatchKeyEvent_FabricatedChar) {
606 // Note: RemoteInputMethodWin::DispatchKeyEvent should always return true
607 // for fabricated character events.
608
609 MockInputMethodDelegate delegate_;
610 MockTextInputClient mock_text_input_client;
611 scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
612
613 ui::KeyEvent fabricated_char(ui::ET_KEY_PRESSED, ui::VKEY_A, 0, true);
614 fabricated_char.set_character(L'A');
615
616 // This must not cause a crash.
617 EXPECT_TRUE(input_method->DispatchKeyEvent(fabricated_char));
618 EXPECT_TRUE(mock_text_input_client.inserted_text().empty());
619 EXPECT_TRUE(delegate_.fabricated_key_events().empty());
620 delegate_.Reset();
621 mock_text_input_client.Reset();
622
623 RemoteInputMethodPrivateWin* private_ptr =
624 RemoteInputMethodPrivateWin::Get(input_method.get());
625 ASSERT_TRUE(private_ptr != NULL);
626 MockRemoteInputMethodDelegateWin mock_remote_delegate;
627 private_ptr->SetRemoteDelegate(&mock_remote_delegate);
628
629 // TextInputClient is not focused yet here.
630
631 EXPECT_TRUE(input_method->DispatchKeyEvent(fabricated_char));
632 EXPECT_TRUE(mock_text_input_client.inserted_text().empty());
633 EXPECT_TRUE(delegate_.fabricated_key_events().empty());
634 delegate_.Reset();
635 mock_text_input_client.Reset();
636
637 input_method->SetFocusedTextInputClient(&mock_text_input_client);
638
639 // TextInputClient is now focused here.
640
641 EXPECT_TRUE(input_method->DispatchKeyEvent(fabricated_char));
642 EXPECT_EQ(L"A", mock_text_input_client.inserted_text());
643 EXPECT_TRUE(delegate_.fabricated_key_events().empty());
644 delegate_.Reset();
645 mock_text_input_client.Reset();
646 }
647
TEST(RemoteInputMethodWinTest,OnCompositionChanged)648 TEST(RemoteInputMethodWinTest, OnCompositionChanged) {
649 MockInputMethodDelegate delegate_;
650 MockTextInputClient mock_text_input_client;
651 scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
652
653 RemoteInputMethodPrivateWin* private_ptr =
654 RemoteInputMethodPrivateWin::Get(input_method.get());
655 ASSERT_TRUE(private_ptr != NULL);
656 MockRemoteInputMethodDelegateWin mock_remote_delegate;
657 private_ptr->SetRemoteDelegate(&mock_remote_delegate);
658
659 CompositionText composition_text;
660
661 // TextInputClient is not focused yet here.
662
663 private_ptr->OnCompositionChanged(composition_text);
664 EXPECT_EQ(0, mock_text_input_client.call_count_set_composition_text());
665 delegate_.Reset();
666 mock_text_input_client.Reset();
667
668 input_method->SetFocusedTextInputClient(&mock_text_input_client);
669
670 // TextInputClient is now focused here.
671
672 private_ptr->OnCompositionChanged(composition_text);
673 EXPECT_EQ(1, mock_text_input_client.call_count_set_composition_text());
674 delegate_.Reset();
675 mock_text_input_client.Reset();
676 }
677
TEST(RemoteInputMethodWinTest,OnTextCommitted)678 TEST(RemoteInputMethodWinTest, OnTextCommitted) {
679 MockInputMethodDelegate delegate_;
680 MockTextInputClient mock_text_input_client;
681 scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
682
683 RemoteInputMethodPrivateWin* private_ptr =
684 RemoteInputMethodPrivateWin::Get(input_method.get());
685 ASSERT_TRUE(private_ptr != NULL);
686 MockRemoteInputMethodDelegateWin mock_remote_delegate;
687 private_ptr->SetRemoteDelegate(&mock_remote_delegate);
688
689 base::string16 committed_text = L"Hello";
690
691 // TextInputClient is not focused yet here.
692
693 mock_text_input_client.set_text_input_type(TEXT_INPUT_TYPE_TEXT);
694 private_ptr->OnTextCommitted(committed_text);
695 EXPECT_EQ(0, mock_text_input_client.call_count_insert_char());
696 EXPECT_EQ(0, mock_text_input_client.call_count_insert_text());
697 EXPECT_EQ(L"", mock_text_input_client.inserted_text());
698 delegate_.Reset();
699 mock_text_input_client.Reset();
700
701 input_method->SetFocusedTextInputClient(&mock_text_input_client);
702
703 // TextInputClient is now focused here.
704
705 mock_text_input_client.set_text_input_type(TEXT_INPUT_TYPE_TEXT);
706 private_ptr->OnTextCommitted(committed_text);
707 EXPECT_EQ(0, mock_text_input_client.call_count_insert_char());
708 EXPECT_EQ(1, mock_text_input_client.call_count_insert_text());
709 EXPECT_EQ(committed_text, mock_text_input_client.inserted_text());
710 delegate_.Reset();
711 mock_text_input_client.Reset();
712
713 // When TextInputType is TEXT_INPUT_TYPE_NONE, TextInputClient::InsertText
714 // should not be used.
715 mock_text_input_client.set_text_input_type(TEXT_INPUT_TYPE_NONE);
716 private_ptr->OnTextCommitted(committed_text);
717 EXPECT_EQ(committed_text.size(),
718 mock_text_input_client.call_count_insert_char());
719 EXPECT_EQ(0, mock_text_input_client.call_count_insert_text());
720 EXPECT_EQ(committed_text, mock_text_input_client.inserted_text());
721 delegate_.Reset();
722 mock_text_input_client.Reset();
723 }
724
TEST(RemoteInputMethodWinTest,OnTextInputStateChanged_Observer)725 TEST(RemoteInputMethodWinTest, OnTextInputStateChanged_Observer) {
726 DummyTextInputClient text_input_client;
727 DummyTextInputClient text_input_client_the_other;
728
729 MockInputMethodObserver input_method_observer;
730 MockInputMethodDelegate delegate_;
731 scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
732 InputMethodScopedObserver scoped_observer(&input_method_observer);
733 scoped_observer.Add(input_method.get());
734
735 input_method->SetFocusedTextInputClient(&text_input_client);
736 ASSERT_EQ(&text_input_client, input_method->GetTextInputClient());
737 EXPECT_EQ(1u, input_method_observer.on_text_input_state_changed());
738 input_method_observer.Reset();
739
740 input_method->SetFocusedTextInputClient(&text_input_client);
741 ASSERT_EQ(&text_input_client, input_method->GetTextInputClient());
742 EXPECT_EQ(0u, input_method_observer.on_text_input_state_changed());
743 input_method_observer.Reset();
744
745 input_method->SetFocusedTextInputClient(&text_input_client_the_other);
746 ASSERT_EQ(&text_input_client_the_other, input_method->GetTextInputClient());
747 EXPECT_EQ(1u, input_method_observer.on_text_input_state_changed());
748 input_method_observer.Reset();
749
750 input_method->DetachTextInputClient(&text_input_client_the_other);
751 ASSERT_TRUE(input_method->GetTextInputClient() == NULL);
752 EXPECT_EQ(1u, input_method_observer.on_text_input_state_changed());
753 input_method_observer.Reset();
754 }
755
TEST(RemoteInputMethodWinTest,OnInputMethodDestroyed_Observer)756 TEST(RemoteInputMethodWinTest, OnInputMethodDestroyed_Observer) {
757 DummyTextInputClient text_input_client;
758 DummyTextInputClient text_input_client_the_other;
759
760 MockInputMethodObserver input_method_observer;
761 InputMethodScopedObserver scoped_observer(&input_method_observer);
762
763 MockInputMethodDelegate delegate_;
764 scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_));
765 input_method->AddObserver(&input_method_observer);
766
767 EXPECT_EQ(0u, input_method_observer.on_input_method_destroyed_changed());
768 input_method.reset();
769 EXPECT_EQ(1u, input_method_observer.on_input_method_destroyed_changed());
770 }
771
772 } // namespace
773 } // namespace ui
774