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.
5 #include "ui/base/ime/remote_input_method_win.h"
7 #include <InputScope.h>
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"
26 class MockTextInputClient
: public DummyTextInputClient
{
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 emulate_pepper_flash_(false),
35 is_candidate_window_shown_called_(false),
36 is_candidate_window_hidden_called_(false) {
39 size_t call_count_set_composition_text() const {
40 return call_count_set_composition_text_
;
42 const base::string16
& inserted_text() const {
43 return inserted_text_
;
45 size_t call_count_insert_char() const {
46 return call_count_insert_char_
;
48 size_t call_count_insert_text() const {
49 return call_count_insert_text_
;
51 bool is_candidate_window_shown_called() const {
52 return is_candidate_window_shown_called_
;
54 bool is_candidate_window_hidden_called() const {
55 return is_candidate_window_hidden_called_
;
58 text_input_type_
= TEXT_INPUT_TYPE_NONE
;
59 text_input_mode_
= TEXT_INPUT_MODE_DEFAULT
;
60 call_count_set_composition_text_
= 0;
61 inserted_text_
.clear();
62 call_count_insert_char_
= 0;
63 call_count_insert_text_
= 0;
64 caret_bounds_
= gfx::Rect();
65 composition_character_bounds_
.clear();
66 emulate_pepper_flash_
= false;
67 is_candidate_window_shown_called_
= false;
68 is_candidate_window_hidden_called_
= false;
70 void set_text_input_type(ui::TextInputType type
) {
71 text_input_type_
= type
;
73 void set_text_input_mode(ui::TextInputMode mode
) {
74 text_input_mode_
= mode
;
76 void set_caret_bounds(const gfx::Rect
& caret_bounds
) {
77 caret_bounds_
= caret_bounds
;
79 void set_composition_character_bounds(
80 const std::vector
<gfx::Rect
>& composition_character_bounds
) {
81 composition_character_bounds_
= composition_character_bounds
;
83 void set_emulate_pepper_flash(bool enabled
) {
84 emulate_pepper_flash_
= enabled
;
88 // Overriden from DummyTextInputClient.
89 virtual void SetCompositionText(
90 const ui::CompositionText
& composition
) OVERRIDE
{
91 ++call_count_set_composition_text_
;
93 virtual void InsertChar(base::char16 ch
, int flags
) OVERRIDE
{
94 inserted_text_
.append(1, ch
);
95 ++call_count_insert_char_
;
97 virtual void InsertText(const base::string16
& text
) OVERRIDE
{
98 inserted_text_
.append(text
);
99 ++call_count_insert_text_
;
101 virtual ui::TextInputType
GetTextInputType() const OVERRIDE
{
102 return text_input_type_
;
104 virtual ui::TextInputMode
GetTextInputMode() const OVERRIDE
{
105 return text_input_mode_
;
107 virtual gfx::Rect
GetCaretBounds() const {
108 return caret_bounds_
;
110 virtual bool GetCompositionCharacterBounds(uint32 index
,
111 gfx::Rect
* rect
) const OVERRIDE
{
112 // Emulate the situation of crbug.com/328237.
113 if (emulate_pepper_flash_
)
115 if (!rect
|| composition_character_bounds_
.size() <= index
)
117 *rect
= composition_character_bounds_
[index
];
120 virtual bool HasCompositionText() const OVERRIDE
{
121 return !composition_character_bounds_
.empty();
123 virtual bool GetCompositionTextRange(gfx::Range
* range
) const OVERRIDE
{
124 if (composition_character_bounds_
.empty())
126 *range
= gfx::Range(0, composition_character_bounds_
.size());
129 virtual void OnCandidateWindowShown() OVERRIDE
{
130 is_candidate_window_shown_called_
= true;
132 virtual void OnCandidateWindowHidden() OVERRIDE
{
133 is_candidate_window_hidden_called_
= true;
136 ui::TextInputType text_input_type_
;
137 ui::TextInputMode text_input_mode_
;
138 gfx::Rect caret_bounds_
;
139 std::vector
<gfx::Rect
> composition_character_bounds_
;
140 base::string16 inserted_text_
;
141 size_t call_count_set_composition_text_
;
142 size_t call_count_insert_char_
;
143 size_t call_count_insert_text_
;
144 bool emulate_pepper_flash_
;
145 bool is_candidate_window_shown_called_
;
146 bool is_candidate_window_hidden_called_
;
147 DISALLOW_COPY_AND_ASSIGN(MockTextInputClient
);
150 class MockInputMethodDelegate
: public internal::InputMethodDelegate
{
152 MockInputMethodDelegate() {}
154 const std::vector
<ui::KeyboardCode
>& fabricated_key_events() const {
155 return fabricated_key_events_
;
158 fabricated_key_events_
.clear();
162 virtual bool DispatchKeyEventPostIME(
163 const base::NativeEvent
& native_key_event
) OVERRIDE
{
164 EXPECT_TRUE(false) << "Not reach here";
167 virtual bool DispatchFabricatedKeyEventPostIME(ui::EventType type
,
168 ui::KeyboardCode key_code
,
169 int flags
) OVERRIDE
{
170 fabricated_key_events_
.push_back(key_code
);
174 std::vector
<ui::KeyboardCode
> fabricated_key_events_
;
175 DISALLOW_COPY_AND_ASSIGN(MockInputMethodDelegate
);
178 class MockRemoteInputMethodDelegateWin
179 : public internal::RemoteInputMethodDelegateWin
{
181 MockRemoteInputMethodDelegateWin()
182 : cancel_composition_called_(false),
183 text_input_client_updated_called_(false) {
186 bool cancel_composition_called() const {
187 return cancel_composition_called_
;
189 bool text_input_client_updated_called() const {
190 return text_input_client_updated_called_
;
192 const std::vector
<int32
>& input_scopes() const {
193 return input_scopes_
;
195 const std::vector
<gfx::Rect
>& composition_character_bounds() const {
196 return composition_character_bounds_
;
199 cancel_composition_called_
= false;
200 text_input_client_updated_called_
= false;
201 input_scopes_
.clear();
202 composition_character_bounds_
.clear();
206 virtual void CancelComposition() OVERRIDE
{
207 cancel_composition_called_
= true;
210 virtual void OnTextInputClientUpdated(
211 const std::vector
<int32
>& input_scopes
,
212 const std::vector
<gfx::Rect
>& composition_character_bounds
) OVERRIDE
{
213 text_input_client_updated_called_
= true;
214 input_scopes_
= input_scopes
;
215 composition_character_bounds_
= composition_character_bounds
;
218 bool cancel_composition_called_
;
219 bool text_input_client_updated_called_
;
220 std::vector
<int32
> input_scopes_
;
221 std::vector
<gfx::Rect
> composition_character_bounds_
;
222 DISALLOW_COPY_AND_ASSIGN(MockRemoteInputMethodDelegateWin
);
225 class MockInputMethodObserver
: public InputMethodObserver
{
227 MockInputMethodObserver()
228 : on_text_input_state_changed_(0),
229 on_input_method_destroyed_changed_(0) {
231 virtual ~MockInputMethodObserver() {
234 on_text_input_state_changed_
= 0;
235 on_input_method_destroyed_changed_
= 0;
237 size_t on_text_input_state_changed() const {
238 return on_text_input_state_changed_
;
240 size_t on_input_method_destroyed_changed() const {
241 return on_input_method_destroyed_changed_
;
245 // Overriden from InputMethodObserver.
246 virtual void OnTextInputTypeChanged(const TextInputClient
* client
) OVERRIDE
{
248 virtual void OnFocus() OVERRIDE
{
250 virtual void OnBlur() OVERRIDE
{
252 virtual void OnCaretBoundsChanged(const TextInputClient
* client
) OVERRIDE
{
254 virtual void OnTextInputStateChanged(const TextInputClient
* client
) OVERRIDE
{
255 ++on_text_input_state_changed_
;
257 virtual void OnInputMethodDestroyed(const InputMethod
* client
) OVERRIDE
{
258 ++on_input_method_destroyed_changed_
;
260 virtual void OnShowImeIfNeeded() {
263 size_t on_text_input_state_changed_
;
264 size_t on_input_method_destroyed_changed_
;
265 DISALLOW_COPY_AND_ASSIGN(MockInputMethodObserver
);
268 typedef ScopedObserver
<InputMethod
, InputMethodObserver
>
269 InputMethodScopedObserver
;
271 TEST(RemoteInputMethodWinTest
, RemoteInputMethodPrivateWin
) {
272 InputMethod
* other_ptr
= static_cast<InputMethod
*>(NULL
) + 1;
274 // Use typed NULL to make EXPECT_NE happy until nullptr becomes available.
275 RemoteInputMethodPrivateWin
* kNull
=
276 static_cast<RemoteInputMethodPrivateWin
*>(NULL
);
277 EXPECT_EQ(kNull
, RemoteInputMethodPrivateWin::Get(other_ptr
));
279 MockInputMethodDelegate delegate_
;
280 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
281 EXPECT_NE(kNull
, RemoteInputMethodPrivateWin::Get(input_method
.get()));
283 InputMethod
* dangling_ptr
= input_method
.get();
284 input_method
.reset(NULL
);
285 EXPECT_EQ(kNull
, RemoteInputMethodPrivateWin::Get(dangling_ptr
));
288 TEST(RemoteInputMethodWinTest
, OnInputSourceChanged
) {
289 MockInputMethodDelegate delegate_
;
290 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
291 RemoteInputMethodPrivateWin
* private_ptr
=
292 RemoteInputMethodPrivateWin::Get(input_method
.get());
293 ASSERT_TRUE(private_ptr
!= NULL
);
295 private_ptr
->OnInputSourceChanged(
296 MAKELANGID(LANG_JAPANESE
, SUBLANG_JAPANESE_JAPAN
), true);
297 EXPECT_EQ("ja-JP", input_method
->GetInputLocale());
299 private_ptr
->OnInputSourceChanged(
300 MAKELANGID(LANG_ARABIC
, SUBLANG_ARABIC_QATAR
), true);
301 EXPECT_EQ("ar-QA", input_method
->GetInputLocale());
304 TEST(RemoteInputMethodWinTest
, OnCandidatePopupChanged
) {
305 MockInputMethodDelegate delegate_
;
306 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
307 RemoteInputMethodPrivateWin
* private_ptr
=
308 RemoteInputMethodPrivateWin::Get(input_method
.get());
309 ASSERT_TRUE(private_ptr
!= NULL
);
312 EXPECT_FALSE(input_method
->IsCandidatePopupOpen());
314 // RemoteInputMethodWin::OnCandidatePopupChanged can be called even when the
315 // focused text input client is NULL.
316 ASSERT_TRUE(input_method
->GetTextInputClient() == NULL
);
317 private_ptr
->OnCandidatePopupChanged(false);
318 private_ptr
->OnCandidatePopupChanged(true);
320 MockTextInputClient mock_text_input_client
;
321 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
323 ASSERT_FALSE(mock_text_input_client
.is_candidate_window_shown_called());
324 ASSERT_FALSE(mock_text_input_client
.is_candidate_window_hidden_called());
325 mock_text_input_client
.Reset();
327 private_ptr
->OnCandidatePopupChanged(true);
328 EXPECT_TRUE(input_method
->IsCandidatePopupOpen());
329 EXPECT_TRUE(mock_text_input_client
.is_candidate_window_shown_called());
330 EXPECT_FALSE(mock_text_input_client
.is_candidate_window_hidden_called());
332 private_ptr
->OnCandidatePopupChanged(false);
333 EXPECT_FALSE(input_method
->IsCandidatePopupOpen());
334 EXPECT_TRUE(mock_text_input_client
.is_candidate_window_shown_called());
335 EXPECT_TRUE(mock_text_input_client
.is_candidate_window_hidden_called());
338 TEST(RemoteInputMethodWinTest
, CancelComposition
) {
339 MockInputMethodDelegate delegate_
;
340 MockTextInputClient mock_text_input_client
;
341 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
343 // This must not cause a crash.
344 input_method
->CancelComposition(&mock_text_input_client
);
346 RemoteInputMethodPrivateWin
* private_ptr
=
347 RemoteInputMethodPrivateWin::Get(input_method
.get());
348 ASSERT_TRUE(private_ptr
!= NULL
);
349 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
350 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
352 input_method
->CancelComposition(&mock_text_input_client
);
353 EXPECT_FALSE(mock_remote_delegate
.cancel_composition_called());
355 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
356 input_method
->CancelComposition(&mock_text_input_client
);
357 EXPECT_TRUE(mock_remote_delegate
.cancel_composition_called());
360 TEST(RemoteInputMethodWinTest
, SetFocusedTextInputClient
) {
361 MockInputMethodDelegate delegate_
;
362 MockTextInputClient mock_text_input_client
;
363 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
365 mock_text_input_client
.set_caret_bounds(gfx::Rect(10, 0, 10, 20));
366 mock_text_input_client
.set_text_input_type(ui::TEXT_INPUT_TYPE_URL
);
367 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
369 RemoteInputMethodPrivateWin
* private_ptr
=
370 RemoteInputMethodPrivateWin::Get(input_method
.get());
371 ASSERT_TRUE(private_ptr
!= NULL
);
372 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
373 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
375 // Initial state must be synced.
376 EXPECT_TRUE(mock_remote_delegate
.text_input_client_updated_called());
377 ASSERT_EQ(1, mock_remote_delegate
.composition_character_bounds().size());
378 EXPECT_EQ(gfx::Rect(10, 0, 10, 20),
379 mock_remote_delegate
.composition_character_bounds()[0]);
380 ASSERT_EQ(1, mock_remote_delegate
.input_scopes().size());
381 EXPECT_EQ(IS_URL
, mock_remote_delegate
.input_scopes()[0]);
383 // State must be cleared by SetFocusedTextInputClient(NULL).
384 mock_remote_delegate
.Reset();
385 input_method
->SetFocusedTextInputClient(NULL
);
386 EXPECT_TRUE(mock_remote_delegate
.text_input_client_updated_called());
387 EXPECT_TRUE(mock_remote_delegate
.composition_character_bounds().empty());
388 EXPECT_TRUE(mock_remote_delegate
.input_scopes().empty());
391 TEST(RemoteInputMethodWinTest
, DetachTextInputClient
) {
392 MockInputMethodDelegate delegate_
;
393 MockTextInputClient mock_text_input_client
;
394 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
396 mock_text_input_client
.set_caret_bounds(gfx::Rect(10, 0, 10, 20));
397 mock_text_input_client
.set_text_input_type(ui::TEXT_INPUT_TYPE_URL
);
398 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
400 RemoteInputMethodPrivateWin
* private_ptr
=
401 RemoteInputMethodPrivateWin::Get(input_method
.get());
402 ASSERT_TRUE(private_ptr
!= NULL
);
403 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
404 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
406 // Initial state must be synced.
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, 0, 10, 20),
410 mock_remote_delegate
.composition_character_bounds()[0]);
411 ASSERT_EQ(1, mock_remote_delegate
.input_scopes().size());
412 EXPECT_EQ(IS_URL
, mock_remote_delegate
.input_scopes()[0]);
414 // State must be cleared by DetachTextInputClient
415 mock_remote_delegate
.Reset();
416 input_method
->DetachTextInputClient(&mock_text_input_client
);
417 EXPECT_TRUE(mock_remote_delegate
.text_input_client_updated_called());
418 EXPECT_TRUE(mock_remote_delegate
.composition_character_bounds().empty());
419 EXPECT_TRUE(mock_remote_delegate
.input_scopes().empty());
422 TEST(RemoteInputMethodWinTest
, OnCaretBoundsChanged
) {
423 MockInputMethodDelegate delegate_
;
424 MockTextInputClient mock_text_input_client
;
425 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
427 // This must not cause a crash.
428 input_method
->OnCaretBoundsChanged(&mock_text_input_client
);
430 mock_text_input_client
.set_caret_bounds(gfx::Rect(10, 0, 10, 20));
431 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
433 RemoteInputMethodPrivateWin
* private_ptr
=
434 RemoteInputMethodPrivateWin::Get(input_method
.get());
435 ASSERT_TRUE(private_ptr
!= NULL
);
436 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
437 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
439 // Initial state must be synced.
440 EXPECT_TRUE(mock_remote_delegate
.text_input_client_updated_called());
441 ASSERT_EQ(1, mock_remote_delegate
.composition_character_bounds().size());
442 EXPECT_EQ(gfx::Rect(10, 0, 10, 20),
443 mock_remote_delegate
.composition_character_bounds()[0]);
445 // Redundant OnCaretBoundsChanged must be ignored.
446 mock_remote_delegate
.Reset();
447 input_method
->OnCaretBoundsChanged(&mock_text_input_client
);
448 EXPECT_FALSE(mock_remote_delegate
.text_input_client_updated_called());
450 // Check OnCaretBoundsChanged is handled. (w/o composition)
451 mock_remote_delegate
.Reset();
452 mock_text_input_client
.Reset();
453 mock_text_input_client
.set_caret_bounds(gfx::Rect(10, 20, 30, 40));
454 input_method
->OnCaretBoundsChanged(&mock_text_input_client
);
455 EXPECT_TRUE(mock_remote_delegate
.text_input_client_updated_called());
456 ASSERT_EQ(1, mock_remote_delegate
.composition_character_bounds().size());
457 EXPECT_EQ(gfx::Rect(10, 20, 30, 40),
458 mock_remote_delegate
.composition_character_bounds()[0]);
460 // Check OnCaretBoundsChanged is handled. (w/ composition)
462 mock_remote_delegate
.Reset();
463 mock_text_input_client
.Reset();
465 std::vector
<gfx::Rect
> bounds
;
466 bounds
.push_back(gfx::Rect(10, 20, 30, 40));
467 bounds
.push_back(gfx::Rect(40, 30, 20, 10));
468 mock_text_input_client
.set_composition_character_bounds(bounds
);
469 input_method
->OnCaretBoundsChanged(&mock_text_input_client
);
470 EXPECT_TRUE(mock_remote_delegate
.text_input_client_updated_called());
471 EXPECT_EQ(bounds
, mock_remote_delegate
.composition_character_bounds());
475 // Test case against crbug.com/328237.
476 TEST(RemoteInputMethodWinTest
, OnCaretBoundsChangedForPepperFlash
) {
477 MockInputMethodDelegate delegate_
;
478 MockTextInputClient mock_text_input_client
;
479 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
480 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
482 RemoteInputMethodPrivateWin
* private_ptr
=
483 RemoteInputMethodPrivateWin::Get(input_method
.get());
484 ASSERT_TRUE(private_ptr
!= NULL
);
485 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
486 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
488 mock_remote_delegate
.Reset();
489 mock_text_input_client
.Reset();
490 mock_text_input_client
.set_emulate_pepper_flash(true);
492 std::vector
<gfx::Rect
> caret_bounds
;
493 caret_bounds
.push_back(gfx::Rect(5, 15, 25, 35));
494 mock_text_input_client
.set_caret_bounds(caret_bounds
[0]);
496 std::vector
<gfx::Rect
> composition_bounds
;
497 composition_bounds
.push_back(gfx::Rect(10, 20, 30, 40));
498 composition_bounds
.push_back(gfx::Rect(40, 30, 20, 10));
499 mock_text_input_client
.set_composition_character_bounds(composition_bounds
);
500 input_method
->OnCaretBoundsChanged(&mock_text_input_client
);
501 EXPECT_TRUE(mock_remote_delegate
.text_input_client_updated_called());
502 // The caret bounds must be used when
503 // TextInputClient::GetCompositionCharacterBounds failed.
504 EXPECT_EQ(caret_bounds
, mock_remote_delegate
.composition_character_bounds());
507 TEST(RemoteInputMethodWinTest
, OnTextInputTypeChanged
) {
508 MockInputMethodDelegate delegate_
;
509 MockTextInputClient mock_text_input_client
;
510 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
512 // This must not cause a crash.
513 input_method
->OnCaretBoundsChanged(&mock_text_input_client
);
515 mock_text_input_client
.set_text_input_type(ui::TEXT_INPUT_TYPE_URL
);
516 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
518 RemoteInputMethodPrivateWin
* private_ptr
=
519 RemoteInputMethodPrivateWin::Get(input_method
.get());
520 ASSERT_TRUE(private_ptr
!= NULL
);
521 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
522 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
524 // Initial state must be synced.
525 EXPECT_TRUE(mock_remote_delegate
.text_input_client_updated_called());
526 ASSERT_EQ(1, mock_remote_delegate
.input_scopes().size());
527 EXPECT_EQ(IS_URL
, mock_remote_delegate
.input_scopes()[0]);
529 // Check TEXT_INPUT_TYPE_NONE is handled.
530 mock_remote_delegate
.Reset();
531 mock_text_input_client
.Reset();
532 mock_text_input_client
.set_text_input_type(ui::TEXT_INPUT_TYPE_NONE
);
533 mock_text_input_client
.set_text_input_mode(ui::TEXT_INPUT_MODE_KATAKANA
);
534 input_method
->OnTextInputTypeChanged(&mock_text_input_client
);
535 EXPECT_TRUE(mock_remote_delegate
.text_input_client_updated_called());
536 EXPECT_TRUE(mock_remote_delegate
.input_scopes().empty());
538 // Redundant OnTextInputTypeChanged must be ignored.
539 mock_remote_delegate
.Reset();
540 input_method
->OnTextInputTypeChanged(&mock_text_input_client
);
541 EXPECT_FALSE(mock_remote_delegate
.text_input_client_updated_called());
543 mock_remote_delegate
.Reset();
544 mock_text_input_client
.Reset();
545 mock_text_input_client
.set_caret_bounds(gfx::Rect(10, 20, 30, 40));
546 input_method
->OnCaretBoundsChanged(&mock_text_input_client
);
549 TEST(RemoteInputMethodWinTest
, DispatchKeyEvent_NativeKeyEvent
) {
550 // Basically RemoteInputMethodWin does not handle native keydown event.
552 MockInputMethodDelegate delegate_
;
553 MockTextInputClient mock_text_input_client
;
554 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
556 const MSG wm_keydown
= { NULL
, WM_KEYDOWN
, ui::VKEY_A
};
557 ui::KeyEvent
native_keydown(wm_keydown
, false);
559 // This must not cause a crash.
560 EXPECT_FALSE(input_method
->DispatchKeyEvent(native_keydown
));
561 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
562 EXPECT_TRUE(delegate_
.fabricated_key_events().empty());
564 mock_text_input_client
.Reset();
566 RemoteInputMethodPrivateWin
* private_ptr
=
567 RemoteInputMethodPrivateWin::Get(input_method
.get());
568 ASSERT_TRUE(private_ptr
!= NULL
);
569 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
570 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
572 // TextInputClient is not focused yet here.
574 EXPECT_FALSE(input_method
->DispatchKeyEvent(native_keydown
));
575 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
576 EXPECT_TRUE(delegate_
.fabricated_key_events().empty());
578 mock_text_input_client
.Reset();
580 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
582 // TextInputClient is now focused here.
584 EXPECT_FALSE(input_method
->DispatchKeyEvent(native_keydown
));
585 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
586 EXPECT_TRUE(delegate_
.fabricated_key_events().empty());
588 mock_text_input_client
.Reset();
591 TEST(RemoteInputMethodWinTest
, DispatchKeyEvent_NativeCharEvent
) {
592 // RemoteInputMethodWin handles native char event if possible.
594 MockInputMethodDelegate delegate_
;
595 MockTextInputClient mock_text_input_client
;
596 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
598 const MSG wm_char
= { NULL
, WM_CHAR
, 'A', 0 };
599 ui::KeyEvent
native_char(wm_char
, true);
601 // This must not cause a crash.
602 EXPECT_FALSE(input_method
->DispatchKeyEvent(native_char
));
603 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
604 EXPECT_TRUE(delegate_
.fabricated_key_events().empty());
606 mock_text_input_client
.Reset();
608 RemoteInputMethodPrivateWin
* private_ptr
=
609 RemoteInputMethodPrivateWin::Get(input_method
.get());
610 ASSERT_TRUE(private_ptr
!= NULL
);
611 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
612 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
614 // TextInputClient is not focused yet here.
616 EXPECT_FALSE(input_method
->DispatchKeyEvent(native_char
));
617 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
618 EXPECT_TRUE(delegate_
.fabricated_key_events().empty());
620 mock_text_input_client
.Reset();
622 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
624 // TextInputClient is now focused here.
626 EXPECT_TRUE(input_method
->DispatchKeyEvent(native_char
));
627 EXPECT_EQ(L
"A", mock_text_input_client
.inserted_text());
628 EXPECT_TRUE(delegate_
.fabricated_key_events().empty());
630 mock_text_input_client
.Reset();
633 TEST(RemoteInputMethodWinTest
, DispatchKeyEvent_FabricatedKeyDown
) {
634 // Fabricated non-char event will be delegated to
635 // InputMethodDelegate::DispatchFabricatedKeyEventPostIME as long as the
636 // delegate is installed.
638 MockInputMethodDelegate delegate_
;
639 MockTextInputClient mock_text_input_client
;
640 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
642 ui::KeyEvent
fabricated_keydown(ui::ET_KEY_PRESSED
, ui::VKEY_A
, 0, false);
643 fabricated_keydown
.set_character(L
'A');
645 // This must not cause a crash.
646 EXPECT_TRUE(input_method
->DispatchKeyEvent(fabricated_keydown
));
647 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
648 ASSERT_EQ(1, delegate_
.fabricated_key_events().size());
649 EXPECT_EQ(L
'A', delegate_
.fabricated_key_events()[0]);
651 mock_text_input_client
.Reset();
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
);
659 // TextInputClient is not focused yet here.
661 EXPECT_TRUE(input_method
->DispatchKeyEvent(fabricated_keydown
));
662 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
663 ASSERT_EQ(1, delegate_
.fabricated_key_events().size());
664 EXPECT_EQ(L
'A', delegate_
.fabricated_key_events()[0]);
666 mock_text_input_client
.Reset();
668 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
669 // TextInputClient is now focused here.
671 EXPECT_TRUE(input_method
->DispatchKeyEvent(fabricated_keydown
));
672 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
673 ASSERT_EQ(1, delegate_
.fabricated_key_events().size());
674 EXPECT_EQ(L
'A', delegate_
.fabricated_key_events()[0]);
676 mock_text_input_client
.Reset();
678 input_method
->SetDelegate(NULL
);
679 // RemoteInputMethodDelegateWin is no longer set here.
681 EXPECT_FALSE(input_method
->DispatchKeyEvent(fabricated_keydown
));
682 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
685 TEST(RemoteInputMethodWinTest
, DispatchKeyEvent_FabricatedChar
) {
686 // Note: RemoteInputMethodWin::DispatchKeyEvent should always return true
687 // for fabricated character events.
689 MockInputMethodDelegate delegate_
;
690 MockTextInputClient mock_text_input_client
;
691 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
693 ui::KeyEvent
fabricated_char(ui::ET_KEY_PRESSED
, ui::VKEY_A
, 0, true);
694 fabricated_char
.set_character(L
'A');
696 // This must not cause a crash.
697 EXPECT_TRUE(input_method
->DispatchKeyEvent(fabricated_char
));
698 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
699 EXPECT_TRUE(delegate_
.fabricated_key_events().empty());
701 mock_text_input_client
.Reset();
703 RemoteInputMethodPrivateWin
* private_ptr
=
704 RemoteInputMethodPrivateWin::Get(input_method
.get());
705 ASSERT_TRUE(private_ptr
!= NULL
);
706 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
707 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
709 // TextInputClient is not focused yet here.
711 EXPECT_TRUE(input_method
->DispatchKeyEvent(fabricated_char
));
712 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
713 EXPECT_TRUE(delegate_
.fabricated_key_events().empty());
715 mock_text_input_client
.Reset();
717 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
719 // TextInputClient is now focused here.
721 EXPECT_TRUE(input_method
->DispatchKeyEvent(fabricated_char
));
722 EXPECT_EQ(L
"A", mock_text_input_client
.inserted_text());
723 EXPECT_TRUE(delegate_
.fabricated_key_events().empty());
725 mock_text_input_client
.Reset();
728 TEST(RemoteInputMethodWinTest
, OnCompositionChanged
) {
729 MockInputMethodDelegate delegate_
;
730 MockTextInputClient mock_text_input_client
;
731 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
733 RemoteInputMethodPrivateWin
* private_ptr
=
734 RemoteInputMethodPrivateWin::Get(input_method
.get());
735 ASSERT_TRUE(private_ptr
!= NULL
);
736 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
737 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
739 CompositionText composition_text
;
741 // TextInputClient is not focused yet here.
743 private_ptr
->OnCompositionChanged(composition_text
);
744 EXPECT_EQ(0, mock_text_input_client
.call_count_set_composition_text());
746 mock_text_input_client
.Reset();
748 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
750 // TextInputClient is now focused here.
752 private_ptr
->OnCompositionChanged(composition_text
);
753 EXPECT_EQ(1, mock_text_input_client
.call_count_set_composition_text());
755 mock_text_input_client
.Reset();
758 TEST(RemoteInputMethodWinTest
, OnTextCommitted
) {
759 MockInputMethodDelegate delegate_
;
760 MockTextInputClient mock_text_input_client
;
761 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
763 RemoteInputMethodPrivateWin
* private_ptr
=
764 RemoteInputMethodPrivateWin::Get(input_method
.get());
765 ASSERT_TRUE(private_ptr
!= NULL
);
766 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
767 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
769 base::string16 committed_text
= L
"Hello";
771 // TextInputClient is not focused yet here.
773 mock_text_input_client
.set_text_input_type(TEXT_INPUT_TYPE_TEXT
);
774 private_ptr
->OnTextCommitted(committed_text
);
775 EXPECT_EQ(0, mock_text_input_client
.call_count_insert_char());
776 EXPECT_EQ(0, mock_text_input_client
.call_count_insert_text());
777 EXPECT_EQ(L
"", mock_text_input_client
.inserted_text());
779 mock_text_input_client
.Reset();
781 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
783 // TextInputClient is now focused here.
785 mock_text_input_client
.set_text_input_type(TEXT_INPUT_TYPE_TEXT
);
786 private_ptr
->OnTextCommitted(committed_text
);
787 EXPECT_EQ(0, mock_text_input_client
.call_count_insert_char());
788 EXPECT_EQ(1, mock_text_input_client
.call_count_insert_text());
789 EXPECT_EQ(committed_text
, mock_text_input_client
.inserted_text());
791 mock_text_input_client
.Reset();
793 // When TextInputType is TEXT_INPUT_TYPE_NONE, TextInputClient::InsertText
794 // should not be used.
795 mock_text_input_client
.set_text_input_type(TEXT_INPUT_TYPE_NONE
);
796 private_ptr
->OnTextCommitted(committed_text
);
797 EXPECT_EQ(committed_text
.size(),
798 mock_text_input_client
.call_count_insert_char());
799 EXPECT_EQ(0, mock_text_input_client
.call_count_insert_text());
800 EXPECT_EQ(committed_text
, mock_text_input_client
.inserted_text());
802 mock_text_input_client
.Reset();
805 TEST(RemoteInputMethodWinTest
, OnTextInputStateChanged_Observer
) {
806 DummyTextInputClient text_input_client
;
807 DummyTextInputClient text_input_client_the_other
;
809 MockInputMethodObserver input_method_observer
;
810 MockInputMethodDelegate delegate_
;
811 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
812 InputMethodScopedObserver
scoped_observer(&input_method_observer
);
813 scoped_observer
.Add(input_method
.get());
815 input_method
->SetFocusedTextInputClient(&text_input_client
);
816 ASSERT_EQ(&text_input_client
, input_method
->GetTextInputClient());
817 EXPECT_EQ(1u, input_method_observer
.on_text_input_state_changed());
818 input_method_observer
.Reset();
820 input_method
->SetFocusedTextInputClient(&text_input_client
);
821 ASSERT_EQ(&text_input_client
, input_method
->GetTextInputClient());
822 EXPECT_EQ(0u, input_method_observer
.on_text_input_state_changed());
823 input_method_observer
.Reset();
825 input_method
->SetFocusedTextInputClient(&text_input_client_the_other
);
826 ASSERT_EQ(&text_input_client_the_other
, input_method
->GetTextInputClient());
827 EXPECT_EQ(1u, input_method_observer
.on_text_input_state_changed());
828 input_method_observer
.Reset();
830 input_method
->DetachTextInputClient(&text_input_client_the_other
);
831 ASSERT_TRUE(input_method
->GetTextInputClient() == NULL
);
832 EXPECT_EQ(1u, input_method_observer
.on_text_input_state_changed());
833 input_method_observer
.Reset();
836 TEST(RemoteInputMethodWinTest
, OnInputMethodDestroyed_Observer
) {
837 DummyTextInputClient text_input_client
;
838 DummyTextInputClient text_input_client_the_other
;
840 MockInputMethodObserver input_method_observer
;
841 InputMethodScopedObserver
scoped_observer(&input_method_observer
);
843 MockInputMethodDelegate delegate_
;
844 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
845 input_method
->AddObserver(&input_method_observer
);
847 EXPECT_EQ(0u, input_method_observer
.on_input_method_destroyed_changed());
848 input_method
.reset();
849 EXPECT_EQ(1u, input_method_observer
.on_input_method_destroyed_changed());