1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "ui/base/ime/remote_input_method_win.h" 6 7 #include <InputScope.h> 8 9 #include <vector> 10 11 #include "base/memory/scoped_ptr.h" 12 #include "base/scoped_observer.h" 13 #include "base/strings/string16.h" 14 #include "testing/gtest/include/gtest/gtest.h" 15 #include "ui/base/ime/composition_text.h" 16 #include "ui/base/ime/dummy_text_input_client.h" 17 #include "ui/base/ime/input_method.h" 18 #include "ui/base/ime/input_method_delegate.h" 19 #include "ui/base/ime/input_method_observer.h" 20 #include "ui/base/ime/remote_input_method_delegate_win.h" 21 #include "ui/events/event.h" 22 23 namespace ui { 24 namespace { 25 26 class MockTextInputClient : public DummyTextInputClient { 27 public: 28 MockTextInputClient() 29 : text_input_type_(TEXT_INPUT_TYPE_NONE), 30 text_input_mode_(TEXT_INPUT_MODE_DEFAULT), 31 call_count_set_composition_text_(0), 32 call_count_insert_char_(0), 33 call_count_insert_text_(0), 34 emulate_pepper_flash_(false), 35 is_candidate_window_shown_called_(false), 36 is_candidate_window_hidden_called_(false) { 37 } 38 39 size_t call_count_set_composition_text() const { 40 return call_count_set_composition_text_; 41 } 42 const base::string16& inserted_text() const { 43 return inserted_text_; 44 } 45 size_t call_count_insert_char() const { 46 return call_count_insert_char_; 47 } 48 size_t call_count_insert_text() const { 49 return call_count_insert_text_; 50 } 51 bool is_candidate_window_shown_called() const { 52 return is_candidate_window_shown_called_; 53 } 54 bool is_candidate_window_hidden_called() const { 55 return is_candidate_window_hidden_called_; 56 } 57 void Reset() { 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; 69 } 70 void set_text_input_type(ui::TextInputType type) { 71 text_input_type_ = type; 72 } 73 void set_text_input_mode(ui::TextInputMode mode) { 74 text_input_mode_ = mode; 75 } 76 void set_caret_bounds(const gfx::Rect& caret_bounds) { 77 caret_bounds_ = caret_bounds; 78 } 79 void set_composition_character_bounds( 80 const std::vector<gfx::Rect>& composition_character_bounds) { 81 composition_character_bounds_ = composition_character_bounds; 82 } 83 void set_emulate_pepper_flash(bool enabled) { 84 emulate_pepper_flash_ = enabled; 85 } 86 87 private: 88 // Overriden from DummyTextInputClient. 89 virtual void SetCompositionText( 90 const ui::CompositionText& composition) OVERRIDE { 91 ++call_count_set_composition_text_; 92 } 93 virtual void InsertChar(base::char16 ch, int flags) OVERRIDE { 94 inserted_text_.append(1, ch); 95 ++call_count_insert_char_; 96 } 97 virtual void InsertText(const base::string16& text) OVERRIDE { 98 inserted_text_.append(text); 99 ++call_count_insert_text_; 100 } 101 virtual ui::TextInputType GetTextInputType() const OVERRIDE { 102 return text_input_type_; 103 } 104 virtual ui::TextInputMode GetTextInputMode() const OVERRIDE { 105 return text_input_mode_; 106 } 107 virtual gfx::Rect GetCaretBounds() const { 108 return caret_bounds_; 109 } 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_) 114 return false; 115 if (!rect || composition_character_bounds_.size() <= index) 116 return false; 117 *rect = composition_character_bounds_[index]; 118 return true; 119 } 120 virtual bool HasCompositionText() const OVERRIDE { 121 return !composition_character_bounds_.empty(); 122 } 123 virtual bool GetCompositionTextRange(gfx::Range* range) const OVERRIDE { 124 if (composition_character_bounds_.empty()) 125 return false; 126 *range = gfx::Range(0, composition_character_bounds_.size()); 127 return true; 128 } 129 virtual void OnCandidateWindowShown() OVERRIDE { 130 is_candidate_window_shown_called_ = true; 131 } 132 virtual void OnCandidateWindowHidden() OVERRIDE { 133 is_candidate_window_hidden_called_ = true; 134 } 135 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); 148 }; 149 150 class MockInputMethodDelegate : public internal::InputMethodDelegate { 151 public: 152 MockInputMethodDelegate() {} 153 154 const std::vector<ui::KeyboardCode>& fabricated_key_events() const { 155 return fabricated_key_events_; 156 } 157 void Reset() { 158 fabricated_key_events_.clear(); 159 } 160 161 private: 162 virtual bool DispatchKeyEventPostIME(const ui::KeyEvent& event) OVERRIDE { 163 EXPECT_FALSE(event.HasNativeEvent()); 164 fabricated_key_events_.push_back(event.key_code()); 165 return true; 166 } 167 168 std::vector<ui::KeyboardCode> fabricated_key_events_; 169 DISALLOW_COPY_AND_ASSIGN(MockInputMethodDelegate); 170 }; 171 172 class MockRemoteInputMethodDelegateWin 173 : public internal::RemoteInputMethodDelegateWin { 174 public: 175 MockRemoteInputMethodDelegateWin() 176 : cancel_composition_called_(false), 177 text_input_client_updated_called_(false) { 178 } 179 180 bool cancel_composition_called() const { 181 return cancel_composition_called_; 182 } 183 bool text_input_client_updated_called() const { 184 return text_input_client_updated_called_; 185 } 186 const std::vector<int32>& input_scopes() const { 187 return input_scopes_; 188 } 189 const std::vector<gfx::Rect>& composition_character_bounds() const { 190 return composition_character_bounds_; 191 } 192 void Reset() { 193 cancel_composition_called_ = false; 194 text_input_client_updated_called_ = false; 195 input_scopes_.clear(); 196 composition_character_bounds_.clear(); 197 } 198 199 private: 200 virtual void CancelComposition() OVERRIDE { 201 cancel_composition_called_ = true; 202 } 203 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; 210 } 211 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); 217 }; 218 219 class MockInputMethodObserver : public InputMethodObserver { 220 public: 221 MockInputMethodObserver() 222 : on_text_input_state_changed_(0), 223 on_input_method_destroyed_changed_(0) { 224 } 225 virtual ~MockInputMethodObserver() { 226 } 227 void Reset() { 228 on_text_input_state_changed_ = 0; 229 on_input_method_destroyed_changed_ = 0; 230 } 231 size_t on_text_input_state_changed() const { 232 return on_text_input_state_changed_; 233 } 234 size_t on_input_method_destroyed_changed() const { 235 return on_input_method_destroyed_changed_; 236 } 237 238 private: 239 // Overriden from InputMethodObserver. 240 virtual void OnTextInputTypeChanged(const TextInputClient* client) OVERRIDE { 241 } 242 virtual void OnFocus() OVERRIDE { 243 } 244 virtual void OnBlur() OVERRIDE { 245 } 246 virtual void OnCaretBoundsChanged(const TextInputClient* client) OVERRIDE { 247 } 248 virtual void OnTextInputStateChanged(const TextInputClient* client) OVERRIDE { 249 ++on_text_input_state_changed_; 250 } 251 virtual void OnInputMethodDestroyed(const InputMethod* client) OVERRIDE { 252 ++on_input_method_destroyed_changed_; 253 } 254 virtual void OnShowImeIfNeeded() { 255 } 256 257 size_t on_text_input_state_changed_; 258 size_t on_input_method_destroyed_changed_; 259 DISALLOW_COPY_AND_ASSIGN(MockInputMethodObserver); 260 }; 261 262 typedef ScopedObserver<InputMethod, InputMethodObserver> 263 InputMethodScopedObserver; 264 265 TEST(RemoteInputMethodWinTest, RemoteInputMethodPrivateWin) { 266 InputMethod* other_ptr = static_cast<InputMethod*>(NULL) + 1; 267 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)); 272 273 MockInputMethodDelegate delegate_; 274 scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_)); 275 EXPECT_NE(kNull, RemoteInputMethodPrivateWin::Get(input_method.get())); 276 277 InputMethod* dangling_ptr = input_method.get(); 278 input_method.reset(NULL); 279 EXPECT_EQ(kNull, RemoteInputMethodPrivateWin::Get(dangling_ptr)); 280 } 281 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); 288 289 private_ptr->OnInputSourceChanged( 290 MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN), true); 291 EXPECT_EQ("ja-JP", input_method->GetInputLocale()); 292 293 private_ptr->OnInputSourceChanged( 294 MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_QATAR), true); 295 EXPECT_EQ("ar-QA", input_method->GetInputLocale()); 296 } 297 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); 304 305 // Initial value 306 EXPECT_FALSE(input_method->IsCandidatePopupOpen()); 307 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); 313 314 MockTextInputClient mock_text_input_client; 315 input_method->SetFocusedTextInputClient(&mock_text_input_client); 316 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(); 320 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()); 325 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()); 330 } 331 332 TEST(RemoteInputMethodWinTest, CancelComposition) { 333 MockInputMethodDelegate delegate_; 334 MockTextInputClient mock_text_input_client; 335 scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_)); 336 337 // This must not cause a crash. 338 input_method->CancelComposition(&mock_text_input_client); 339 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); 345 346 input_method->CancelComposition(&mock_text_input_client); 347 EXPECT_FALSE(mock_remote_delegate.cancel_composition_called()); 348 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()); 352 } 353 354 TEST(RemoteInputMethodWinTest, SetFocusedTextInputClient) { 355 MockInputMethodDelegate delegate_; 356 MockTextInputClient mock_text_input_client; 357 scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_)); 358 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); 362 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); 368 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]); 376 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()); 383 } 384 385 TEST(RemoteInputMethodWinTest, DetachTextInputClient) { 386 MockInputMethodDelegate delegate_; 387 MockTextInputClient mock_text_input_client; 388 scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_)); 389 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); 393 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); 399 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]); 407 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()); 414 } 415 416 TEST(RemoteInputMethodWinTest, OnCaretBoundsChanged) { 417 MockInputMethodDelegate delegate_; 418 MockTextInputClient mock_text_input_client; 419 scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_)); 420 421 // This must not cause a crash. 422 input_method->OnCaretBoundsChanged(&mock_text_input_client); 423 424 mock_text_input_client.set_caret_bounds(gfx::Rect(10, 0, 10, 20)); 425 input_method->SetFocusedTextInputClient(&mock_text_input_client); 426 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); 432 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]); 438 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()); 443 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]); 453 454 // Check OnCaretBoundsChanged is handled. (w/ composition) 455 { 456 mock_remote_delegate.Reset(); 457 mock_text_input_client.Reset(); 458 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()); 466 } 467 } 468 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); 475 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); 481 482 mock_remote_delegate.Reset(); 483 mock_text_input_client.Reset(); 484 mock_text_input_client.set_emulate_pepper_flash(true); 485 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]); 489 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()); 499 } 500 501 TEST(RemoteInputMethodWinTest, OnTextInputTypeChanged) { 502 MockInputMethodDelegate delegate_; 503 MockTextInputClient mock_text_input_client; 504 scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_)); 505 506 // This must not cause a crash. 507 input_method->OnCaretBoundsChanged(&mock_text_input_client); 508 509 mock_text_input_client.set_text_input_type(ui::TEXT_INPUT_TYPE_URL); 510 input_method->SetFocusedTextInputClient(&mock_text_input_client); 511 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); 517 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]); 522 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()); 531 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()); 536 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); 541 } 542 543 TEST(RemoteInputMethodWinTest, DispatchKeyEvent_NativeKeyEvent) { 544 // Basically RemoteInputMethodWin does not handle native keydown event. 545 546 MockInputMethodDelegate delegate_; 547 MockTextInputClient mock_text_input_client; 548 scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_)); 549 550 const MSG wm_keydown = { NULL, WM_KEYDOWN, ui::VKEY_A }; 551 ui::KeyEvent native_keydown(wm_keydown, false); 552 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()); 557 delegate_.Reset(); 558 mock_text_input_client.Reset(); 559 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); 565 566 // TextInputClient is not focused yet here. 567 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()); 571 delegate_.Reset(); 572 mock_text_input_client.Reset(); 573 574 input_method->SetFocusedTextInputClient(&mock_text_input_client); 575 576 // TextInputClient is now focused here. 577 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()); 581 delegate_.Reset(); 582 mock_text_input_client.Reset(); 583 } 584 585 TEST(RemoteInputMethodWinTest, DispatchKeyEvent_NativeCharEvent) { 586 // RemoteInputMethodWin handles native char event if possible. 587 588 MockInputMethodDelegate delegate_; 589 MockTextInputClient mock_text_input_client; 590 scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_)); 591 592 const MSG wm_char = { NULL, WM_CHAR, 'A', 0 }; 593 ui::KeyEvent native_char(wm_char, true); 594 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()); 599 delegate_.Reset(); 600 mock_text_input_client.Reset(); 601 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); 607 608 // TextInputClient is not focused yet here. 609 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()); 613 delegate_.Reset(); 614 mock_text_input_client.Reset(); 615 616 input_method->SetFocusedTextInputClient(&mock_text_input_client); 617 618 // TextInputClient is now focused here. 619 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()); 623 delegate_.Reset(); 624 mock_text_input_client.Reset(); 625 } 626 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. 631 632 MockInputMethodDelegate delegate_; 633 MockTextInputClient mock_text_input_client; 634 scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_)); 635 636 ui::KeyEvent fabricated_keydown(ui::ET_KEY_PRESSED, ui::VKEY_A, 0, false); 637 fabricated_keydown.set_character(L'A'); 638 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]); 644 delegate_.Reset(); 645 mock_text_input_client.Reset(); 646 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); 652 653 // TextInputClient is not focused yet here. 654 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]); 659 delegate_.Reset(); 660 mock_text_input_client.Reset(); 661 662 input_method->SetFocusedTextInputClient(&mock_text_input_client); 663 // TextInputClient is now focused here. 664 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]); 669 delegate_.Reset(); 670 mock_text_input_client.Reset(); 671 672 input_method->SetDelegate(NULL); 673 // RemoteInputMethodDelegateWin is no longer set here. 674 675 EXPECT_FALSE(input_method->DispatchKeyEvent(fabricated_keydown)); 676 EXPECT_TRUE(mock_text_input_client.inserted_text().empty()); 677 } 678 679 TEST(RemoteInputMethodWinTest, DispatchKeyEvent_FabricatedChar) { 680 // Note: RemoteInputMethodWin::DispatchKeyEvent should always return true 681 // for fabricated character events. 682 683 MockInputMethodDelegate delegate_; 684 MockTextInputClient mock_text_input_client; 685 scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_)); 686 687 ui::KeyEvent fabricated_char(ui::ET_KEY_PRESSED, ui::VKEY_A, 0, true); 688 fabricated_char.set_character(L'A'); 689 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()); 694 delegate_.Reset(); 695 mock_text_input_client.Reset(); 696 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); 702 703 // TextInputClient is not focused yet here. 704 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()); 708 delegate_.Reset(); 709 mock_text_input_client.Reset(); 710 711 input_method->SetFocusedTextInputClient(&mock_text_input_client); 712 713 // TextInputClient is now focused here. 714 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()); 718 delegate_.Reset(); 719 mock_text_input_client.Reset(); 720 } 721 722 TEST(RemoteInputMethodWinTest, OnCompositionChanged) { 723 MockInputMethodDelegate delegate_; 724 MockTextInputClient mock_text_input_client; 725 scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_)); 726 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); 732 733 CompositionText composition_text; 734 735 // TextInputClient is not focused yet here. 736 737 private_ptr->OnCompositionChanged(composition_text); 738 EXPECT_EQ(0, mock_text_input_client.call_count_set_composition_text()); 739 delegate_.Reset(); 740 mock_text_input_client.Reset(); 741 742 input_method->SetFocusedTextInputClient(&mock_text_input_client); 743 744 // TextInputClient is now focused here. 745 746 private_ptr->OnCompositionChanged(composition_text); 747 EXPECT_EQ(1, mock_text_input_client.call_count_set_composition_text()); 748 delegate_.Reset(); 749 mock_text_input_client.Reset(); 750 } 751 752 TEST(RemoteInputMethodWinTest, OnTextCommitted) { 753 MockInputMethodDelegate delegate_; 754 MockTextInputClient mock_text_input_client; 755 scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_)); 756 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); 762 763 base::string16 committed_text = L"Hello"; 764 765 // TextInputClient is not focused yet here. 766 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()); 772 delegate_.Reset(); 773 mock_text_input_client.Reset(); 774 775 input_method->SetFocusedTextInputClient(&mock_text_input_client); 776 777 // TextInputClient is now focused here. 778 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()); 784 delegate_.Reset(); 785 mock_text_input_client.Reset(); 786 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()); 795 delegate_.Reset(); 796 mock_text_input_client.Reset(); 797 } 798 799 TEST(RemoteInputMethodWinTest, OnTextInputStateChanged_Observer) { 800 DummyTextInputClient text_input_client; 801 DummyTextInputClient text_input_client_the_other; 802 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()); 808 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(); 813 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(); 818 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(); 823 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(); 828 } 829 830 TEST(RemoteInputMethodWinTest, OnInputMethodDestroyed_Observer) { 831 DummyTextInputClient text_input_client; 832 DummyTextInputClient text_input_client_the_other; 833 834 MockInputMethodObserver input_method_observer; 835 InputMethodScopedObserver scoped_observer(&input_method_observer); 836 837 MockInputMethodDelegate delegate_; 838 scoped_ptr<InputMethod> input_method(CreateRemoteInputMethodWin(&delegate_)); 839 input_method->AddObserver(&input_method_observer); 840 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()); 844 } 845 846 } // namespace 847 } // namespace ui 848