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 ~MockInputMethodObserver() override
{}
222 on_text_input_state_changed_
= 0;
223 on_input_method_destroyed_changed_
= 0;
225 size_t on_text_input_state_changed() const {
226 return on_text_input_state_changed_
;
228 size_t on_input_method_destroyed_changed() const {
229 return on_input_method_destroyed_changed_
;
233 // Overriden from InputMethodObserver.
234 void OnTextInputTypeChanged(const TextInputClient
* client
) override
{}
235 void OnFocus() override
{}
236 void OnBlur() override
{}
237 void OnCaretBoundsChanged(const TextInputClient
* client
) override
{}
238 void OnTextInputStateChanged(const TextInputClient
* client
) override
{
239 ++on_text_input_state_changed_
;
241 void OnInputMethodDestroyed(const InputMethod
* client
) override
{
242 ++on_input_method_destroyed_changed_
;
244 void OnShowImeIfNeeded() override
{}
246 size_t on_text_input_state_changed_
;
247 size_t on_input_method_destroyed_changed_
;
248 DISALLOW_COPY_AND_ASSIGN(MockInputMethodObserver
);
251 typedef ScopedObserver
<InputMethod
, InputMethodObserver
>
252 InputMethodScopedObserver
;
254 TEST(RemoteInputMethodWinTest
, RemoteInputMethodPrivateWin
) {
255 InputMethod
* other_ptr
= static_cast<InputMethod
*>(NULL
) + 1;
257 // Use typed NULL to make EXPECT_NE happy until nullptr becomes available.
258 RemoteInputMethodPrivateWin
* kNull
=
259 static_cast<RemoteInputMethodPrivateWin
*>(NULL
);
260 EXPECT_EQ(kNull
, RemoteInputMethodPrivateWin::Get(other_ptr
));
262 MockInputMethodDelegate delegate_
;
263 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
264 EXPECT_NE(kNull
, RemoteInputMethodPrivateWin::Get(input_method
.get()));
266 InputMethod
* dangling_ptr
= input_method
.get();
267 input_method
.reset(NULL
);
268 EXPECT_EQ(kNull
, RemoteInputMethodPrivateWin::Get(dangling_ptr
));
271 TEST(RemoteInputMethodWinTest
, OnInputSourceChanged
) {
272 MockInputMethodDelegate delegate_
;
273 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
274 RemoteInputMethodPrivateWin
* private_ptr
=
275 RemoteInputMethodPrivateWin::Get(input_method
.get());
276 ASSERT_TRUE(private_ptr
!= NULL
);
278 private_ptr
->OnInputSourceChanged(
279 MAKELANGID(LANG_JAPANESE
, SUBLANG_JAPANESE_JAPAN
), true);
280 EXPECT_EQ("ja-JP", input_method
->GetInputLocale());
282 private_ptr
->OnInputSourceChanged(
283 MAKELANGID(LANG_ARABIC
, SUBLANG_ARABIC_QATAR
), true);
284 EXPECT_EQ("ar-QA", input_method
->GetInputLocale());
287 TEST(RemoteInputMethodWinTest
, OnCandidatePopupChanged
) {
288 MockInputMethodDelegate delegate_
;
289 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
290 RemoteInputMethodPrivateWin
* private_ptr
=
291 RemoteInputMethodPrivateWin::Get(input_method
.get());
292 ASSERT_TRUE(private_ptr
!= NULL
);
295 EXPECT_FALSE(input_method
->IsCandidatePopupOpen());
297 // RemoteInputMethodWin::OnCandidatePopupChanged can be called even when the
298 // focused text input client is NULL.
299 ASSERT_TRUE(input_method
->GetTextInputClient() == NULL
);
300 private_ptr
->OnCandidatePopupChanged(false);
301 private_ptr
->OnCandidatePopupChanged(true);
303 MockTextInputClient mock_text_input_client
;
304 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
306 ASSERT_FALSE(mock_text_input_client
.is_candidate_window_shown_called());
307 ASSERT_FALSE(mock_text_input_client
.is_candidate_window_hidden_called());
308 mock_text_input_client
.Reset();
310 private_ptr
->OnCandidatePopupChanged(true);
311 EXPECT_TRUE(input_method
->IsCandidatePopupOpen());
312 EXPECT_TRUE(mock_text_input_client
.is_candidate_window_shown_called());
313 EXPECT_FALSE(mock_text_input_client
.is_candidate_window_hidden_called());
315 private_ptr
->OnCandidatePopupChanged(false);
316 EXPECT_FALSE(input_method
->IsCandidatePopupOpen());
317 EXPECT_TRUE(mock_text_input_client
.is_candidate_window_shown_called());
318 EXPECT_TRUE(mock_text_input_client
.is_candidate_window_hidden_called());
321 TEST(RemoteInputMethodWinTest
, CancelComposition
) {
322 MockInputMethodDelegate delegate_
;
323 MockTextInputClient mock_text_input_client
;
324 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
326 // This must not cause a crash.
327 input_method
->CancelComposition(&mock_text_input_client
);
329 RemoteInputMethodPrivateWin
* private_ptr
=
330 RemoteInputMethodPrivateWin::Get(input_method
.get());
331 ASSERT_TRUE(private_ptr
!= NULL
);
332 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
333 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
335 input_method
->CancelComposition(&mock_text_input_client
);
336 EXPECT_FALSE(mock_remote_delegate
.cancel_composition_called());
338 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
339 input_method
->CancelComposition(&mock_text_input_client
);
340 EXPECT_TRUE(mock_remote_delegate
.cancel_composition_called());
343 TEST(RemoteInputMethodWinTest
, SetFocusedTextInputClient
) {
344 MockInputMethodDelegate delegate_
;
345 MockTextInputClient mock_text_input_client
;
346 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
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
);
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
);
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]);
366 // State must be cleared by SetFocusedTextInputClient(NULL).
367 mock_remote_delegate
.Reset();
368 input_method
->SetFocusedTextInputClient(NULL
);
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());
374 TEST(RemoteInputMethodWinTest
, DetachTextInputClient
) {
375 MockInputMethodDelegate delegate_
;
376 MockTextInputClient mock_text_input_client
;
377 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
379 mock_text_input_client
.set_caret_bounds(gfx::Rect(10, 0, 10, 20));
380 mock_text_input_client
.set_text_input_type(ui::TEXT_INPUT_TYPE_URL
);
381 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
383 RemoteInputMethodPrivateWin
* private_ptr
=
384 RemoteInputMethodPrivateWin::Get(input_method
.get());
385 ASSERT_TRUE(private_ptr
!= NULL
);
386 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
387 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
389 // Initial state must be synced.
390 EXPECT_TRUE(mock_remote_delegate
.text_input_client_updated_called());
391 ASSERT_EQ(1, mock_remote_delegate
.composition_character_bounds().size());
392 EXPECT_EQ(gfx::Rect(10, 0, 10, 20),
393 mock_remote_delegate
.composition_character_bounds()[0]);
394 ASSERT_EQ(1, mock_remote_delegate
.input_scopes().size());
395 EXPECT_EQ(IS_URL
, mock_remote_delegate
.input_scopes()[0]);
397 // State must be cleared by DetachTextInputClient
398 mock_remote_delegate
.Reset();
399 input_method
->DetachTextInputClient(&mock_text_input_client
);
400 EXPECT_TRUE(mock_remote_delegate
.text_input_client_updated_called());
401 EXPECT_TRUE(mock_remote_delegate
.composition_character_bounds().empty());
402 EXPECT_TRUE(mock_remote_delegate
.input_scopes().empty());
405 TEST(RemoteInputMethodWinTest
, OnCaretBoundsChanged
) {
406 MockInputMethodDelegate delegate_
;
407 MockTextInputClient mock_text_input_client
;
408 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
410 // This must not cause a crash.
411 input_method
->OnCaretBoundsChanged(&mock_text_input_client
);
413 mock_text_input_client
.set_caret_bounds(gfx::Rect(10, 0, 10, 20));
414 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
416 RemoteInputMethodPrivateWin
* private_ptr
=
417 RemoteInputMethodPrivateWin::Get(input_method
.get());
418 ASSERT_TRUE(private_ptr
!= NULL
);
419 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
420 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
422 // Initial state must be synced.
423 EXPECT_TRUE(mock_remote_delegate
.text_input_client_updated_called());
424 ASSERT_EQ(1, mock_remote_delegate
.composition_character_bounds().size());
425 EXPECT_EQ(gfx::Rect(10, 0, 10, 20),
426 mock_remote_delegate
.composition_character_bounds()[0]);
428 // Redundant OnCaretBoundsChanged must be ignored.
429 mock_remote_delegate
.Reset();
430 input_method
->OnCaretBoundsChanged(&mock_text_input_client
);
431 EXPECT_FALSE(mock_remote_delegate
.text_input_client_updated_called());
433 // Check OnCaretBoundsChanged is handled. (w/o composition)
434 mock_remote_delegate
.Reset();
435 mock_text_input_client
.Reset();
436 mock_text_input_client
.set_caret_bounds(gfx::Rect(10, 20, 30, 40));
437 input_method
->OnCaretBoundsChanged(&mock_text_input_client
);
438 EXPECT_TRUE(mock_remote_delegate
.text_input_client_updated_called());
439 ASSERT_EQ(1, mock_remote_delegate
.composition_character_bounds().size());
440 EXPECT_EQ(gfx::Rect(10, 20, 30, 40),
441 mock_remote_delegate
.composition_character_bounds()[0]);
443 // Check OnCaretBoundsChanged is handled. (w/ composition)
445 mock_remote_delegate
.Reset();
446 mock_text_input_client
.Reset();
448 std::vector
<gfx::Rect
> bounds
;
449 bounds
.push_back(gfx::Rect(10, 20, 30, 40));
450 bounds
.push_back(gfx::Rect(40, 30, 20, 10));
451 mock_text_input_client
.set_composition_character_bounds(bounds
);
452 input_method
->OnCaretBoundsChanged(&mock_text_input_client
);
453 EXPECT_TRUE(mock_remote_delegate
.text_input_client_updated_called());
454 EXPECT_EQ(bounds
, mock_remote_delegate
.composition_character_bounds());
458 // Test case against crbug.com/328237.
459 TEST(RemoteInputMethodWinTest
, OnCaretBoundsChangedForPepperFlash
) {
460 MockInputMethodDelegate delegate_
;
461 MockTextInputClient mock_text_input_client
;
462 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
463 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
465 RemoteInputMethodPrivateWin
* private_ptr
=
466 RemoteInputMethodPrivateWin::Get(input_method
.get());
467 ASSERT_TRUE(private_ptr
!= NULL
);
468 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
469 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
471 mock_remote_delegate
.Reset();
472 mock_text_input_client
.Reset();
473 mock_text_input_client
.set_emulate_pepper_flash(true);
475 std::vector
<gfx::Rect
> caret_bounds
;
476 caret_bounds
.push_back(gfx::Rect(5, 15, 25, 35));
477 mock_text_input_client
.set_caret_bounds(caret_bounds
[0]);
479 std::vector
<gfx::Rect
> composition_bounds
;
480 composition_bounds
.push_back(gfx::Rect(10, 20, 30, 40));
481 composition_bounds
.push_back(gfx::Rect(40, 30, 20, 10));
482 mock_text_input_client
.set_composition_character_bounds(composition_bounds
);
483 input_method
->OnCaretBoundsChanged(&mock_text_input_client
);
484 EXPECT_TRUE(mock_remote_delegate
.text_input_client_updated_called());
485 // The caret bounds must be used when
486 // TextInputClient::GetCompositionCharacterBounds failed.
487 EXPECT_EQ(caret_bounds
, mock_remote_delegate
.composition_character_bounds());
490 TEST(RemoteInputMethodWinTest
, OnTextInputTypeChanged
) {
491 MockInputMethodDelegate delegate_
;
492 MockTextInputClient mock_text_input_client
;
493 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
495 // This must not cause a crash.
496 input_method
->OnCaretBoundsChanged(&mock_text_input_client
);
498 mock_text_input_client
.set_text_input_type(ui::TEXT_INPUT_TYPE_URL
);
499 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
501 RemoteInputMethodPrivateWin
* private_ptr
=
502 RemoteInputMethodPrivateWin::Get(input_method
.get());
503 ASSERT_TRUE(private_ptr
!= NULL
);
504 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
505 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
507 // Initial state must be synced.
508 EXPECT_TRUE(mock_remote_delegate
.text_input_client_updated_called());
509 ASSERT_EQ(1, mock_remote_delegate
.input_scopes().size());
510 EXPECT_EQ(IS_URL
, mock_remote_delegate
.input_scopes()[0]);
512 // Check TEXT_INPUT_TYPE_NONE is handled.
513 mock_remote_delegate
.Reset();
514 mock_text_input_client
.Reset();
515 mock_text_input_client
.set_text_input_type(ui::TEXT_INPUT_TYPE_NONE
);
516 mock_text_input_client
.set_text_input_mode(ui::TEXT_INPUT_MODE_KATAKANA
);
517 input_method
->OnTextInputTypeChanged(&mock_text_input_client
);
518 EXPECT_TRUE(mock_remote_delegate
.text_input_client_updated_called());
519 EXPECT_TRUE(mock_remote_delegate
.input_scopes().empty());
521 // Redundant OnTextInputTypeChanged must be ignored.
522 mock_remote_delegate
.Reset();
523 input_method
->OnTextInputTypeChanged(&mock_text_input_client
);
524 EXPECT_FALSE(mock_remote_delegate
.text_input_client_updated_called());
526 mock_remote_delegate
.Reset();
527 mock_text_input_client
.Reset();
528 mock_text_input_client
.set_caret_bounds(gfx::Rect(10, 20, 30, 40));
529 input_method
->OnCaretBoundsChanged(&mock_text_input_client
);
532 TEST(RemoteInputMethodWinTest
, DispatchKeyEvent_NativeKeyEvent
) {
533 // Basically RemoteInputMethodWin does not handle native keydown event.
535 MockInputMethodDelegate delegate_
;
536 MockTextInputClient mock_text_input_client
;
537 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
539 const MSG wm_keydown
= { NULL
, WM_KEYDOWN
, ui::VKEY_A
};
540 ui::KeyEvent
native_keydown(wm_keydown
);
542 // This must not cause a crash.
543 EXPECT_FALSE(input_method
->DispatchKeyEvent(native_keydown
));
544 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
545 EXPECT_TRUE(delegate_
.fabricated_key_events().empty());
547 mock_text_input_client
.Reset();
549 RemoteInputMethodPrivateWin
* private_ptr
=
550 RemoteInputMethodPrivateWin::Get(input_method
.get());
551 ASSERT_TRUE(private_ptr
!= NULL
);
552 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
553 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
555 // TextInputClient is not focused yet here.
557 EXPECT_FALSE(input_method
->DispatchKeyEvent(native_keydown
));
558 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
559 EXPECT_TRUE(delegate_
.fabricated_key_events().empty());
561 mock_text_input_client
.Reset();
563 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
565 // TextInputClient is now focused here.
567 EXPECT_FALSE(input_method
->DispatchKeyEvent(native_keydown
));
568 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
569 EXPECT_TRUE(delegate_
.fabricated_key_events().empty());
571 mock_text_input_client
.Reset();
574 TEST(RemoteInputMethodWinTest
, DispatchKeyEvent_NativeCharEvent
) {
575 // RemoteInputMethodWin handles native char event if possible.
577 MockInputMethodDelegate delegate_
;
578 MockTextInputClient mock_text_input_client
;
579 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
581 const MSG wm_char
= { NULL
, WM_CHAR
, 'A', 0 };
582 ui::KeyEvent
native_char(wm_char
);
584 // This must not cause a crash.
585 EXPECT_FALSE(input_method
->DispatchKeyEvent(native_char
));
586 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
587 EXPECT_TRUE(delegate_
.fabricated_key_events().empty());
589 mock_text_input_client
.Reset();
591 RemoteInputMethodPrivateWin
* private_ptr
=
592 RemoteInputMethodPrivateWin::Get(input_method
.get());
593 ASSERT_TRUE(private_ptr
!= NULL
);
594 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
595 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
597 // TextInputClient is not focused yet here.
599 EXPECT_FALSE(input_method
->DispatchKeyEvent(native_char
));
600 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
601 EXPECT_TRUE(delegate_
.fabricated_key_events().empty());
603 mock_text_input_client
.Reset();
605 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
607 // TextInputClient is now focused here.
609 EXPECT_TRUE(input_method
->DispatchKeyEvent(native_char
));
610 EXPECT_EQ(L
"A", mock_text_input_client
.inserted_text());
611 EXPECT_TRUE(delegate_
.fabricated_key_events().empty());
613 mock_text_input_client
.Reset();
616 TEST(RemoteInputMethodWinTest
, DispatchKeyEvent_FabricatedKeyDown
) {
617 // Fabricated non-char event will be delegated to
618 // InputMethodDelegate::DispatchFabricatedKeyEventPostIME as long as the
619 // delegate is installed.
621 MockInputMethodDelegate delegate_
;
622 MockTextInputClient mock_text_input_client
;
623 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
625 ui::KeyEvent
fabricated_keydown(ui::ET_KEY_PRESSED
, ui::VKEY_A
, ui::EF_NONE
);
626 fabricated_keydown
.set_character(L
'A');
628 // This must not cause a crash.
629 EXPECT_TRUE(input_method
->DispatchKeyEvent(fabricated_keydown
));
630 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
631 ASSERT_EQ(1, delegate_
.fabricated_key_events().size());
632 EXPECT_EQ(L
'A', delegate_
.fabricated_key_events()[0]);
634 mock_text_input_client
.Reset();
636 RemoteInputMethodPrivateWin
* private_ptr
=
637 RemoteInputMethodPrivateWin::Get(input_method
.get());
638 ASSERT_TRUE(private_ptr
!= NULL
);
639 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
640 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
642 // TextInputClient is not focused yet here.
644 EXPECT_TRUE(input_method
->DispatchKeyEvent(fabricated_keydown
));
645 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
646 ASSERT_EQ(1, delegate_
.fabricated_key_events().size());
647 EXPECT_EQ(L
'A', delegate_
.fabricated_key_events()[0]);
649 mock_text_input_client
.Reset();
651 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
652 // TextInputClient is now focused here.
654 EXPECT_TRUE(input_method
->DispatchKeyEvent(fabricated_keydown
));
655 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
656 ASSERT_EQ(1, delegate_
.fabricated_key_events().size());
657 EXPECT_EQ(L
'A', delegate_
.fabricated_key_events()[0]);
659 mock_text_input_client
.Reset();
661 input_method
->SetDelegate(NULL
);
662 // RemoteInputMethodDelegateWin is no longer set here.
664 EXPECT_FALSE(input_method
->DispatchKeyEvent(fabricated_keydown
));
665 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
668 TEST(RemoteInputMethodWinTest
, DispatchKeyEvent_FabricatedChar
) {
669 // Note: RemoteInputMethodWin::DispatchKeyEvent should always return true
670 // for fabricated character events.
672 MockInputMethodDelegate delegate_
;
673 MockTextInputClient mock_text_input_client
;
674 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
676 ui::KeyEvent
fabricated_char(L
'A', ui::VKEY_A
, ui::EF_NONE
);
678 // This must not cause a crash.
679 EXPECT_TRUE(input_method
->DispatchKeyEvent(fabricated_char
));
680 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
681 EXPECT_TRUE(delegate_
.fabricated_key_events().empty());
683 mock_text_input_client
.Reset();
685 RemoteInputMethodPrivateWin
* private_ptr
=
686 RemoteInputMethodPrivateWin::Get(input_method
.get());
687 ASSERT_TRUE(private_ptr
!= NULL
);
688 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
689 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
691 // TextInputClient is not focused yet here.
693 EXPECT_TRUE(input_method
->DispatchKeyEvent(fabricated_char
));
694 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
695 EXPECT_TRUE(delegate_
.fabricated_key_events().empty());
697 mock_text_input_client
.Reset();
699 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
701 // TextInputClient is now focused here.
703 EXPECT_TRUE(input_method
->DispatchKeyEvent(fabricated_char
));
704 EXPECT_EQ(L
"A", mock_text_input_client
.inserted_text());
705 EXPECT_TRUE(delegate_
.fabricated_key_events().empty());
707 mock_text_input_client
.Reset();
710 TEST(RemoteInputMethodWinTest
, OnCompositionChanged
) {
711 MockInputMethodDelegate delegate_
;
712 MockTextInputClient mock_text_input_client
;
713 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
715 RemoteInputMethodPrivateWin
* private_ptr
=
716 RemoteInputMethodPrivateWin::Get(input_method
.get());
717 ASSERT_TRUE(private_ptr
!= NULL
);
718 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
719 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
721 CompositionText composition_text
;
723 // TextInputClient is not focused yet here.
725 private_ptr
->OnCompositionChanged(composition_text
);
726 EXPECT_EQ(0, mock_text_input_client
.call_count_set_composition_text());
728 mock_text_input_client
.Reset();
730 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
732 // TextInputClient is now focused here.
734 private_ptr
->OnCompositionChanged(composition_text
);
735 EXPECT_EQ(1, mock_text_input_client
.call_count_set_composition_text());
737 mock_text_input_client
.Reset();
740 TEST(RemoteInputMethodWinTest
, OnTextCommitted
) {
741 MockInputMethodDelegate delegate_
;
742 MockTextInputClient mock_text_input_client
;
743 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
745 RemoteInputMethodPrivateWin
* private_ptr
=
746 RemoteInputMethodPrivateWin::Get(input_method
.get());
747 ASSERT_TRUE(private_ptr
!= NULL
);
748 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
749 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
751 base::string16 committed_text
= L
"Hello";
753 // TextInputClient is not focused yet here.
755 mock_text_input_client
.set_text_input_type(TEXT_INPUT_TYPE_TEXT
);
756 private_ptr
->OnTextCommitted(committed_text
);
757 EXPECT_EQ(0, mock_text_input_client
.call_count_insert_char());
758 EXPECT_EQ(0, mock_text_input_client
.call_count_insert_text());
759 EXPECT_EQ(L
"", mock_text_input_client
.inserted_text());
761 mock_text_input_client
.Reset();
763 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
765 // TextInputClient is now focused here.
767 mock_text_input_client
.set_text_input_type(TEXT_INPUT_TYPE_TEXT
);
768 private_ptr
->OnTextCommitted(committed_text
);
769 EXPECT_EQ(0, mock_text_input_client
.call_count_insert_char());
770 EXPECT_EQ(1, mock_text_input_client
.call_count_insert_text());
771 EXPECT_EQ(committed_text
, mock_text_input_client
.inserted_text());
773 mock_text_input_client
.Reset();
775 // When TextInputType is TEXT_INPUT_TYPE_NONE, TextInputClient::InsertText
776 // should not be used.
777 mock_text_input_client
.set_text_input_type(TEXT_INPUT_TYPE_NONE
);
778 private_ptr
->OnTextCommitted(committed_text
);
779 EXPECT_EQ(committed_text
.size(),
780 mock_text_input_client
.call_count_insert_char());
781 EXPECT_EQ(0, mock_text_input_client
.call_count_insert_text());
782 EXPECT_EQ(committed_text
, mock_text_input_client
.inserted_text());
784 mock_text_input_client
.Reset();
787 TEST(RemoteInputMethodWinTest
, OnTextInputStateChanged_Observer
) {
788 DummyTextInputClient text_input_client
;
789 DummyTextInputClient text_input_client_the_other
;
791 MockInputMethodObserver input_method_observer
;
792 MockInputMethodDelegate delegate_
;
793 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
794 InputMethodScopedObserver
scoped_observer(&input_method_observer
);
795 scoped_observer
.Add(input_method
.get());
797 input_method
->SetFocusedTextInputClient(&text_input_client
);
798 ASSERT_EQ(&text_input_client
, input_method
->GetTextInputClient());
799 EXPECT_EQ(1u, input_method_observer
.on_text_input_state_changed());
800 input_method_observer
.Reset();
802 input_method
->SetFocusedTextInputClient(&text_input_client
);
803 ASSERT_EQ(&text_input_client
, input_method
->GetTextInputClient());
804 EXPECT_EQ(0u, input_method_observer
.on_text_input_state_changed());
805 input_method_observer
.Reset();
807 input_method
->SetFocusedTextInputClient(&text_input_client_the_other
);
808 ASSERT_EQ(&text_input_client_the_other
, input_method
->GetTextInputClient());
809 EXPECT_EQ(1u, input_method_observer
.on_text_input_state_changed());
810 input_method_observer
.Reset();
812 input_method
->DetachTextInputClient(&text_input_client_the_other
);
813 ASSERT_TRUE(input_method
->GetTextInputClient() == NULL
);
814 EXPECT_EQ(1u, input_method_observer
.on_text_input_state_changed());
815 input_method_observer
.Reset();
818 TEST(RemoteInputMethodWinTest
, OnInputMethodDestroyed_Observer
) {
819 DummyTextInputClient text_input_client
;
820 DummyTextInputClient text_input_client_the_other
;
822 MockInputMethodObserver input_method_observer
;
823 InputMethodScopedObserver
scoped_observer(&input_method_observer
);
825 MockInputMethodDelegate delegate_
;
826 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
827 input_method
->AddObserver(&input_method_observer
);
829 EXPECT_EQ(0u, input_method_observer
.on_input_method_destroyed_changed());
830 input_method
.reset();
831 EXPECT_EQ(1u, input_method_observer
.on_input_method_destroyed_changed());