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(const ui::KeyEvent
& event
) OVERRIDE
{
163 EXPECT_FALSE(event
.HasNativeEvent());
164 fabricated_key_events_
.push_back(event
.key_code());
168 std::vector
<ui::KeyboardCode
> fabricated_key_events_
;
169 DISALLOW_COPY_AND_ASSIGN(MockInputMethodDelegate
);
172 class MockRemoteInputMethodDelegateWin
173 : public internal::RemoteInputMethodDelegateWin
{
175 MockRemoteInputMethodDelegateWin()
176 : cancel_composition_called_(false),
177 text_input_client_updated_called_(false) {
180 bool cancel_composition_called() const {
181 return cancel_composition_called_
;
183 bool text_input_client_updated_called() const {
184 return text_input_client_updated_called_
;
186 const std::vector
<int32
>& input_scopes() const {
187 return input_scopes_
;
189 const std::vector
<gfx::Rect
>& composition_character_bounds() const {
190 return composition_character_bounds_
;
193 cancel_composition_called_
= false;
194 text_input_client_updated_called_
= false;
195 input_scopes_
.clear();
196 composition_character_bounds_
.clear();
200 virtual void CancelComposition() OVERRIDE
{
201 cancel_composition_called_
= true;
204 virtual void OnTextInputClientUpdated(
205 const std::vector
<int32
>& input_scopes
,
206 const std::vector
<gfx::Rect
>& composition_character_bounds
) OVERRIDE
{
207 text_input_client_updated_called_
= true;
208 input_scopes_
= input_scopes
;
209 composition_character_bounds_
= composition_character_bounds
;
212 bool cancel_composition_called_
;
213 bool text_input_client_updated_called_
;
214 std::vector
<int32
> input_scopes_
;
215 std::vector
<gfx::Rect
> composition_character_bounds_
;
216 DISALLOW_COPY_AND_ASSIGN(MockRemoteInputMethodDelegateWin
);
219 class MockInputMethodObserver
: public InputMethodObserver
{
221 MockInputMethodObserver()
222 : on_text_input_state_changed_(0),
223 on_input_method_destroyed_changed_(0) {
225 virtual ~MockInputMethodObserver() {
228 on_text_input_state_changed_
= 0;
229 on_input_method_destroyed_changed_
= 0;
231 size_t on_text_input_state_changed() const {
232 return on_text_input_state_changed_
;
234 size_t on_input_method_destroyed_changed() const {
235 return on_input_method_destroyed_changed_
;
239 // Overriden from InputMethodObserver.
240 virtual void OnTextInputTypeChanged(const TextInputClient
* client
) OVERRIDE
{
242 virtual void OnFocus() OVERRIDE
{
244 virtual void OnBlur() OVERRIDE
{
246 virtual void OnCaretBoundsChanged(const TextInputClient
* client
) OVERRIDE
{
248 virtual void OnTextInputStateChanged(const TextInputClient
* client
) OVERRIDE
{
249 ++on_text_input_state_changed_
;
251 virtual void OnInputMethodDestroyed(const InputMethod
* client
) OVERRIDE
{
252 ++on_input_method_destroyed_changed_
;
254 virtual void OnShowImeIfNeeded() {
257 size_t on_text_input_state_changed_
;
258 size_t on_input_method_destroyed_changed_
;
259 DISALLOW_COPY_AND_ASSIGN(MockInputMethodObserver
);
262 typedef ScopedObserver
<InputMethod
, InputMethodObserver
>
263 InputMethodScopedObserver
;
265 TEST(RemoteInputMethodWinTest
, RemoteInputMethodPrivateWin
) {
266 InputMethod
* other_ptr
= static_cast<InputMethod
*>(NULL
) + 1;
268 // Use typed NULL to make EXPECT_NE happy until nullptr becomes available.
269 RemoteInputMethodPrivateWin
* kNull
=
270 static_cast<RemoteInputMethodPrivateWin
*>(NULL
);
271 EXPECT_EQ(kNull
, RemoteInputMethodPrivateWin::Get(other_ptr
));
273 MockInputMethodDelegate delegate_
;
274 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
275 EXPECT_NE(kNull
, RemoteInputMethodPrivateWin::Get(input_method
.get()));
277 InputMethod
* dangling_ptr
= input_method
.get();
278 input_method
.reset(NULL
);
279 EXPECT_EQ(kNull
, RemoteInputMethodPrivateWin::Get(dangling_ptr
));
282 TEST(RemoteInputMethodWinTest
, OnInputSourceChanged
) {
283 MockInputMethodDelegate delegate_
;
284 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
285 RemoteInputMethodPrivateWin
* private_ptr
=
286 RemoteInputMethodPrivateWin::Get(input_method
.get());
287 ASSERT_TRUE(private_ptr
!= NULL
);
289 private_ptr
->OnInputSourceChanged(
290 MAKELANGID(LANG_JAPANESE
, SUBLANG_JAPANESE_JAPAN
), true);
291 EXPECT_EQ("ja-JP", input_method
->GetInputLocale());
293 private_ptr
->OnInputSourceChanged(
294 MAKELANGID(LANG_ARABIC
, SUBLANG_ARABIC_QATAR
), true);
295 EXPECT_EQ("ar-QA", input_method
->GetInputLocale());
298 TEST(RemoteInputMethodWinTest
, OnCandidatePopupChanged
) {
299 MockInputMethodDelegate delegate_
;
300 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
301 RemoteInputMethodPrivateWin
* private_ptr
=
302 RemoteInputMethodPrivateWin::Get(input_method
.get());
303 ASSERT_TRUE(private_ptr
!= NULL
);
306 EXPECT_FALSE(input_method
->IsCandidatePopupOpen());
308 // RemoteInputMethodWin::OnCandidatePopupChanged can be called even when the
309 // focused text input client is NULL.
310 ASSERT_TRUE(input_method
->GetTextInputClient() == NULL
);
311 private_ptr
->OnCandidatePopupChanged(false);
312 private_ptr
->OnCandidatePopupChanged(true);
314 MockTextInputClient mock_text_input_client
;
315 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
317 ASSERT_FALSE(mock_text_input_client
.is_candidate_window_shown_called());
318 ASSERT_FALSE(mock_text_input_client
.is_candidate_window_hidden_called());
319 mock_text_input_client
.Reset();
321 private_ptr
->OnCandidatePopupChanged(true);
322 EXPECT_TRUE(input_method
->IsCandidatePopupOpen());
323 EXPECT_TRUE(mock_text_input_client
.is_candidate_window_shown_called());
324 EXPECT_FALSE(mock_text_input_client
.is_candidate_window_hidden_called());
326 private_ptr
->OnCandidatePopupChanged(false);
327 EXPECT_FALSE(input_method
->IsCandidatePopupOpen());
328 EXPECT_TRUE(mock_text_input_client
.is_candidate_window_shown_called());
329 EXPECT_TRUE(mock_text_input_client
.is_candidate_window_hidden_called());
332 TEST(RemoteInputMethodWinTest
, CancelComposition
) {
333 MockInputMethodDelegate delegate_
;
334 MockTextInputClient mock_text_input_client
;
335 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
337 // This must not cause a crash.
338 input_method
->CancelComposition(&mock_text_input_client
);
340 RemoteInputMethodPrivateWin
* private_ptr
=
341 RemoteInputMethodPrivateWin::Get(input_method
.get());
342 ASSERT_TRUE(private_ptr
!= NULL
);
343 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
344 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
346 input_method
->CancelComposition(&mock_text_input_client
);
347 EXPECT_FALSE(mock_remote_delegate
.cancel_composition_called());
349 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
350 input_method
->CancelComposition(&mock_text_input_client
);
351 EXPECT_TRUE(mock_remote_delegate
.cancel_composition_called());
354 TEST(RemoteInputMethodWinTest
, SetFocusedTextInputClient
) {
355 MockInputMethodDelegate delegate_
;
356 MockTextInputClient mock_text_input_client
;
357 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
359 mock_text_input_client
.set_caret_bounds(gfx::Rect(10, 0, 10, 20));
360 mock_text_input_client
.set_text_input_type(ui::TEXT_INPUT_TYPE_URL
);
361 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
363 RemoteInputMethodPrivateWin
* private_ptr
=
364 RemoteInputMethodPrivateWin::Get(input_method
.get());
365 ASSERT_TRUE(private_ptr
!= NULL
);
366 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
367 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
369 // Initial state must be synced.
370 EXPECT_TRUE(mock_remote_delegate
.text_input_client_updated_called());
371 ASSERT_EQ(1, mock_remote_delegate
.composition_character_bounds().size());
372 EXPECT_EQ(gfx::Rect(10, 0, 10, 20),
373 mock_remote_delegate
.composition_character_bounds()[0]);
374 ASSERT_EQ(1, mock_remote_delegate
.input_scopes().size());
375 EXPECT_EQ(IS_URL
, mock_remote_delegate
.input_scopes()[0]);
377 // State must be cleared by SetFocusedTextInputClient(NULL).
378 mock_remote_delegate
.Reset();
379 input_method
->SetFocusedTextInputClient(NULL
);
380 EXPECT_TRUE(mock_remote_delegate
.text_input_client_updated_called());
381 EXPECT_TRUE(mock_remote_delegate
.composition_character_bounds().empty());
382 EXPECT_TRUE(mock_remote_delegate
.input_scopes().empty());
385 TEST(RemoteInputMethodWinTest
, DetachTextInputClient
) {
386 MockInputMethodDelegate delegate_
;
387 MockTextInputClient mock_text_input_client
;
388 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
390 mock_text_input_client
.set_caret_bounds(gfx::Rect(10, 0, 10, 20));
391 mock_text_input_client
.set_text_input_type(ui::TEXT_INPUT_TYPE_URL
);
392 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
394 RemoteInputMethodPrivateWin
* private_ptr
=
395 RemoteInputMethodPrivateWin::Get(input_method
.get());
396 ASSERT_TRUE(private_ptr
!= NULL
);
397 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
398 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
400 // Initial state must be synced.
401 EXPECT_TRUE(mock_remote_delegate
.text_input_client_updated_called());
402 ASSERT_EQ(1, mock_remote_delegate
.composition_character_bounds().size());
403 EXPECT_EQ(gfx::Rect(10, 0, 10, 20),
404 mock_remote_delegate
.composition_character_bounds()[0]);
405 ASSERT_EQ(1, mock_remote_delegate
.input_scopes().size());
406 EXPECT_EQ(IS_URL
, mock_remote_delegate
.input_scopes()[0]);
408 // State must be cleared by DetachTextInputClient
409 mock_remote_delegate
.Reset();
410 input_method
->DetachTextInputClient(&mock_text_input_client
);
411 EXPECT_TRUE(mock_remote_delegate
.text_input_client_updated_called());
412 EXPECT_TRUE(mock_remote_delegate
.composition_character_bounds().empty());
413 EXPECT_TRUE(mock_remote_delegate
.input_scopes().empty());
416 TEST(RemoteInputMethodWinTest
, OnCaretBoundsChanged
) {
417 MockInputMethodDelegate delegate_
;
418 MockTextInputClient mock_text_input_client
;
419 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
421 // This must not cause a crash.
422 input_method
->OnCaretBoundsChanged(&mock_text_input_client
);
424 mock_text_input_client
.set_caret_bounds(gfx::Rect(10, 0, 10, 20));
425 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
427 RemoteInputMethodPrivateWin
* private_ptr
=
428 RemoteInputMethodPrivateWin::Get(input_method
.get());
429 ASSERT_TRUE(private_ptr
!= NULL
);
430 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
431 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
433 // Initial state must be synced.
434 EXPECT_TRUE(mock_remote_delegate
.text_input_client_updated_called());
435 ASSERT_EQ(1, mock_remote_delegate
.composition_character_bounds().size());
436 EXPECT_EQ(gfx::Rect(10, 0, 10, 20),
437 mock_remote_delegate
.composition_character_bounds()[0]);
439 // Redundant OnCaretBoundsChanged must be ignored.
440 mock_remote_delegate
.Reset();
441 input_method
->OnCaretBoundsChanged(&mock_text_input_client
);
442 EXPECT_FALSE(mock_remote_delegate
.text_input_client_updated_called());
444 // Check OnCaretBoundsChanged is handled. (w/o composition)
445 mock_remote_delegate
.Reset();
446 mock_text_input_client
.Reset();
447 mock_text_input_client
.set_caret_bounds(gfx::Rect(10, 20, 30, 40));
448 input_method
->OnCaretBoundsChanged(&mock_text_input_client
);
449 EXPECT_TRUE(mock_remote_delegate
.text_input_client_updated_called());
450 ASSERT_EQ(1, mock_remote_delegate
.composition_character_bounds().size());
451 EXPECT_EQ(gfx::Rect(10, 20, 30, 40),
452 mock_remote_delegate
.composition_character_bounds()[0]);
454 // Check OnCaretBoundsChanged is handled. (w/ composition)
456 mock_remote_delegate
.Reset();
457 mock_text_input_client
.Reset();
459 std::vector
<gfx::Rect
> bounds
;
460 bounds
.push_back(gfx::Rect(10, 20, 30, 40));
461 bounds
.push_back(gfx::Rect(40, 30, 20, 10));
462 mock_text_input_client
.set_composition_character_bounds(bounds
);
463 input_method
->OnCaretBoundsChanged(&mock_text_input_client
);
464 EXPECT_TRUE(mock_remote_delegate
.text_input_client_updated_called());
465 EXPECT_EQ(bounds
, mock_remote_delegate
.composition_character_bounds());
469 // Test case against crbug.com/328237.
470 TEST(RemoteInputMethodWinTest
, OnCaretBoundsChangedForPepperFlash
) {
471 MockInputMethodDelegate delegate_
;
472 MockTextInputClient mock_text_input_client
;
473 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
474 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
476 RemoteInputMethodPrivateWin
* private_ptr
=
477 RemoteInputMethodPrivateWin::Get(input_method
.get());
478 ASSERT_TRUE(private_ptr
!= NULL
);
479 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
480 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
482 mock_remote_delegate
.Reset();
483 mock_text_input_client
.Reset();
484 mock_text_input_client
.set_emulate_pepper_flash(true);
486 std::vector
<gfx::Rect
> caret_bounds
;
487 caret_bounds
.push_back(gfx::Rect(5, 15, 25, 35));
488 mock_text_input_client
.set_caret_bounds(caret_bounds
[0]);
490 std::vector
<gfx::Rect
> composition_bounds
;
491 composition_bounds
.push_back(gfx::Rect(10, 20, 30, 40));
492 composition_bounds
.push_back(gfx::Rect(40, 30, 20, 10));
493 mock_text_input_client
.set_composition_character_bounds(composition_bounds
);
494 input_method
->OnCaretBoundsChanged(&mock_text_input_client
);
495 EXPECT_TRUE(mock_remote_delegate
.text_input_client_updated_called());
496 // The caret bounds must be used when
497 // TextInputClient::GetCompositionCharacterBounds failed.
498 EXPECT_EQ(caret_bounds
, mock_remote_delegate
.composition_character_bounds());
501 TEST(RemoteInputMethodWinTest
, OnTextInputTypeChanged
) {
502 MockInputMethodDelegate delegate_
;
503 MockTextInputClient mock_text_input_client
;
504 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
506 // This must not cause a crash.
507 input_method
->OnCaretBoundsChanged(&mock_text_input_client
);
509 mock_text_input_client
.set_text_input_type(ui::TEXT_INPUT_TYPE_URL
);
510 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
512 RemoteInputMethodPrivateWin
* private_ptr
=
513 RemoteInputMethodPrivateWin::Get(input_method
.get());
514 ASSERT_TRUE(private_ptr
!= NULL
);
515 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
516 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
518 // Initial state must be synced.
519 EXPECT_TRUE(mock_remote_delegate
.text_input_client_updated_called());
520 ASSERT_EQ(1, mock_remote_delegate
.input_scopes().size());
521 EXPECT_EQ(IS_URL
, mock_remote_delegate
.input_scopes()[0]);
523 // Check TEXT_INPUT_TYPE_NONE is handled.
524 mock_remote_delegate
.Reset();
525 mock_text_input_client
.Reset();
526 mock_text_input_client
.set_text_input_type(ui::TEXT_INPUT_TYPE_NONE
);
527 mock_text_input_client
.set_text_input_mode(ui::TEXT_INPUT_MODE_KATAKANA
);
528 input_method
->OnTextInputTypeChanged(&mock_text_input_client
);
529 EXPECT_TRUE(mock_remote_delegate
.text_input_client_updated_called());
530 EXPECT_TRUE(mock_remote_delegate
.input_scopes().empty());
532 // Redundant OnTextInputTypeChanged must be ignored.
533 mock_remote_delegate
.Reset();
534 input_method
->OnTextInputTypeChanged(&mock_text_input_client
);
535 EXPECT_FALSE(mock_remote_delegate
.text_input_client_updated_called());
537 mock_remote_delegate
.Reset();
538 mock_text_input_client
.Reset();
539 mock_text_input_client
.set_caret_bounds(gfx::Rect(10, 20, 30, 40));
540 input_method
->OnCaretBoundsChanged(&mock_text_input_client
);
543 TEST(RemoteInputMethodWinTest
, DispatchKeyEvent_NativeKeyEvent
) {
544 // Basically RemoteInputMethodWin does not handle native keydown event.
546 MockInputMethodDelegate delegate_
;
547 MockTextInputClient mock_text_input_client
;
548 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
550 const MSG wm_keydown
= { NULL
, WM_KEYDOWN
, ui::VKEY_A
};
551 ui::KeyEvent
native_keydown(wm_keydown
, false);
553 // This must not cause a crash.
554 EXPECT_FALSE(input_method
->DispatchKeyEvent(native_keydown
));
555 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
556 EXPECT_TRUE(delegate_
.fabricated_key_events().empty());
558 mock_text_input_client
.Reset();
560 RemoteInputMethodPrivateWin
* private_ptr
=
561 RemoteInputMethodPrivateWin::Get(input_method
.get());
562 ASSERT_TRUE(private_ptr
!= NULL
);
563 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
564 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
566 // TextInputClient is not focused yet 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();
574 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
576 // TextInputClient is now focused here.
578 EXPECT_FALSE(input_method
->DispatchKeyEvent(native_keydown
));
579 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
580 EXPECT_TRUE(delegate_
.fabricated_key_events().empty());
582 mock_text_input_client
.Reset();
585 TEST(RemoteInputMethodWinTest
, DispatchKeyEvent_NativeCharEvent
) {
586 // RemoteInputMethodWin handles native char event if possible.
588 MockInputMethodDelegate delegate_
;
589 MockTextInputClient mock_text_input_client
;
590 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
592 const MSG wm_char
= { NULL
, WM_CHAR
, 'A', 0 };
593 ui::KeyEvent
native_char(wm_char
, true);
595 // This must not cause a crash.
596 EXPECT_FALSE(input_method
->DispatchKeyEvent(native_char
));
597 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
598 EXPECT_TRUE(delegate_
.fabricated_key_events().empty());
600 mock_text_input_client
.Reset();
602 RemoteInputMethodPrivateWin
* private_ptr
=
603 RemoteInputMethodPrivateWin::Get(input_method
.get());
604 ASSERT_TRUE(private_ptr
!= NULL
);
605 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
606 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
608 // TextInputClient is not focused yet here.
610 EXPECT_FALSE(input_method
->DispatchKeyEvent(native_char
));
611 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
612 EXPECT_TRUE(delegate_
.fabricated_key_events().empty());
614 mock_text_input_client
.Reset();
616 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
618 // TextInputClient is now focused here.
620 EXPECT_TRUE(input_method
->DispatchKeyEvent(native_char
));
621 EXPECT_EQ(L
"A", mock_text_input_client
.inserted_text());
622 EXPECT_TRUE(delegate_
.fabricated_key_events().empty());
624 mock_text_input_client
.Reset();
627 TEST(RemoteInputMethodWinTest
, DispatchKeyEvent_FabricatedKeyDown
) {
628 // Fabricated non-char event will be delegated to
629 // InputMethodDelegate::DispatchFabricatedKeyEventPostIME as long as the
630 // delegate is installed.
632 MockInputMethodDelegate delegate_
;
633 MockTextInputClient mock_text_input_client
;
634 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
636 ui::KeyEvent
fabricated_keydown(ui::ET_KEY_PRESSED
, ui::VKEY_A
, 0, false);
637 fabricated_keydown
.set_character(L
'A');
639 // This must not cause a crash.
640 EXPECT_TRUE(input_method
->DispatchKeyEvent(fabricated_keydown
));
641 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
642 ASSERT_EQ(1, delegate_
.fabricated_key_events().size());
643 EXPECT_EQ(L
'A', delegate_
.fabricated_key_events()[0]);
645 mock_text_input_client
.Reset();
647 RemoteInputMethodPrivateWin
* private_ptr
=
648 RemoteInputMethodPrivateWin::Get(input_method
.get());
649 ASSERT_TRUE(private_ptr
!= NULL
);
650 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
651 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
653 // TextInputClient is not focused yet 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
->SetFocusedTextInputClient(&mock_text_input_client
);
663 // TextInputClient is now focused here.
665 EXPECT_TRUE(input_method
->DispatchKeyEvent(fabricated_keydown
));
666 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
667 ASSERT_EQ(1, delegate_
.fabricated_key_events().size());
668 EXPECT_EQ(L
'A', delegate_
.fabricated_key_events()[0]);
670 mock_text_input_client
.Reset();
672 input_method
->SetDelegate(NULL
);
673 // RemoteInputMethodDelegateWin is no longer set here.
675 EXPECT_FALSE(input_method
->DispatchKeyEvent(fabricated_keydown
));
676 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
679 TEST(RemoteInputMethodWinTest
, DispatchKeyEvent_FabricatedChar
) {
680 // Note: RemoteInputMethodWin::DispatchKeyEvent should always return true
681 // for fabricated character events.
683 MockInputMethodDelegate delegate_
;
684 MockTextInputClient mock_text_input_client
;
685 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
687 ui::KeyEvent
fabricated_char(ui::ET_KEY_PRESSED
, ui::VKEY_A
, 0, true);
688 fabricated_char
.set_character(L
'A');
690 // This must not cause a crash.
691 EXPECT_TRUE(input_method
->DispatchKeyEvent(fabricated_char
));
692 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
693 EXPECT_TRUE(delegate_
.fabricated_key_events().empty());
695 mock_text_input_client
.Reset();
697 RemoteInputMethodPrivateWin
* private_ptr
=
698 RemoteInputMethodPrivateWin::Get(input_method
.get());
699 ASSERT_TRUE(private_ptr
!= NULL
);
700 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
701 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
703 // TextInputClient is not focused yet here.
705 EXPECT_TRUE(input_method
->DispatchKeyEvent(fabricated_char
));
706 EXPECT_TRUE(mock_text_input_client
.inserted_text().empty());
707 EXPECT_TRUE(delegate_
.fabricated_key_events().empty());
709 mock_text_input_client
.Reset();
711 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
713 // TextInputClient is now focused here.
715 EXPECT_TRUE(input_method
->DispatchKeyEvent(fabricated_char
));
716 EXPECT_EQ(L
"A", mock_text_input_client
.inserted_text());
717 EXPECT_TRUE(delegate_
.fabricated_key_events().empty());
719 mock_text_input_client
.Reset();
722 TEST(RemoteInputMethodWinTest
, OnCompositionChanged
) {
723 MockInputMethodDelegate delegate_
;
724 MockTextInputClient mock_text_input_client
;
725 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
727 RemoteInputMethodPrivateWin
* private_ptr
=
728 RemoteInputMethodPrivateWin::Get(input_method
.get());
729 ASSERT_TRUE(private_ptr
!= NULL
);
730 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
731 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
733 CompositionText composition_text
;
735 // TextInputClient is not focused yet here.
737 private_ptr
->OnCompositionChanged(composition_text
);
738 EXPECT_EQ(0, mock_text_input_client
.call_count_set_composition_text());
740 mock_text_input_client
.Reset();
742 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
744 // TextInputClient is now focused here.
746 private_ptr
->OnCompositionChanged(composition_text
);
747 EXPECT_EQ(1, mock_text_input_client
.call_count_set_composition_text());
749 mock_text_input_client
.Reset();
752 TEST(RemoteInputMethodWinTest
, OnTextCommitted
) {
753 MockInputMethodDelegate delegate_
;
754 MockTextInputClient mock_text_input_client
;
755 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
757 RemoteInputMethodPrivateWin
* private_ptr
=
758 RemoteInputMethodPrivateWin::Get(input_method
.get());
759 ASSERT_TRUE(private_ptr
!= NULL
);
760 MockRemoteInputMethodDelegateWin mock_remote_delegate
;
761 private_ptr
->SetRemoteDelegate(&mock_remote_delegate
);
763 base::string16 committed_text
= L
"Hello";
765 // TextInputClient is not focused yet 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(0, mock_text_input_client
.call_count_insert_text());
771 EXPECT_EQ(L
"", mock_text_input_client
.inserted_text());
773 mock_text_input_client
.Reset();
775 input_method
->SetFocusedTextInputClient(&mock_text_input_client
);
777 // TextInputClient is now focused here.
779 mock_text_input_client
.set_text_input_type(TEXT_INPUT_TYPE_TEXT
);
780 private_ptr
->OnTextCommitted(committed_text
);
781 EXPECT_EQ(0, mock_text_input_client
.call_count_insert_char());
782 EXPECT_EQ(1, 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();
787 // When TextInputType is TEXT_INPUT_TYPE_NONE, TextInputClient::InsertText
788 // should not be used.
789 mock_text_input_client
.set_text_input_type(TEXT_INPUT_TYPE_NONE
);
790 private_ptr
->OnTextCommitted(committed_text
);
791 EXPECT_EQ(committed_text
.size(),
792 mock_text_input_client
.call_count_insert_char());
793 EXPECT_EQ(0, mock_text_input_client
.call_count_insert_text());
794 EXPECT_EQ(committed_text
, mock_text_input_client
.inserted_text());
796 mock_text_input_client
.Reset();
799 TEST(RemoteInputMethodWinTest
, OnTextInputStateChanged_Observer
) {
800 DummyTextInputClient text_input_client
;
801 DummyTextInputClient text_input_client_the_other
;
803 MockInputMethodObserver input_method_observer
;
804 MockInputMethodDelegate delegate_
;
805 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
806 InputMethodScopedObserver
scoped_observer(&input_method_observer
);
807 scoped_observer
.Add(input_method
.get());
809 input_method
->SetFocusedTextInputClient(&text_input_client
);
810 ASSERT_EQ(&text_input_client
, input_method
->GetTextInputClient());
811 EXPECT_EQ(1u, input_method_observer
.on_text_input_state_changed());
812 input_method_observer
.Reset();
814 input_method
->SetFocusedTextInputClient(&text_input_client
);
815 ASSERT_EQ(&text_input_client
, input_method
->GetTextInputClient());
816 EXPECT_EQ(0u, input_method_observer
.on_text_input_state_changed());
817 input_method_observer
.Reset();
819 input_method
->SetFocusedTextInputClient(&text_input_client_the_other
);
820 ASSERT_EQ(&text_input_client_the_other
, input_method
->GetTextInputClient());
821 EXPECT_EQ(1u, input_method_observer
.on_text_input_state_changed());
822 input_method_observer
.Reset();
824 input_method
->DetachTextInputClient(&text_input_client_the_other
);
825 ASSERT_TRUE(input_method
->GetTextInputClient() == NULL
);
826 EXPECT_EQ(1u, input_method_observer
.on_text_input_state_changed());
827 input_method_observer
.Reset();
830 TEST(RemoteInputMethodWinTest
, OnInputMethodDestroyed_Observer
) {
831 DummyTextInputClient text_input_client
;
832 DummyTextInputClient text_input_client_the_other
;
834 MockInputMethodObserver input_method_observer
;
835 InputMethodScopedObserver
scoped_observer(&input_method_observer
);
837 MockInputMethodDelegate delegate_
;
838 scoped_ptr
<InputMethod
> input_method(CreateRemoteInputMethodWin(&delegate_
));
839 input_method
->AddObserver(&input_method_observer
);
841 EXPECT_EQ(0u, input_method_observer
.on_input_method_destroyed_changed());
842 input_method
.reset();
843 EXPECT_EQ(1u, input_method_observer
.on_input_method_destroyed_changed());