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 void SetCompositionText(const ui::CompositionText
& composition
) override
{
90 ++call_count_set_composition_text_
;
92 void InsertChar(base::char16 ch
, int flags
) override
{
93 inserted_text_
.append(1, ch
);
94 ++call_count_insert_char_
;
96 void InsertText(const base::string16
& text
) override
{
97 inserted_text_
.append(text
);
98 ++call_count_insert_text_
;
100 ui::TextInputType
GetTextInputType() const override
{
101 return text_input_type_
;
103 ui::TextInputMode
GetTextInputMode() const override
{
104 return text_input_mode_
;
106 gfx::Rect
GetCaretBounds() const override
{ return caret_bounds_
; }
107 bool GetCompositionCharacterBounds(uint32 index
,
108 gfx::Rect
* rect
) const override
{
109 // Emulate the situation of crbug.com/328237.
110 if (emulate_pepper_flash_
)
112 if (!rect
|| composition_character_bounds_
.size() <= index
)
114 *rect
= composition_character_bounds_
[index
];
117 bool HasCompositionText() const override
{
118 return !composition_character_bounds_
.empty();
120 bool GetCompositionTextRange(gfx::Range
* range
) const override
{
121 if (composition_character_bounds_
.empty())
123 *range
= gfx::Range(0, composition_character_bounds_
.size());
126 void OnCandidateWindowShown() override
{
127 is_candidate_window_shown_called_
= true;
129 void OnCandidateWindowHidden() override
{
130 is_candidate_window_hidden_called_
= true;
133 ui::TextInputType text_input_type_
;
134 ui::TextInputMode text_input_mode_
;
135 gfx::Rect caret_bounds_
;
136 std::vector
<gfx::Rect
> composition_character_bounds_
;
137 base::string16 inserted_text_
;
138 size_t call_count_set_composition_text_
;
139 size_t call_count_insert_char_
;
140 size_t call_count_insert_text_
;
141 bool emulate_pepper_flash_
;
142 bool is_candidate_window_shown_called_
;
143 bool is_candidate_window_hidden_called_
;
144 DISALLOW_COPY_AND_ASSIGN(MockTextInputClient
);
147 class MockInputMethodDelegate
: public internal::InputMethodDelegate
{
149 MockInputMethodDelegate() {}
151 const std::vector
<ui::KeyboardCode
>& fabricated_key_events() const {
152 return fabricated_key_events_
;
155 fabricated_key_events_
.clear();
159 bool DispatchKeyEventPostIME(const ui::KeyEvent
& event
) override
{
160 EXPECT_FALSE(event
.HasNativeEvent());
161 fabricated_key_events_
.push_back(event
.key_code());
165 std::vector
<ui::KeyboardCode
> fabricated_key_events_
;
166 DISALLOW_COPY_AND_ASSIGN(MockInputMethodDelegate
);
169 class MockRemoteInputMethodDelegateWin
170 : public internal::RemoteInputMethodDelegateWin
{
172 MockRemoteInputMethodDelegateWin()
173 : cancel_composition_called_(false),
174 text_input_client_updated_called_(false) {
177 bool cancel_composition_called() const {
178 return cancel_composition_called_
;
180 bool text_input_client_updated_called() const {
181 return text_input_client_updated_called_
;
183 const std::vector
<int32
>& input_scopes() const {
184 return input_scopes_
;
186 const std::vector
<gfx::Rect
>& composition_character_bounds() const {
187 return composition_character_bounds_
;
190 cancel_composition_called_
= false;
191 text_input_client_updated_called_
= false;
192 input_scopes_
.clear();
193 composition_character_bounds_
.clear();
197 void CancelComposition() override
{ cancel_composition_called_
= true; }
199 void OnTextInputClientUpdated(
200 const std::vector
<int32
>& input_scopes
,
201 const std::vector
<gfx::Rect
>& composition_character_bounds
) override
{
202 text_input_client_updated_called_
= true;
203 input_scopes_
= input_scopes
;
204 composition_character_bounds_
= composition_character_bounds
;
207 bool cancel_composition_called_
;
208 bool text_input_client_updated_called_
;
209 std::vector
<int32
> input_scopes_
;
210 std::vector
<gfx::Rect
> composition_character_bounds_
;
211 DISALLOW_COPY_AND_ASSIGN(MockRemoteInputMethodDelegateWin
);
214 class MockInputMethodObserver
: public InputMethodObserver
{
216 MockInputMethodObserver()
217 : on_text_input_state_changed_(0),
218 on_input_method_destroyed_changed_(0) {
220 virtual ~MockInputMethodObserver() {
223 on_text_input_state_changed_
= 0;
224 on_input_method_destroyed_changed_
= 0;
226 size_t on_text_input_state_changed() const {
227 return on_text_input_state_changed_
;
229 size_t on_input_method_destroyed_changed() const {
230 return on_input_method_destroyed_changed_
;
234 // Overriden from InputMethodObserver.
235 void OnTextInputTypeChanged(const TextInputClient
* client
) override
{}
236 void OnFocus() override
{}
237 void OnBlur() override
{}
238 void OnCaretBoundsChanged(const TextInputClient
* client
) override
{}
239 void OnTextInputStateChanged(const TextInputClient
* client
) override
{
240 ++on_text_input_state_changed_
;
242 void OnInputMethodDestroyed(const InputMethod
* client
) override
{
243 ++on_input_method_destroyed_changed_
;
245 void OnShowImeIfNeeded() override
{}
247 size_t on_text_input_state_changed_
;
248 size_t on_input_method_destroyed_changed_
;
249 DISALLOW_COPY_AND_ASSIGN(MockInputMethodObserver
);
252 typedef ScopedObserver
<InputMethod
, InputMethodObserver
>
253 InputMethodScopedObserver
;
255 TEST(RemoteInputMethodWinTest
, RemoteInputMethodPrivateWin
) {
256 InputMethod
* other_ptr
= static_cast<InputMethod
*>(NULL
) + 1;
258 // Use typed NULL to make EXPECT_NE happy until nullptr becomes available.
259 RemoteInputMethodPrivateWin
* kNull
=
260 static_cast<RemoteInputMethodPrivateWin
*>(NULL
);
261 EXPECT_EQ(kNull
, RemoteInputMethodPrivateWin::Get(other_ptr
));
263 MockInputMethodDelegate delegate_
;
264 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
265 EXPECT_NE(kNull
, RemoteInputMethodPrivateWin::Get(input_method
.get()));
267 InputMethod
* dangling_ptr
= input_method
.get();
268 input_method
.reset(NULL
);
269 EXPECT_EQ(kNull
, RemoteInputMethodPrivateWin::Get(dangling_ptr
));
272 TEST(RemoteInputMethodWinTest
, OnInputSourceChanged
) {
273 MockInputMethodDelegate delegate_
;
274 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
275 RemoteInputMethodPrivateWin
* private_ptr
=
276 RemoteInputMethodPrivateWin::Get(input_method
.get());
277 ASSERT_TRUE(private_ptr
!= NULL
);
279 private_ptr
->OnInputSourceChanged(
280 MAKELANGID(LANG_JAPANESE
, SUBLANG_JAPANESE_JAPAN
), true);
281 EXPECT_EQ("ja-JP", input_method
->GetInputLocale());
283 private_ptr
->OnInputSourceChanged(
284 MAKELANGID(LANG_ARABIC
, SUBLANG_ARABIC_QATAR
), true);
285 EXPECT_EQ("ar-QA", input_method
->GetInputLocale());
288 TEST(RemoteInputMethodWinTest
, OnCandidatePopupChanged
) {
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
);
296 EXPECT_FALSE(input_method
->IsCandidatePopupOpen());
298 // RemoteInputMethodWin::OnCandidatePopupChanged can be called even when the
299 // focused text input client is NULL.
300 ASSERT_TRUE(input_method
->GetTextInputClient() == NULL
);
301 private_ptr
->OnCandidatePopupChanged(false);
302 private_ptr
->OnCandidatePopupChanged(true);
304 MockTextInputClient mock_text_input_client
;
305 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
307 ASSERT_FALSE(mock_text_input_client
.is_candidate_window_shown_called());
308 ASSERT_FALSE(mock_text_input_client
.is_candidate_window_hidden_called());
309 mock_text_input_client
.Reset();
311 private_ptr
->OnCandidatePopupChanged(true);
312 EXPECT_TRUE(input_method
->IsCandidatePopupOpen());
313 EXPECT_TRUE(mock_text_input_client
.is_candidate_window_shown_called());
314 EXPECT_FALSE(mock_text_input_client
.is_candidate_window_hidden_called());
316 private_ptr
->OnCandidatePopupChanged(false);
317 EXPECT_FALSE(input_method
->IsCandidatePopupOpen());
318 EXPECT_TRUE(mock_text_input_client
.is_candidate_window_shown_called());
319 EXPECT_TRUE(mock_text_input_client
.is_candidate_window_hidden_called());
322 TEST(RemoteInputMethodWinTest
, CancelComposition
) {
323 MockInputMethodDelegate delegate_
;
324 MockTextInputClient mock_text_input_client
;
325 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
327 // This must not cause a crash.
328 input_method
->CancelComposition(&mock_text_input_client
);
330 RemoteInputMethodPrivateWin
* private_ptr
=
331 RemoteInputMethodPrivateWin::Get(input_method
.get());
332 ASSERT_TRUE(private_ptr
!= NULL
);
333 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
334 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
336 input_method
->CancelComposition(&mock_text_input_client
);
337 EXPECT_FALSE(mock_remote_delegate
.cancel_composition_called());
339 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
340 input_method
->CancelComposition(&mock_text_input_client
);
341 EXPECT_TRUE(mock_remote_delegate
.cancel_composition_called());
344 TEST(RemoteInputMethodWinTest
, SetFocusedTextInputClient
) {
345 MockInputMethodDelegate delegate_
;
346 MockTextInputClient mock_text_input_client
;
347 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
349 mock_text_input_client
.set_caret_bounds(gfx::Rect(10, 0, 10, 20));
350 mock_text_input_client
.set_text_input_type(ui::TEXT_INPUT_TYPE_URL
);
351 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
353 RemoteInputMethodPrivateWin
* private_ptr
=
354 RemoteInputMethodPrivateWin::Get(input_method
.get());
355 ASSERT_TRUE(private_ptr
!= NULL
);
356 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
357 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
359 // Initial state must be synced.
360 EXPECT_TRUE(mock_remote_delegate
.text_input_client_updated_called());
361 ASSERT_EQ(1, mock_remote_delegate
.composition_character_bounds().size());
362 EXPECT_EQ(gfx::Rect(10, 0, 10, 20),
363 mock_remote_delegate
.composition_character_bounds()[0]);
364 ASSERT_EQ(1, mock_remote_delegate
.input_scopes().size());
365 EXPECT_EQ(IS_URL
, mock_remote_delegate
.input_scopes()[0]);
367 // State must be cleared by SetFocusedTextInputClient(NULL).
368 mock_remote_delegate
.Reset();
369 input_method
->SetFocusedTextInputClient(NULL
);
370 EXPECT_TRUE(mock_remote_delegate
.text_input_client_updated_called());
371 EXPECT_TRUE(mock_remote_delegate
.composition_character_bounds().empty());
372 EXPECT_TRUE(mock_remote_delegate
.input_scopes().empty());
375 TEST(RemoteInputMethodWinTest
, DetachTextInputClient
) {
376 MockInputMethodDelegate delegate_
;
377 MockTextInputClient mock_text_input_client
;
378 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
380 mock_text_input_client
.set_caret_bounds(gfx::Rect(10, 0, 10, 20));
381 mock_text_input_client
.set_text_input_type(ui::TEXT_INPUT_TYPE_URL
);
382 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
384 RemoteInputMethodPrivateWin
* private_ptr
=
385 RemoteInputMethodPrivateWin::Get(input_method
.get());
386 ASSERT_TRUE(private_ptr
!= NULL
);
387 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
388 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
390 // Initial state must be synced.
391 EXPECT_TRUE(mock_remote_delegate
.text_input_client_updated_called());
392 ASSERT_EQ(1, mock_remote_delegate
.composition_character_bounds().size());
393 EXPECT_EQ(gfx::Rect(10, 0, 10, 20),
394 mock_remote_delegate
.composition_character_bounds()[0]);
395 ASSERT_EQ(1, mock_remote_delegate
.input_scopes().size());
396 EXPECT_EQ(IS_URL
, mock_remote_delegate
.input_scopes()[0]);
398 // State must be cleared by DetachTextInputClient
399 mock_remote_delegate
.Reset();
400 input_method
->DetachTextInputClient(&mock_text_input_client
);
401 EXPECT_TRUE(mock_remote_delegate
.text_input_client_updated_called());
402 EXPECT_TRUE(mock_remote_delegate
.composition_character_bounds().empty());
403 EXPECT_TRUE(mock_remote_delegate
.input_scopes().empty());
406 TEST(RemoteInputMethodWinTest
, OnCaretBoundsChanged
) {
407 MockInputMethodDelegate delegate_
;
408 MockTextInputClient mock_text_input_client
;
409 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
411 // This must not cause a crash.
412 input_method
->OnCaretBoundsChanged(&mock_text_input_client
);
414 mock_text_input_client
.set_caret_bounds(gfx::Rect(10, 0, 10, 20));
415 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
417 RemoteInputMethodPrivateWin
* private_ptr
=
418 RemoteInputMethodPrivateWin::Get(input_method
.get());
419 ASSERT_TRUE(private_ptr
!= NULL
);
420 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
421 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
423 // Initial state must be synced.
424 EXPECT_TRUE(mock_remote_delegate
.text_input_client_updated_called());
425 ASSERT_EQ(1, mock_remote_delegate
.composition_character_bounds().size());
426 EXPECT_EQ(gfx::Rect(10, 0, 10, 20),
427 mock_remote_delegate
.composition_character_bounds()[0]);
429 // Redundant OnCaretBoundsChanged must be ignored.
430 mock_remote_delegate
.Reset();
431 input_method
->OnCaretBoundsChanged(&mock_text_input_client
);
432 EXPECT_FALSE(mock_remote_delegate
.text_input_client_updated_called());
434 // Check OnCaretBoundsChanged is handled. (w/o composition)
435 mock_remote_delegate
.Reset();
436 mock_text_input_client
.Reset();
437 mock_text_input_client
.set_caret_bounds(gfx::Rect(10, 20, 30, 40));
438 input_method
->OnCaretBoundsChanged(&mock_text_input_client
);
439 EXPECT_TRUE(mock_remote_delegate
.text_input_client_updated_called());
440 ASSERT_EQ(1, mock_remote_delegate
.composition_character_bounds().size());
441 EXPECT_EQ(gfx::Rect(10, 20, 30, 40),
442 mock_remote_delegate
.composition_character_bounds()[0]);
444 // Check OnCaretBoundsChanged is handled. (w/ composition)
446 mock_remote_delegate
.Reset();
447 mock_text_input_client
.Reset();
449 std::vector
<gfx::Rect
> bounds
;
450 bounds
.push_back(gfx::Rect(10, 20, 30, 40));
451 bounds
.push_back(gfx::Rect(40, 30, 20, 10));
452 mock_text_input_client
.set_composition_character_bounds(bounds
);
453 input_method
->OnCaretBoundsChanged(&mock_text_input_client
);
454 EXPECT_TRUE(mock_remote_delegate
.text_input_client_updated_called());
455 EXPECT_EQ(bounds
, mock_remote_delegate
.composition_character_bounds());
459 // Test case against crbug.com/328237.
460 TEST(RemoteInputMethodWinTest
, OnCaretBoundsChangedForPepperFlash
) {
461 MockInputMethodDelegate delegate_
;
462 MockTextInputClient mock_text_input_client
;
463 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
464 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
466 RemoteInputMethodPrivateWin
* private_ptr
=
467 RemoteInputMethodPrivateWin::Get(input_method
.get());
468 ASSERT_TRUE(private_ptr
!= NULL
);
469 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
470 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
472 mock_remote_delegate
.Reset();
473 mock_text_input_client
.Reset();
474 mock_text_input_client
.set_emulate_pepper_flash(true);
476 std::vector
<gfx::Rect
> caret_bounds
;
477 caret_bounds
.push_back(gfx::Rect(5, 15, 25, 35));
478 mock_text_input_client
.set_caret_bounds(caret_bounds
[0]);
480 std::vector
<gfx::Rect
> composition_bounds
;
481 composition_bounds
.push_back(gfx::Rect(10, 20, 30, 40));
482 composition_bounds
.push_back(gfx::Rect(40, 30, 20, 10));
483 mock_text_input_client
.set_composition_character_bounds(composition_bounds
);
484 input_method
->OnCaretBoundsChanged(&mock_text_input_client
);
485 EXPECT_TRUE(mock_remote_delegate
.text_input_client_updated_called());
486 // The caret bounds must be used when
487 // TextInputClient::GetCompositionCharacterBounds failed.
488 EXPECT_EQ(caret_bounds
, mock_remote_delegate
.composition_character_bounds());
491 TEST(RemoteInputMethodWinTest
, OnTextInputTypeChanged
) {
492 MockInputMethodDelegate delegate_
;
493 MockTextInputClient mock_text_input_client
;
494 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
496 // This must not cause a crash.
497 input_method
->OnCaretBoundsChanged(&mock_text_input_client
);
499 mock_text_input_client
.set_text_input_type(ui::TEXT_INPUT_TYPE_URL
);
500 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
502 RemoteInputMethodPrivateWin
* private_ptr
=
503 RemoteInputMethodPrivateWin::Get(input_method
.get());
504 ASSERT_TRUE(private_ptr
!= NULL
);
505 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
506 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
508 // Initial state must be synced.
509 EXPECT_TRUE(mock_remote_delegate
.text_input_client_updated_called());
510 ASSERT_EQ(1, mock_remote_delegate
.input_scopes().size());
511 EXPECT_EQ(IS_URL
, mock_remote_delegate
.input_scopes()[0]);
513 // Check TEXT_INPUT_TYPE_NONE is handled.
514 mock_remote_delegate
.Reset();
515 mock_text_input_client
.Reset();
516 mock_text_input_client
.set_text_input_type(ui::TEXT_INPUT_TYPE_NONE
);
517 mock_text_input_client
.set_text_input_mode(ui::TEXT_INPUT_MODE_KATAKANA
);
518 input_method
->OnTextInputTypeChanged(&mock_text_input_client
);
519 EXPECT_TRUE(mock_remote_delegate
.text_input_client_updated_called());
520 EXPECT_TRUE(mock_remote_delegate
.input_scopes().empty());
522 // Redundant OnTextInputTypeChanged must be ignored.
523 mock_remote_delegate
.Reset();
524 input_method
->OnTextInputTypeChanged(&mock_text_input_client
);
525 EXPECT_FALSE(mock_remote_delegate
.text_input_client_updated_called());
527 mock_remote_delegate
.Reset();
528 mock_text_input_client
.Reset();
529 mock_text_input_client
.set_caret_bounds(gfx::Rect(10, 20, 30, 40));
530 input_method
->OnCaretBoundsChanged(&mock_text_input_client
);
533 TEST(RemoteInputMethodWinTest
, DispatchKeyEvent_NativeKeyEvent
) {
534 // Basically RemoteInputMethodWin does not handle native keydown event.
536 MockInputMethodDelegate delegate_
;
537 MockTextInputClient mock_text_input_client
;
538 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
540 const MSG wm_keydown
= { NULL
, WM_KEYDOWN
, ui::VKEY_A
};
541 ui::KeyEvent
native_keydown(wm_keydown
);
543 // This must not cause a crash.
544 EXPECT_FALSE(input_method
->DispatchKeyEvent(native_keydown
));
545 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
546 EXPECT_TRUE(delegate_
.fabricated_key_events().empty());
548 mock_text_input_client
.Reset();
550 RemoteInputMethodPrivateWin
* private_ptr
=
551 RemoteInputMethodPrivateWin::Get(input_method
.get());
552 ASSERT_TRUE(private_ptr
!= NULL
);
553 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
554 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
556 // TextInputClient is not focused yet here.
558 EXPECT_FALSE(input_method
->DispatchKeyEvent(native_keydown
));
559 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
560 EXPECT_TRUE(delegate_
.fabricated_key_events().empty());
562 mock_text_input_client
.Reset();
564 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
566 // TextInputClient is now focused here.
568 EXPECT_FALSE(input_method
->DispatchKeyEvent(native_keydown
));
569 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
570 EXPECT_TRUE(delegate_
.fabricated_key_events().empty());
572 mock_text_input_client
.Reset();
575 TEST(RemoteInputMethodWinTest
, DispatchKeyEvent_NativeCharEvent
) {
576 // RemoteInputMethodWin handles native char event if possible.
578 MockInputMethodDelegate delegate_
;
579 MockTextInputClient mock_text_input_client
;
580 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
582 const MSG wm_char
= { NULL
, WM_CHAR
, 'A', 0 };
583 ui::KeyEvent
native_char(wm_char
);
585 // This must not cause a crash.
586 EXPECT_FALSE(input_method
->DispatchKeyEvent(native_char
));
587 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
588 EXPECT_TRUE(delegate_
.fabricated_key_events().empty());
590 mock_text_input_client
.Reset();
592 RemoteInputMethodPrivateWin
* private_ptr
=
593 RemoteInputMethodPrivateWin::Get(input_method
.get());
594 ASSERT_TRUE(private_ptr
!= NULL
);
595 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
596 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
598 // TextInputClient is not focused yet here.
600 EXPECT_FALSE(input_method
->DispatchKeyEvent(native_char
));
601 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
602 EXPECT_TRUE(delegate_
.fabricated_key_events().empty());
604 mock_text_input_client
.Reset();
606 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
608 // TextInputClient is now focused here.
610 EXPECT_TRUE(input_method
->DispatchKeyEvent(native_char
));
611 EXPECT_EQ(L
"A", mock_text_input_client
.inserted_text());
612 EXPECT_TRUE(delegate_
.fabricated_key_events().empty());
614 mock_text_input_client
.Reset();
617 TEST(RemoteInputMethodWinTest
, DispatchKeyEvent_FabricatedKeyDown
) {
618 // Fabricated non-char event will be delegated to
619 // InputMethodDelegate::DispatchFabricatedKeyEventPostIME as long as the
620 // delegate is installed.
622 MockInputMethodDelegate delegate_
;
623 MockTextInputClient mock_text_input_client
;
624 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
626 ui::KeyEvent
fabricated_keydown(ui::ET_KEY_PRESSED
, ui::VKEY_A
, ui::EF_NONE
);
627 fabricated_keydown
.set_character(L
'A');
629 // This must not cause a crash.
630 EXPECT_TRUE(input_method
->DispatchKeyEvent(fabricated_keydown
));
631 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
632 ASSERT_EQ(1, delegate_
.fabricated_key_events().size());
633 EXPECT_EQ(L
'A', delegate_
.fabricated_key_events()[0]);
635 mock_text_input_client
.Reset();
637 RemoteInputMethodPrivateWin
* private_ptr
=
638 RemoteInputMethodPrivateWin::Get(input_method
.get());
639 ASSERT_TRUE(private_ptr
!= NULL
);
640 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
641 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
643 // TextInputClient is not focused yet here.
645 EXPECT_TRUE(input_method
->DispatchKeyEvent(fabricated_keydown
));
646 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
647 ASSERT_EQ(1, delegate_
.fabricated_key_events().size());
648 EXPECT_EQ(L
'A', delegate_
.fabricated_key_events()[0]);
650 mock_text_input_client
.Reset();
652 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
653 // TextInputClient is now focused here.
655 EXPECT_TRUE(input_method
->DispatchKeyEvent(fabricated_keydown
));
656 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
657 ASSERT_EQ(1, delegate_
.fabricated_key_events().size());
658 EXPECT_EQ(L
'A', delegate_
.fabricated_key_events()[0]);
660 mock_text_input_client
.Reset();
662 input_method
->SetDelegate(NULL
);
663 // RemoteInputMethodDelegateWin is no longer set here.
665 EXPECT_FALSE(input_method
->DispatchKeyEvent(fabricated_keydown
));
666 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
669 TEST(RemoteInputMethodWinTest
, DispatchKeyEvent_FabricatedChar
) {
670 // Note: RemoteInputMethodWin::DispatchKeyEvent should always return true
671 // for fabricated character events.
673 MockInputMethodDelegate delegate_
;
674 MockTextInputClient mock_text_input_client
;
675 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
677 ui::KeyEvent
fabricated_char(L
'A', ui::VKEY_A
, ui::EF_NONE
);
679 // This must not cause a crash.
680 EXPECT_TRUE(input_method
->DispatchKeyEvent(fabricated_char
));
681 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
682 EXPECT_TRUE(delegate_
.fabricated_key_events().empty());
684 mock_text_input_client
.Reset();
686 RemoteInputMethodPrivateWin
* private_ptr
=
687 RemoteInputMethodPrivateWin::Get(input_method
.get());
688 ASSERT_TRUE(private_ptr
!= NULL
);
689 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
690 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
692 // TextInputClient is not focused yet here.
694 EXPECT_TRUE(input_method
->DispatchKeyEvent(fabricated_char
));
695 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
696 EXPECT_TRUE(delegate_
.fabricated_key_events().empty());
698 mock_text_input_client
.Reset();
700 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
702 // TextInputClient is now focused here.
704 EXPECT_TRUE(input_method
->DispatchKeyEvent(fabricated_char
));
705 EXPECT_EQ(L
"A", mock_text_input_client
.inserted_text());
706 EXPECT_TRUE(delegate_
.fabricated_key_events().empty());
708 mock_text_input_client
.Reset();
711 TEST(RemoteInputMethodWinTest
, OnCompositionChanged
) {
712 MockInputMethodDelegate delegate_
;
713 MockTextInputClient mock_text_input_client
;
714 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
716 RemoteInputMethodPrivateWin
* private_ptr
=
717 RemoteInputMethodPrivateWin::Get(input_method
.get());
718 ASSERT_TRUE(private_ptr
!= NULL
);
719 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
720 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
722 CompositionText composition_text
;
724 // TextInputClient is not focused yet here.
726 private_ptr
->OnCompositionChanged(composition_text
);
727 EXPECT_EQ(0, mock_text_input_client
.call_count_set_composition_text());
729 mock_text_input_client
.Reset();
731 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
733 // TextInputClient is now focused here.
735 private_ptr
->OnCompositionChanged(composition_text
);
736 EXPECT_EQ(1, mock_text_input_client
.call_count_set_composition_text());
738 mock_text_input_client
.Reset();
741 TEST(RemoteInputMethodWinTest
, OnTextCommitted
) {
742 MockInputMethodDelegate delegate_
;
743 MockTextInputClient mock_text_input_client
;
744 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
746 RemoteInputMethodPrivateWin
* private_ptr
=
747 RemoteInputMethodPrivateWin::Get(input_method
.get());
748 ASSERT_TRUE(private_ptr
!= NULL
);
749 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
750 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
752 base::string16 committed_text
= L
"Hello";
754 // TextInputClient is not focused yet here.
756 mock_text_input_client
.set_text_input_type(TEXT_INPUT_TYPE_TEXT
);
757 private_ptr
->OnTextCommitted(committed_text
);
758 EXPECT_EQ(0, mock_text_input_client
.call_count_insert_char());
759 EXPECT_EQ(0, mock_text_input_client
.call_count_insert_text());
760 EXPECT_EQ(L
"", mock_text_input_client
.inserted_text());
762 mock_text_input_client
.Reset();
764 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
766 // TextInputClient is now focused here.
768 mock_text_input_client
.set_text_input_type(TEXT_INPUT_TYPE_TEXT
);
769 private_ptr
->OnTextCommitted(committed_text
);
770 EXPECT_EQ(0, mock_text_input_client
.call_count_insert_char());
771 EXPECT_EQ(1, mock_text_input_client
.call_count_insert_text());
772 EXPECT_EQ(committed_text
, mock_text_input_client
.inserted_text());
774 mock_text_input_client
.Reset();
776 // When TextInputType is TEXT_INPUT_TYPE_NONE, TextInputClient::InsertText
777 // should not be used.
778 mock_text_input_client
.set_text_input_type(TEXT_INPUT_TYPE_NONE
);
779 private_ptr
->OnTextCommitted(committed_text
);
780 EXPECT_EQ(committed_text
.size(),
781 mock_text_input_client
.call_count_insert_char());
782 EXPECT_EQ(0, mock_text_input_client
.call_count_insert_text());
783 EXPECT_EQ(committed_text
, mock_text_input_client
.inserted_text());
785 mock_text_input_client
.Reset();
788 TEST(RemoteInputMethodWinTest
, OnTextInputStateChanged_Observer
) {
789 DummyTextInputClient text_input_client
;
790 DummyTextInputClient text_input_client_the_other
;
792 MockInputMethodObserver input_method_observer
;
793 MockInputMethodDelegate delegate_
;
794 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
795 InputMethodScopedObserver
scoped_observer(&input_method_observer
);
796 scoped_observer
.Add(input_method
.get());
798 input_method
->SetFocusedTextInputClient(&text_input_client
);
799 ASSERT_EQ(&text_input_client
, input_method
->GetTextInputClient());
800 EXPECT_EQ(1u, input_method_observer
.on_text_input_state_changed());
801 input_method_observer
.Reset();
803 input_method
->SetFocusedTextInputClient(&text_input_client
);
804 ASSERT_EQ(&text_input_client
, input_method
->GetTextInputClient());
805 EXPECT_EQ(0u, input_method_observer
.on_text_input_state_changed());
806 input_method_observer
.Reset();
808 input_method
->SetFocusedTextInputClient(&text_input_client_the_other
);
809 ASSERT_EQ(&text_input_client_the_other
, input_method
->GetTextInputClient());
810 EXPECT_EQ(1u, input_method_observer
.on_text_input_state_changed());
811 input_method_observer
.Reset();
813 input_method
->DetachTextInputClient(&text_input_client_the_other
);
814 ASSERT_TRUE(input_method
->GetTextInputClient() == NULL
);
815 EXPECT_EQ(1u, input_method_observer
.on_text_input_state_changed());
816 input_method_observer
.Reset();
819 TEST(RemoteInputMethodWinTest
, OnInputMethodDestroyed_Observer
) {
820 DummyTextInputClient text_input_client
;
821 DummyTextInputClient text_input_client_the_other
;
823 MockInputMethodObserver input_method_observer
;
824 InputMethodScopedObserver
scoped_observer(&input_method_observer
);
826 MockInputMethodDelegate delegate_
;
827 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
828 input_method
->AddObserver(&input_method_observer
);
830 EXPECT_EQ(0u, input_method_observer
.on_input_method_destroyed_changed());
831 input_method
.reset();
832 EXPECT_EQ(1u, input_method_observer
.on_input_method_destroyed_changed());